55 Commits
v0.19 ... v0.20

Author SHA1 Message Date
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
56 changed files with 3137 additions and 3242 deletions

3
.gitignore vendored
View File

@@ -4,3 +4,6 @@ firmware
/firmware.packed.bin
/firmware.bin
/compiled-firmware
.cache
compile_commands.json
.vscode

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

View File

@@ -2,11 +2,14 @@
# compile options (see README.md for descriptions)
# 0 = disable
# 1 = enable
#
# ---- COMPILER/LINKER OPTIONS ----
ENABLE_CLANG := 0
ENABLE_SWD := 0
ENABLE_OVERLAY := 0
ENABLE_LTO := 1
# ---- STOCK QUANSHENG FERATURES ----
ENABLE_UART := 1
ENABLE_AIRCOPY := 0
ENABLE_FMRADIO := 1
@@ -16,6 +19,10 @@ 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_KEEP_MEM_NAME := 1
@@ -24,11 +31,10 @@ 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_SHOW_CHARGE_LEVEL := 0
ENABLE_REVERSE_BAT_SYMBOL := 0
ENABLE_NO_CODE_SCAN_TIMEOUT := 1
ENABLE_AM_FIX := 1
ENABLE_AM_FIX_SHOW_DATA := 0
ENABLE_SQUELCH_MORE_SENSITIVE := 1
ENABLE_FASTER_CHANNEL_SCAN := 1
ENABLE_RSSI_BAR := 1
@@ -39,7 +45,11 @@ ENABLE_REDUCE_LOW_MID_TX_POWER:= 0
ENABLE_BYP_RAW_DEMODULATORS := 0
ENABLE_BLMIN_TMP_OFF := 0
ENABLE_SCAN_RANGES := 1
ENABLE_DTMF_CALLING := 1
# ---- DEBUGGING ----
ENABLE_AM_FIX_SHOW_DATA := 0
ENABLE_AGC_SHOW_DATA := 0
#############################################################
TARGET = firmware
@@ -104,6 +114,9 @@ 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
@@ -175,17 +188,15 @@ else # unix
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
@@ -212,17 +223,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
@@ -313,9 +325,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
@@ -355,23 +364,19 @@ 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
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

110
README.md
View File

@@ -1,12 +1,36 @@
# Main features:
# Open re-implementation of the Quansheng UV-K5 v2.1.27 firmware
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.
All is a cloned and customized version of DualTachyon's open firmware found here ..
https://github.com/DualTachyon/uv-k5-firmware .. a cool achievement !
> [!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.
## Table of Contents
* [Main Features](#main-features)
* [Manual](#manual)
* [Radio Performance](#radio-performance)
* [User Customization](#user-customization)
* [Compiler](#compiler)
* [Building](#building)
* [Credits](#credits)
* [License](#license)
* [Example changes/updates](#example-changesupdates)
## Main features:
* many of OneOfEleven mods:
* AM fix, huge improvement in reception quality
* longpress buttons functions replicating F+ action
* long press buttons functions replicating F+ action
* fast scanning
* channel name editing in the menu
* channel name + frequency display option
* shortcut for scannlist assignment (longpress `5 NOAA`)
* scannlist toggle (longpress `* Scan` while scanning)
* 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
@@ -18,17 +42,17 @@
* some other mods introduced by me:
* SSB demodulation (adopted from fagci)
* backlight dimming
* battery voltage callibration from menu
* battery voltage calibration from menu
* better battery percentage calculation, selectable for 1600mAh or 2200mAh
* more configurable button functions
* longpress MENU as another configurable button
* long press MENU as another configurable button
* better DCS/CTCSS scanning in the menu (`* SCAN` while in RX DCS/CTCSS menu item)
* Piotr022 s-meter style
* 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
# Manual
## Manual
* [Radio operation](https://github.com/egzumer/uv-k5-firmware-custom/wiki/Radio-operation)
@@ -42,22 +66,7 @@
<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.
Anyway, have fun.
# Radio performance
## 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
@@ -68,12 +77,12 @@ 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.
@@ -83,42 +92,47 @@ 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_LTO := 1 **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_FMRADIO := 1 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_VOX := 1
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_TX1750 := 0 side key 1750Hz TX tone (older style repeater access)
ENABLE_PWRON_PASSWORD := 0 power-on password stuff
ENABLE_DTMF_CALLING := 1 DTMF calling fuctionality, sending calls, receiving calls, group calls, contacts list etc.
ENABLE_FLASHLIGHT := 1 enable top flashlight LED (on, blink, SOS)
ENABLE_BIG_FREQ := 1 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 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_CTCSS_TAIL_PHASE_SHIFT := 0 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_SHOW_CHARGE_LEVEL := 1 show the charge level when the radio is on charge
ENABLE_REVERSE_BAT_SYMBOL := 0 mirror the battery symbol on the status bar (+ pole on the right)
ENABLE_NO_CODE_SCAN_TIMEOUT := 1 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 audio bar level when TX'ing
ENABLE_AM_FIX := 1 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 := 0 show debug data for the AM fix
ENABLE_SQUELCH_MORE_SENSITIVE := 1 make squelch levels a little bit more sensitive - I plan to let user adjust the values themselves
ENABLE_FASTER_CHANNEL_SCAN := 1 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 in place of the little antenna symbols
ENABLE_AUDIO_BAR := 1 experimental, display an audio bar level when TX'ing
ENABLE_COPY_CHAN_TO_VFO := 1 copy current channel into the other VFO. Long press `1 BAND` when in channel mode
ENABLE_SPECTRUM := 1 fagci spectrum analizer, activated with `F` + `5 NOAA`
ENABLE_SPECTRUM := 1 fagci spectrum analyzer, activated with `F` + `5 NOAA`
ENABLE_REDUCE_LOW_MID_TX_POWER:= 0 makes medium and low power settings even lower
ENABLE_BYP_RAW_DEMODULATORS := 0 additional BYP (bypass?) and RAW demodulation options, prooved not to be very usefull, but it is there if you want to experiment
ENABLE_BYP_RAW_DEMODULATORS := 0 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 := 0 additional function for configurable buttons that toggles `BLMin` on and off wihout saving it to the EEPROM
ENABLE_SCAN_RANGES := 1 scan range mode for frequency scanning, see wiki for instructions (radio operation -> frequency scanning)
```
# 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.
@@ -127,9 +141,9 @@ 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.
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.
To compile directly in windows:
@@ -159,7 +173,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:
@@ -177,7 +191,7 @@ Many thanks to various people on Telegram for putting up with me during this eff
* @d1ced95
* and others I forget
# License
## License
Copyright 2023 Dual Tachyon
https://github.com/DualTachyon
@@ -194,7 +208,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 />

741
am_fix.c
View File

@@ -29,461 +29,374 @@
#include "frequencies.h"
#include "functions.h"
#include "misc.h"
#include "settings.h"
#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
{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;
#if LOOKUP_TABLE
static const t_gain_table gain_table[] =
{
{0x03BE, -7}, // 0 .. 3 5 3 6 .. 0dB -4dB 0dB -3dB .. -7dB original
{0x0000,-93}, // 1 .. 0 0 0 0 .. -28dB -24dB -8dB -33dB .. -93dB
{0x0008,-91}, // 2 .. 0 0 1 0 .. -28dB -24dB -6dB -33dB .. -91dB
{0x0010,-88}, // 3 .. 0 0 2 0 .. -28dB -24dB -3dB -33dB .. -88dB
{0x0001,-87}, // 4 .. 0 0 0 1 .. -28dB -24dB -8dB -27dB .. -87dB
{0x0009,-85}, // 5 .. 0 0 1 1 .. -28dB -24dB -6dB -27dB .. -85dB
{0x0011,-82}, // 6 .. 0 0 2 1 .. -28dB -24dB -3dB -27dB .. -82dB
{0x0002,-81}, // 7 .. 0 0 0 2 .. -28dB -24dB -8dB -21dB .. -81dB
{0x000A,-79}, // 8 .. 0 0 1 2 .. -28dB -24dB -6dB -21dB .. -79dB
{0x0012,-76}, // 9 .. 0 0 2 2 .. -28dB -24dB -3dB -21dB .. -76dB
{0x0003,-75}, // 10 .. 0 0 0 3 .. -28dB -24dB -8dB -15dB .. -75dB
{0x000B,-73}, // 11 .. 0 0 1 3 .. -28dB -24dB -6dB -15dB .. -73dB
{0x0013,-70}, // 12 .. 0 0 2 3 .. -28dB -24dB -3dB -15dB .. -70dB
{0x0004,-69}, // 13 .. 0 0 0 4 .. -28dB -24dB -8dB -9dB .. -69dB
{0x000C,-67}, // 14 .. 0 0 1 4 .. -28dB -24dB -6dB -9dB .. -67dB
{0x000D,-64}, // 15 .. 0 0 1 5 .. -28dB -24dB -6dB -6dB .. -64dB
{0x001C,-61}, // 16 .. 0 0 3 4 .. -28dB -24dB 0dB - 9dB .. -61dB
{0x001D,-58}, // 17 .. 0 0 3 5 .. -28dB -24dB 0dB -6dB .. -58dB
{0x001E,-55}, // 18 .. 0 0 3 6 .. -28dB -24dB 0dB -3dB .. -55dB
{0x001F,-52}, // 19 .. 0 0 3 7 .. -28dB -24dB 0dB 0dB .. -52dB
{0x003E,-50}, // 20 .. 0 1 3 6 .. -28dB -19dB 0dB -3dB .. -50dB
{0x003F,-47}, // 21 .. 0 1 3 7 .. -28dB -19dB 0dB 0dB .. -47dB
{0x005E,-45}, // 22 .. 0 2 3 6 .. -28dB -14dB 0dB -3dB .. -45dB
{0x005F,-42}, // 23 .. 0 2 3 7 .. -28dB -14dB 0dB 0dB .. -42dB
{0x007E,-40}, // 24 .. 0 3 3 6 .. -28dB -9dB 0dB -3dB .. -40dB
{0x007F,-37}, // 25 .. 0 3 3 7 .. -28dB -9dB 0dB 0dB .. -37dB
{0x009F,-34}, // 26 .. 0 4 3 7 .. -28dB -6dB 0dB 0dB .. -34dB
{0x00BF,-32}, // 27 .. 0 5 3 7 .. -28dB -4dB 0dB 0dB .. -32dB
{0x00DF,-30}, // 28 .. 0 6 3 7 .. -28dB -2dB 0dB 0dB .. -30dB
{0x00FF,-28}, // 29 .. 0 7 3 7 .. -28dB 0dB 0dB 0dB .. -28dB
{0x01DF,-26}, // 30 .. 1 6 3 7 .. -24dB -2dB 0dB 0dB .. -26dB
{0x01FF,-24}, // 31 .. 1 7 3 7 .. -24dB 0dB 0dB 0dB .. -24dB
{0x02BF,-23}, // 32 .. 2 5 3 7 .. -19dB -4dB 0dB 0dB .. -23dB
{0x02DF,-21}, // 33 .. 2 6 3 7 .. -19dB -2dB 0dB -0dB .. -21dB
{0x02FF,-19}, // 34 .. 2 7 3 7 .. -19dB 0dB 0dB 0dB .. -19dB
{0x035E,-17}, // 35 .. 3 2 3 6 .. 0dB -14dB 0dB -3dB .. -17dB
{0x035F,-14}, // 36 .. 3 2 3 7 .. 0dB -14dB 0dB 0dB .. -14dB
{0x037E,-12}, // 37 .. 3 3 3 6 .. 0dB -9dB 0dB -3dB .. -12dB
{0x037F,-9}, // 38 .. 3 3 3 7 .. 0dB -9dB 0dB 0dB .. -9dB
{0x038F,-6}, // 39 .. 3 4 3 7 .. 0dB - 6dB 0dB 0dB .. -6dB
{0x03BF,-4}, // 40 .. 3 5 3 7 .. 0dB -4dB 0dB 0dB .. -4dB
{0x03DF,-2}, // 41 .. 3 6 3 7 .. 0dB - 2dB 0dB 0dB .. -2dB
{0x03FF,0} // 42 .. 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};
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;
// to help reduce gain hunting, peak hold count down tick
unsigned int hold_counter[2] = {0, 0};
// only adjust stuff if we're in one of these modes
case FUNCTION_FOREGROUND:
case FUNCTION_RECEIVE:
case FUNCTION_MONITOR:
case FUNCTION_INCOMING:
break;
}
// 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_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,6 +14,7 @@
* limitations under the License.
*/
#include <assert.h>
#include <string.h>
#include "app/action.h"
@@ -21,6 +22,9 @@
#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
@@ -39,23 +43,61 @@
#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_FLASHLIGHT] = &ACTION_FlashLight,
[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_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)
{
@@ -64,11 +106,12 @@ void ACTION_Power(void)
gRequestSaveChannel = 1;
gRequestDisplayScreen = gScreenToDisplay;
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_POWER;
#endif
gRequestDisplayScreen = gScreenToDisplay;
}
void ACTION_Monitor(void)
@@ -80,12 +123,12 @@ void ACTION_Monitor(void)
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) {
gScanPauseDelayIn_10ms = scan_pause_delay_in_1_10ms;
gScheduleScanListen = false;
@@ -114,245 +157,119 @@ void ACTION_Monitor(void)
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 (!SCANNER_IsScanning())
{ // not scanning
if (SCANNER_IsScanning()) {
return;
}
gMonitor = false;
// not scanning
gMonitor = false;
#ifdef ENABLE_DTMF_CALLING
DTMF_clear_RX();
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
CHFRSCANNER_Start(false, gScanStateDir);
gScanPauseDelayIn_10ms = 1;
gScheduleScanListen = false;
gUpdateStatus = true;
}
else
{ // stop scanning
CHFRSCANNER_Stop();
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_SCANNING_STOP;
#endif
}
}
else
{ // start scanning
CHFRSCANNER_Start(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;
}
#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
CHFRSCANNER_Start(false, gScanStateDir);
gScanPauseDelayIn_10ms = 1;
gScheduleScanListen = false;
} else {
// start scanning
CHFRSCANNER_Start(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;
}
#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;
}
#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
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;
@@ -389,59 +306,134 @@ 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;
#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;
#ifdef ENABLE_BLMIN_TMP_OFF
case ACTION_OPT_BLMIN_TMP_OFF:
ACTION_BlminTmpOff();
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
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 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
}
#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,16 +19,13 @@
#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
@@ -41,4 +38,3 @@ void ACTION_BlminTmpOff(void);
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

605
app/app.c
View File

@@ -14,15 +14,22 @@
* limitations under the License.
*/
#include <assert.h>
#include <stdint.h>
#include <string.h>
#include "am_fix.h"
#include "app/action.h"
#ifdef ENABLE_AIRCOPY
#include "app/aircopy.h"
#endif
#include "app/app.h"
#include "app/chFrScanner.h"
#include "app/dtmf.h"
#ifdef ENABLE_FLASHLIGHT
#include "app/flashlight.h"
#endif
#ifdef ENABLE_FMRADIO
#include "app/fm.h"
#endif
@@ -44,7 +51,6 @@
#include "driver/keyboard.h"
#include "driver/st7565.h"
#include "driver/system.h"
#include "am_fix.h"
#include "dtmf.h"
#include "external/printf/printf.h"
#include "frequencies.h"
@@ -53,6 +59,7 @@
#include "misc.h"
#include "radio.h"
#include "settings.h"
#if defined(ENABLE_OVERLAY)
#include "sram-overlay.h"
#endif
@@ -63,26 +70,28 @@
#include "ui/status.h"
#include "ui/ui.h"
#include "debugging.h"
static void ProcessKey(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld);
static void FlashlightTimeSlice();
static void UpdateRSSI(const int vfo)
{
int16_t rssi = BK4819_GetRSSI();
#ifdef ENABLE_AM_FIX
// add RF gain adjust compensation
if (gEeprom.VfoInfo[vfo].Modulation == MODULATION_AM && gSetting_AM_fix)
rssi -= rssi_gain_diff[vfo];
#endif
void (*ProcessKeysFunctions[])(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld) = {
[DISPLAY_MAIN] = &MAIN_ProcessKeys,
[DISPLAY_MENU] = &MENU_ProcessKeys,
[DISPLAY_SCANNER] = &SCANNER_ProcessKeys,
if (gCurrentRSSI[vfo] == rssi)
return; // no change
#ifdef ENABLE_FMRADIO
[DISPLAY_FM] = &FM_ProcessKeys,
#endif
#ifdef ENABLE_AIRCOPY
[DISPLAY_AIRCOPY] = &AIRCOPY_ProcessKeys,
#endif
};
static_assert(ARRAY_SIZE(ProcessKeysFunctions) == DISPLAY_N_ELEM);
gCurrentRSSI[vfo] = rssi;
UI_UpdateRSSI(rssi, vfo);
}
static void CheckForIncoming(void)
{
@@ -108,9 +117,6 @@ static void CheckForIncoming(void)
{
FUNCTION_Select(FUNCTION_INCOMING);
//gUpdateDisplay = true;
UpdateRSSI(gEeprom.RX_VFO);
gUpdateRSSI = true;
}
return;
@@ -124,9 +130,6 @@ static void CheckForIncoming(void)
{
FUNCTION_Select(FUNCTION_INCOMING);
//gUpdateDisplay = true;
UpdateRSSI(gEeprom.RX_VFO);
gUpdateRSSI = true;
}
return;
}
@@ -146,9 +149,6 @@ static void CheckForIncoming(void)
{
FUNCTION_Select(FUNCTION_INCOMING);
//gUpdateDisplay = true;
UpdateRSSI(gEeprom.RX_VFO);
gUpdateRSSI = true;
}
return;
}
@@ -163,16 +163,11 @@ static void CheckForIncoming(void)
{
FUNCTION_Select(FUNCTION_INCOMING);
//gUpdateDisplay = true;
UpdateRSSI(gEeprom.RX_VFO);
gUpdateRSSI = true;
}
}
static void HandleIncoming(void)
{
bool bFlag;
if (!g_SquelchLost) { // squelch is closed
#ifdef ENABLE_DTMF_CALLING
if (gDTMF_RX_index > 0)
@@ -185,7 +180,7 @@ static void HandleIncoming(void)
return;
}
bFlag = (gScanStateDir == SCAN_OFF && gCurrentCodeType == CODE_TYPE_OFF);
bool bFlag = (gScanStateDir == SCAN_OFF && gCurrentCodeType == CODE_TYPE_OFF);
#ifdef ENABLE_NOAA
if (IS_NOAA_CHANNEL(gRxVfo->CHANNEL_SAVE) && gNOAACountdown_10ms > 0) {
@@ -199,7 +194,9 @@ static void HandleIncoming(void)
gFoundCTCSS = false;
}
if (g_CDCSS_Lost && gCDCSSCodeType == CDCSS_POSITIVE_CODE && (gCurrentCodeType == CODE_TYPE_DIGITAL || gCurrentCodeType == CODE_TYPE_REVERSE_DIGITAL)) {
if (g_CDCSS_Lost && gCDCSSCodeType == CDCSS_POSITIVE_CODE
&& (gCurrentCodeType == CODE_TYPE_DIGITAL || gCurrentCodeType == CODE_TYPE_REVERSE_DIGITAL))
{
gFoundCDCSS = false;
}
else if (!bFlag)
@@ -230,7 +227,7 @@ static void HandleIncoming(void)
}
#endif
APP_StartListening(gMonitor ? FUNCTION_MONITOR : FUNCTION_RECEIVE, false);
APP_StartListening(gMonitor ? FUNCTION_MONITOR : FUNCTION_RECEIVE);
}
static void HandleReceive(void)
@@ -444,10 +441,9 @@ static void HandleFunction(void)
}
}
void APP_StartListening(FUNCTION_Type_t Function, const bool reset_am_fix)
void APP_StartListening(FUNCTION_Type_t function)
{
const unsigned int chan = gEeprom.RX_VFO;
// const unsigned int chan = gRxVfo->CHANNEL_SAVE;
const unsigned int vfo = gEeprom.RX_VFO;
#ifdef ENABLE_DTMF_CALLING
if (gSetting_KILLED)
@@ -460,13 +456,14 @@ void APP_StartListening(FUNCTION_Type_t Function, const bool reset_am_fix)
#endif
// clear the other vfo's rssi level (to hide the antenna symbol)
gVFO_RSSI_bar_level[(chan + 1) & 1u] = 0;
gVFO_RSSI_bar_level[!vfo] = 0;
AUDIO_AudioPathOn();
gEnableSpeaker = true;
if (gSetting_backlight_on_tx_rx >= BACKLIGHT_ON_TR_RX)
if (gSetting_backlight_on_tx_rx != BACKLIGHT_ON_TR_OFF) {
BACKLIGHT_TurnOn();
}
if (gScanStateDir != SCAN_OFF)
CHFRSCANNER_Found();
@@ -476,7 +473,7 @@ void APP_StartListening(FUNCTION_Type_t Function, const bool reset_am_fix)
gRxVfo->CHANNEL_SAVE = gNoaaChannel + NOAA_CHANNEL_FIRST;
gRxVfo->pRX->Frequency = NoaaFrequencyTable[gNoaaChannel];
gRxVfo->pTX->Frequency = NoaaFrequencyTable[gNoaaChannel];
gEeprom.ScreenChannel[chan] = gRxVfo->CHANNEL_SAVE;
gEeprom.ScreenChannel[vfo] = gRxVfo->CHANNEL_SAVE;
gNOAA_Countdown_10ms = 500; // 5 sec
gScheduleNOAA = false;
@@ -499,52 +496,23 @@ void APP_StartListening(FUNCTION_Type_t Function, const bool reset_am_fix)
gUpdateStatus = true;
}
{ // RF RX front end gain
// original QS front end register settings
// 0x03BE 00000 011 101 11 110
const uint8_t orig_lna_short = 3; // 0dB
const uint8_t orig_lna = 5; // -4dB
const uint8_t orig_mixer = 3; // 0dB
const uint8_t orig_pga = 6; // -3dB
#ifdef ENABLE_AM_FIX
if (gRxVfo->Modulation == MODULATION_AM && gSetting_AM_fix) { // AM RX mode
if (reset_am_fix)
AM_fix_reset(chan); // TODO: only reset it when moving channel/frequency
AM_fix_10ms(chan);
}
else { // FM RX mode
BK4819_WriteRegister(BK4819_REG_13, (orig_lna_short << 8) | (orig_lna << 5) | (orig_mixer << 3) | (orig_pga << 0));
}
#else
BK4819_WriteRegister(BK4819_REG_13, (orig_lna_short << 8) | (orig_lna << 5) | (orig_mixer << 3) | (orig_pga << 0));
#endif
}
// AF gain - original QS values
// if (gRxVfo->Modulation != MODULATION_FM){
// BK4819_WriteRegister(BK4819_REG_48, 0xB3A8);
// }
// else
{
BK4819_WriteRegister(BK4819_REG_48,
(11u << 12) | // ??? .. 0 to 15, doesn't seem to make any difference
( 0u << 10) | // AF Rx Gain-1
(gEeprom.VOLUME_GAIN << 4) | // AF Rx Gain-2
(gEeprom.DAC_GAIN << 0)); // AF DAC Gain (after Gain-1 and Gain-2)
}
#ifdef ENABLE_VOICE
if (gVoiceWriteIndex == 0) // AM/FM RX mode will be set when the voice has finished
#endif
RADIO_SetModulation(gRxVfo->Modulation); // no need, set it now
FUNCTION_Select(Function);
FUNCTION_Select(function);
#ifdef ENABLE_FMRADIO
if (Function == FUNCTION_MONITOR || gFmRadioMode)
if (function == FUNCTION_MONITOR || gFmRadioMode)
#else
if (Function == FUNCTION_MONITOR)
if (function == FUNCTION_MONITOR)
#endif
{ // squelch is disabled
if (gScreenToDisplay != DISPLAY_MENU) // 1of11 .. don't close the menu
@@ -702,36 +670,36 @@ static void CheckRadioInterrupts(void)
g_CTCSS_Lost = false;
#ifdef ENABLE_VOX
if (interrupt_status_bits & BK4819_REG_02_VOX_LOST)
if (interrupt_status_bits & BK4819_REG_02_VOX_LOST)
{
g_VOX_Lost = true;
gVoxPauseCountdown = 10;
if (gEeprom.VOX_SWITCH)
{
g_VOX_Lost = true;
gVoxPauseCountdown = 10;
if (gEeprom.VOX_SWITCH)
if (gCurrentFunction == FUNCTION_POWER_SAVE && !gRxIdleMode)
{
if (gCurrentFunction == FUNCTION_POWER_SAVE && !gRxIdleMode)
{
gPowerSave_10ms = power_save2_10ms;
gPowerSaveCountdownExpired = 0;
}
if (gEeprom.DUAL_WATCH != DUAL_WATCH_OFF && (gScheduleDualWatch || gDualWatchCountdown_10ms < dual_watch_count_after_vox_10ms))
{
gDualWatchCountdown_10ms = dual_watch_count_after_vox_10ms;
gScheduleDualWatch = false;
// let the user see DW is not active
gDualWatchActive = false;
gUpdateStatus = true;
}
gPowerSave_10ms = power_save2_10ms;
gPowerSaveCountdownExpired = 0;
}
if (gEeprom.DUAL_WATCH != DUAL_WATCH_OFF && (gScheduleDualWatch || gDualWatchCountdown_10ms < dual_watch_count_after_vox_10ms))
{
gDualWatchCountdown_10ms = dual_watch_count_after_vox_10ms;
gScheduleDualWatch = false;
// let the user see DW is not active
gDualWatchActive = false;
gUpdateStatus = true;
}
}
}
if (interrupt_status_bits & BK4819_REG_02_VOX_FOUND)
{
g_VOX_Lost = false;
gVoxPauseCountdown = 0;
}
if (interrupt_status_bits & BK4819_REG_02_VOX_FOUND)
{
g_VOX_Lost = false;
gVoxPauseCountdown = 0;
}
#endif
if (interrupt_status_bits & BK4819_REG_02_SQUELCH_LOST)
@@ -746,18 +714,19 @@ static void CheckRadioInterrupts(void)
BK4819_ToggleGpioOut(BK4819_GPIO6_PIN2_GREEN, false);
}
#ifdef ENABLE_AIRCOPY
if (interrupt_status_bits & BK4819_REG_02_FSK_FIFO_ALMOST_FULL &&
gScreenToDisplay == DISPLAY_AIRCOPY &&
gAircopyState == AIRCOPY_TRANSFER &&
gAirCopyIsSendMode == 0)
{
unsigned int i;
for (i = 0; i < 4; i++)
g_FSK_Buffer[gFSKWriteIndex++] = BK4819_ReadRegister(BK4819_REG_5F);
AIRCOPY_StorePacket();
#ifdef ENABLE_AIRCOPY
if (interrupt_status_bits & BK4819_REG_02_FSK_FIFO_ALMOST_FULL &&
gScreenToDisplay == DISPLAY_AIRCOPY &&
gAircopyState == AIRCOPY_TRANSFER &&
gAirCopyIsSendMode == 0)
{
for (unsigned int i = 0; i < 4; i++) {
g_FSK_Buffer[gFSKWriteIndex++] = BK4819_ReadRegister(BK4819_REG_5F);
}
#endif
AIRCOPY_StorePacket();
}
#endif
}
}
@@ -773,87 +742,86 @@ void APP_EndTransmission(void)
}
#ifdef ENABLE_VOX
static void HandleVox(void)
{
static void HandleVox(void)
{
#ifdef ENABLE_DTMF_CALLING
if (gSetting_KILLED)
return;
if (gSetting_KILLED)
return;
#endif
if (gVoxResumeCountdown == 0)
{
if (gVoxPauseCountdown)
return;
}
else
{
g_VOX_Lost = false;
gVoxPauseCountdown = 0;
}
#ifdef ENABLE_FMRADIO
if (gFmRadioMode)
return;
#endif
if (gCurrentFunction == FUNCTION_RECEIVE || gCurrentFunction == FUNCTION_MONITOR)
if (gVoxResumeCountdown == 0)
{
if (gVoxPauseCountdown)
return;
if (gScanStateDir != SCAN_OFF)
}
else
{
g_VOX_Lost = false;
gVoxPauseCountdown = 0;
}
#ifdef ENABLE_FMRADIO
if (gFmRadioMode)
return;
if (gVOX_NoiseDetected)
#endif
if (gCurrentFunction == FUNCTION_RECEIVE || gCurrentFunction == FUNCTION_MONITOR)
return;
if (gScanStateDir != SCAN_OFF)
return;
if (gVOX_NoiseDetected)
{
if (g_VOX_Lost)
gVoxStopCountdown_10ms = vox_stop_count_down_10ms;
else if (gVoxStopCountdown_10ms == 0)
gVOX_NoiseDetected = false;
if (gCurrentFunction == FUNCTION_TRANSMIT && !gPttIsPressed && !gVOX_NoiseDetected)
{
if (g_VOX_Lost)
gVoxStopCountdown_10ms = vox_stop_count_down_10ms;
else
if (gVoxStopCountdown_10ms == 0)
gVOX_NoiseDetected = false;
if (gCurrentFunction == FUNCTION_TRANSMIT && !gPttIsPressed && !gVOX_NoiseDetected)
if (gFlagEndTransmission)
{
if (gFlagEndTransmission)
//if (gCurrentFunction != FUNCTION_FOREGROUND)
FUNCTION_Select(FUNCTION_FOREGROUND);
}
else
{
APP_EndTransmission();
if (gEeprom.REPEATER_TAIL_TONE_ELIMINATION == 0)
{
//if (gCurrentFunction != FUNCTION_FOREGROUND)
FUNCTION_Select(FUNCTION_FOREGROUND);
}
else
{
APP_EndTransmission();
if (gEeprom.REPEATER_TAIL_TONE_ELIMINATION == 0)
{
//if (gCurrentFunction != FUNCTION_FOREGROUND)
FUNCTION_Select(FUNCTION_FOREGROUND);
}
else
gRTTECountdown = gEeprom.REPEATER_TAIL_TONE_ELIMINATION * 10;
}
gUpdateStatus = true;
gUpdateDisplay = true;
gFlagEndTransmission = false;
gRTTECountdown = gEeprom.REPEATER_TAIL_TONE_ELIMINATION * 10;
}
return;
gUpdateStatus = true;
gUpdateDisplay = true;
gFlagEndTransmission = false;
}
if (g_VOX_Lost)
return;
}
if (g_VOX_Lost)
{
gVOX_NoiseDetected = true;
if (gCurrentFunction == FUNCTION_POWER_SAVE)
FUNCTION_Select(FUNCTION_FOREGROUND);
if (gCurrentFunction != FUNCTION_TRANSMIT && !SerialConfigInProgress())
{
gVOX_NoiseDetected = true;
if (gCurrentFunction == FUNCTION_POWER_SAVE)
FUNCTION_Select(FUNCTION_FOREGROUND);
if (gCurrentFunction != FUNCTION_TRANSMIT && gSerialConfigCountDown_500ms == 0)
{
#ifdef ENABLE_DTMF_CALLING
gDTMF_ReplyState = DTMF_REPLY_NONE;
gDTMF_ReplyState = DTMF_REPLY_NONE;
#endif
RADIO_PrepareTX();
gUpdateDisplay = true;
}
RADIO_PrepareTX();
gUpdateDisplay = true;
}
}
}
#endif
void APP_Update(void)
@@ -865,7 +833,7 @@ void APP_Update(void)
}
#endif
if (gCurrentFunction == FUNCTION_TRANSMIT && (gTxTimeoutReached || gSerialConfigCountDown_500ms > 0))
if (gCurrentFunction == FUNCTION_TRANSMIT && (gTxTimeoutReached || SerialConfigInProgress()))
{ // transmitter timed out or must de-key
gTxTimeoutReached = false;
@@ -950,12 +918,8 @@ void APP_Update(void)
}
#ifdef ENABLE_FMRADIO
if (gScheduleFM &&
gFM_ScanState != FM_SCAN_OFF &&
gCurrentFunction != FUNCTION_MONITOR &&
gCurrentFunction != FUNCTION_RECEIVE &&
gCurrentFunction != FUNCTION_TRANSMIT)
{ // switch to FM radio mode
if (gScheduleFM && gFM_ScanState != FM_SCAN_OFF && !FUNCTION_IsRx()) {
// switch to FM radio mode
FM_Play();
gScheduleFM = false;
}
@@ -966,23 +930,20 @@ void APP_Update(void)
HandleVox();
#endif
if (gSchedulePowerSave)
{
if (
#ifdef ENABLE_FMRADIO
gFmRadioMode ||
#endif
gPttIsPressed ||
if (gSchedulePowerSave) {
if (gPttIsPressed ||
gKeyBeingHeld ||
gEeprom.BATTERY_SAVE == 0 ||
gScanStateDir != SCAN_OFF ||
gCssBackgroundScan ||
gCssBackgroundScan ||
gScreenToDisplay != DISPLAY_MAIN
#ifdef ENABLE_FMRADIO
|| gFmRadioMode
#endif
#ifdef ENABLE_DTMF_CALLING
|| gDTMF_CallState != DTMF_CALL_STATE_NONE
#endif
)
{
){
gBatterySaveCountdown_10ms = battery_save_count_10ms;
}
else
@@ -1003,13 +964,15 @@ void APP_Update(void)
#endif
}
#ifdef ENABLE_VOICE
if (gPowerSaveCountdownExpired && gCurrentFunction == FUNCTION_POWER_SAVE && gVoiceWriteIndex == 0)
#else
if (gPowerSaveCountdownExpired && gCurrentFunction == FUNCTION_POWER_SAVE)
#endif
{ // wake up, enable RX then go back to sleep
if (gPowerSaveCountdownExpired && gCurrentFunction == FUNCTION_POWER_SAVE
#ifdef ENABLE_VOICE
&& gVoiceWriteIndex == 0
#endif
)
{
static bool goToSleep;
// wake up, enable RX then go back to sleep
if (gRxIdleMode)
{
BK4819_Conditional_RX_TurnOn_and_GPIO6_Enable();
@@ -1024,8 +987,7 @@ void APP_Update(void)
!gCssBackgroundScan)
{ // dual watch mode, toggle between the two VFO's
DualwatchAlternate();
gUpdateRSSI = false;
goToSleep = false;
}
FUNCTION_Init();
@@ -1033,16 +995,13 @@ void APP_Update(void)
gPowerSave_10ms = power_save1_10ms; // come back here in a bit
gRxIdleMode = false; // RX is awake
}
else
if (gEeprom.DUAL_WATCH == DUAL_WATCH_OFF || gScanStateDir != SCAN_OFF || gCssBackgroundScan || gUpdateRSSI)
else if (gEeprom.DUAL_WATCH == DUAL_WATCH_OFF || gScanStateDir != SCAN_OFF || gCssBackgroundScan || goToSleep)
{ // dual watch mode off or scanning or rssi update request
UpdateRSSI(gEeprom.RX_VFO);
// go back to sleep
gPowerSave_10ms = gEeprom.BATTERY_SAVE * 10;
gRxIdleMode = true;
goToSleep = false;
BK4819_DisableVox();
BK4819_Sleep();
@@ -1051,13 +1010,11 @@ void APP_Update(void)
// Authentic device checked removed
}
else
{
else {
// toggle between the two VFO's
DualwatchAlternate();
gUpdateRSSI = true;
gPowerSave_10ms = power_save1_10ms;
goToSleep = true;
}
gPowerSaveCountdownExpired = false;
@@ -1082,9 +1039,9 @@ static void CheckKeys(void)
// -------------------- PTT ------------------------
if (gPttIsPressed)
{
if (GPIO_CheckBit(&GPIOC->DATA, GPIOC_PIN_PTT) || gSerialConfigCountDown_500ms > 0)
if (GPIO_CheckBit(&GPIOC->DATA, GPIOC_PIN_PTT) || SerialConfigInProgress())
{ // PTT released or serial comms config in progress
if (++gPttDebounceCounter >= 3 || gSerialConfigCountDown_500ms > 0) // 30ms
if (++gPttDebounceCounter >= 3 || SerialConfigInProgress()) // 30ms
{ // stop transmitting
ProcessKey(KEY_PTT, false, false);
gPttIsPressed = false;
@@ -1095,7 +1052,7 @@ static void CheckKeys(void)
else
gPttDebounceCounter = 0;
}
else if (!GPIO_CheckBit(&GPIOC->DATA, GPIOC_PIN_PTT) && gSerialConfigCountDown_500ms == 0)
else if (!GPIO_CheckBit(&GPIOC->DATA, GPIOC_PIN_PTT) && !SerialConfigInProgress())
{ // PTT pressed
if (++gPttDebounceCounter >= 3) // 30ms
{ // start transmitting
@@ -1187,8 +1144,7 @@ void APP_TimeSlice10ms(void)
#endif
#ifdef ENABLE_AM_FIX
// if (gEeprom.VfoInfo[gEeprom.RX_VFO].Modulation != MODULATION_FM && gSetting_AM_fix)
if (gRxVfo->Modulation == MODULATION_AM && gSetting_AM_fix)
if (gRxVfo->Modulation == MODULATION_AM)
AM_fix_10ms(gEeprom.RX_VFO);
#endif
@@ -1207,10 +1163,10 @@ void APP_TimeSlice10ms(void)
if (gCurrentFunction == FUNCTION_TRANSMIT)
{ // transmitting
#ifdef ENABLE_AUDIO_BAR
if (gSetting_mic_bar && (gFlashLightBlinkCounter % (150 / 10)) == 0) // once every 150ms
UI_DisplayAudioBar();
#endif
#ifdef ENABLE_AUDIO_BAR
if (gSetting_mic_bar && (gFlashLightBlinkCounter % (150 / 10)) == 0) // once every 150ms
UI_DisplayAudioBar();
#endif
}
if (gUpdateDisplay)
@@ -1224,25 +1180,27 @@ void APP_TimeSlice10ms(void)
// Skipping authentic device checks
#ifdef ENABLE_FMRADIO
if (gFmRadioMode && gFmRadioCountdown_500ms > 0) // 1of11
return;
#endif
#ifdef ENABLE_FMRADIO
if (gFmRadioMode && gFmRadioCountdown_500ms > 0) // 1of11
return;
#endif
#ifdef ENABLE_FLASHLIGHT
FlashlightTimeSlice();
#endif
#ifdef ENABLE_VOX
if (gVoxResumeCountdown > 0)
gVoxResumeCountdown--;
#ifdef ENABLE_VOX
if (gVoxResumeCountdown > 0)
gVoxResumeCountdown--;
if (gVoxPauseCountdown > 0)
gVoxPauseCountdown--;
#endif
if (gVoxPauseCountdown > 0)
gVoxPauseCountdown--;
#endif
if (gCurrentFunction == FUNCTION_TRANSMIT)
{
#ifdef ENABLE_ALARM
if (gAlarmState == ALARM_STATE_TXALARM || gAlarmState == ALARM_STATE_ALARM)
if (gAlarmState == ALARM_STATE_TXALARM || gAlarmState == ALARM_STATE_SITE_ALARM)
{
uint16_t Tone;
@@ -1264,7 +1222,7 @@ void APP_TimeSlice10ms(void)
if (gAlarmState == ALARM_STATE_TXALARM)
{
gAlarmState = ALARM_STATE_ALARM;
gAlarmState = ALARM_STATE_SITE_ALARM;
RADIO_EnableCxCSS();
BK4819_SetupPowerAmplifier(0, 0);
@@ -1324,13 +1282,8 @@ void APP_TimeSlice10ms(void)
#ifdef ENABLE_AIRCOPY
if (gScreenToDisplay == DISPLAY_AIRCOPY && gAircopyState == AIRCOPY_TRANSFER && gAirCopyIsSendMode == 1)
{
if (gAircopySendCountdown > 0)
{
if (--gAircopySendCountdown == 0)
{
AIRCOPY_SendMessage();
GUI_DisplayScreen();
}
if (!AIRCOPY_SendMessage()) {
GUI_DisplayScreen();
}
}
#endif
@@ -1414,28 +1367,25 @@ void APP_TimeSlice500ms(void)
// Skipped authentic device check
#ifdef ENABLE_FMRADIO
if (gFmRadioCountdown_500ms > 0)
{
gFmRadioCountdown_500ms--;
if (gFmRadioMode) // 1of11
return;
}
#endif
if (gBacklightCountdown > 0 &&
!gAskToSave &&
!gCssBackgroundScan &&
// don't turn off backlight if user is in backlight menu option
!(gScreenToDisplay == DISPLAY_MENU && (UI_MENU_GetCurrentMenuId() == MENU_ABR || UI_MENU_GetCurrentMenuId() == MENU_ABR_MAX))
)
{ if (--gBacklightCountdown == 0)
if (gEeprom.BACKLIGHT_TIME < (ARRAY_SIZE(gSubMenu_BACKLIGHT) - 1)) // backlight is not set to be always on
BACKLIGHT_TurnOff(); // turn backlight off
}
if (gSerialConfigCountDown_500ms > 0)
#ifdef ENABLE_FMRADIO
if (gFmRadioCountdown_500ms > 0)
{
gFmRadioCountdown_500ms--;
if (gFmRadioMode) // 1of11
return;
}
#endif
if (gBacklightCountdown_500ms > 0 && !gAskToSave && !gCssBackgroundScan &&
// don't turn off backlight if user is in backlight menu option
!(gScreenToDisplay == DISPLAY_MENU && (UI_MENU_GetCurrentMenuId() == MENU_ABR || UI_MENU_GetCurrentMenuId() == MENU_ABR_MAX)))
{
if (--gBacklightCountdown_500ms == 0) {
if (gEeprom.BACKLIGHT_TIME < (ARRAY_SIZE(gSubMenu_BACKLIGHT) - 1)) {
// backlight is not set to be always on
BACKLIGHT_TurnOff();
}
}
}
if (gReducedService)
@@ -1537,11 +1487,7 @@ void APP_TimeSlice500ms(void)
GUI_DisplayType_t disp = DISPLAY_INVALID;
#ifdef ENABLE_FMRADIO
if (gFmRadioMode &&
gCurrentFunction != FUNCTION_RECEIVE &&
gCurrentFunction != FUNCTION_MONITOR &&
gCurrentFunction != FUNCTION_TRANSMIT)
{
if (gFmRadioMode && ! FUNCTION_IsRx()) {
disp = DISPLAY_FM;
}
#endif
@@ -1561,20 +1507,14 @@ void APP_TimeSlice500ms(void)
}
}
if (gCurrentFunction != FUNCTION_POWER_SAVE && gCurrentFunction != FUNCTION_TRANSMIT)
UpdateRSSI(gEeprom.RX_VFO);
if (!gPttIsPressed && gVFOStateResumeCountdown_500ms > 0)
{
if (--gVFOStateResumeCountdown_500ms == 0)
{
RADIO_SetVfoState(VFO_STATE_NORMAL);
#ifdef ENABLE_FMRADIO
if (gCurrentFunction != FUNCTION_RECEIVE &&
gCurrentFunction != FUNCTION_TRANSMIT &&
gCurrentFunction != FUNCTION_MONITOR &&
gFmRadioMode)
{ // switch back to FM radio mode
if (gFmRadioMode && !FUNCTION_IsRx()) {
// switch back to FM radio mode
FM_Start();
GUI_SelectNextDisplay(DISPLAY_FM);
}
@@ -1584,6 +1524,7 @@ void APP_TimeSlice500ms(void)
BATTERY_TimeSlice500ms();
SCANNER_TimeSlice500ms();
UI_MAIN_TimeSlice500ms();
#ifdef ENABLE_DTMF_CALLING
if (gCurrentFunction != FUNCTION_TRANSMIT)
@@ -1626,33 +1567,30 @@ void APP_TimeSlice500ms(void)
}
#if defined(ENABLE_ALARM) || defined(ENABLE_TX1750)
static void ALARM_Off(void)
{
gAlarmState = ALARM_STATE_OFF;
static void ALARM_Off(void)
{
AUDIO_AudioPathOff();
gEnableSpeaker = false;
AUDIO_AudioPathOff();
gEnableSpeaker = false;
if (gEeprom.ALARM_MODE == ALARM_MODE_TONE)
{
RADIO_SendEndOfTransmission();
RADIO_EnableCxCSS();
}
#ifdef ENABLE_VOX
gVoxResumeCountdown = 80;
#endif
SYSTEM_DelayMs(5);
RADIO_SetupRegisters(true);
if (gScreenToDisplay != DISPLAY_MENU) // 1of11 .. don't close the menu
gRequestDisplayScreen = DISPLAY_MAIN;
if (gAlarmState == ALARM_STATE_TXALARM) {
RADIO_SendEndOfTransmission();
RADIO_EnableCxCSS();
}
gAlarmState = ALARM_STATE_OFF;
#ifdef ENABLE_VOX
gVoxResumeCountdown = 80;
#endif
SYSTEM_DelayMs(5);
RADIO_SetupRegisters(true);
if (gScreenToDisplay != DISPLAY_MENU) // 1of11 .. don't close the menu
gRequestDisplayScreen = DISPLAY_MAIN;
}
#endif
static void ProcessKey(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
{
@@ -1706,10 +1644,9 @@ static void ProcessKey(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
}
else // key pressed or held
{
const uint8_t s = gSetting_backlight_on_tx_rx;
const int m = UI_MENU_GetCurrentMenuId();
if ( //not when PTT and the backlight shouldn't turn on on TX
!(Key == KEY_PTT && s != BACKLIGHT_ON_TR_TX && s != BACKLIGHT_ON_TR_TXRX)
!(Key == KEY_PTT && !(gSetting_backlight_on_tx_rx & BACKLIGHT_ON_TR_TX))
// not in the backlight menu
&& !(gScreenToDisplay == DISPLAY_MENU && ( m == MENU_ABR || m == MENU_ABR_MAX || m == MENU_ABR_MIN))
)
@@ -1905,51 +1842,25 @@ static void ProcessKey(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
}
}
#if defined(ENABLE_ALARM) || defined(ENABLE_TX1750)
else if ((!bKeyHeld && bKeyPressed) || (gAlarmState == ALARM_STATE_TX1750 && bKeyHeld && !bKeyPressed))
{
ALARM_Off();
if (gEeprom.REPEATER_TAIL_TONE_ELIMINATION == 0)
FUNCTION_Select(FUNCTION_FOREGROUND);
else
if ((!bKeyHeld && bKeyPressed) || (gAlarmState == ALARM_STATE_TX1750 && bKeyHeld && !bKeyPressed))
{
ALARM_Off();
gRTTECountdown = gEeprom.REPEATER_TAIL_TONE_ELIMINATION * 10;
if (gEeprom.REPEATER_TAIL_TONE_ELIMINATION == 0)
FUNCTION_Select(FUNCTION_FOREGROUND);
else
gRTTECountdown = gEeprom.REPEATER_TAIL_TONE_ELIMINATION * 10;
if (Key == KEY_PTT)
gPttWasPressed = true;
else
if (!bKeyHeld)
gPttWasReleased = true;
}
if (Key == KEY_PTT)
gPttWasPressed = true;
else
if (!bKeyHeld)
gPttWasReleased = true;
}
#endif
}
else if (Key != KEY_SIDE1 && Key != KEY_SIDE2) {
switch (gScreenToDisplay) {
case DISPLAY_MAIN:
MAIN_ProcessKeys(Key, bKeyPressed, bKeyHeld);
break;
#ifdef ENABLE_FMRADIO
case DISPLAY_FM:
FM_ProcessKeys(Key, bKeyPressed, bKeyHeld);
break;
#endif
case DISPLAY_MENU:
MENU_ProcessKeys(Key, bKeyPressed, bKeyHeld);
break;
case DISPLAY_SCANNER:
SCANNER_ProcessKeys(Key, bKeyPressed, bKeyHeld);
break;
#ifdef ENABLE_AIRCOPY
case DISPLAY_AIRCOPY:
AIRCOPY_ProcessKeys(Key, bKeyPressed, bKeyHeld);
break;
#endif
case DISPLAY_INVALID:
default:
break;
}
else if (Key != KEY_SIDE1 && Key != KEY_SIDE2 && gScreenToDisplay != DISPLAY_INVALID) {
ProcessKeysFunctions[gScreenToDisplay](Key, bKeyPressed, bKeyHeld);
}
else
#ifdef ENABLE_AIRCOPY
@@ -2011,7 +1922,7 @@ Skip:
gRequestSaveVFO = false;
}
if (gRequestSaveChannel > 0)
if (gRequestSaveChannel > 0) // TODO: remove the gRequestSaveChannel, why use global variable for that??
{
if (!bKeyHeld)
{
@@ -2105,37 +2016,3 @@ Skip:
gUpdateDisplay = true;
}
static void FlashlightTimeSlice()
{
if (gFlashLightState == FLASHLIGHT_BLINK && (gFlashLightBlinkCounter & 15u) == 0)
GPIO_FlipBit(&GPIOC->DATA, GPIOC_PIN_FLASHLIGHT);
else 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;
}
else 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++;
}
}
}

View File

@@ -24,7 +24,7 @@
#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);

View File

@@ -71,14 +71,14 @@ void CHFRSCANNER_ContinueScanning(void)
if (IS_FREQ_CHANNEL(gNextMrChannel))
{
if (gCurrentFunction == FUNCTION_INCOMING)
APP_StartListening(gMonitor ? FUNCTION_MONITOR : FUNCTION_RECEIVE, true);
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, true);
APP_StartListening(gMonitor ? FUNCTION_MONITOR : FUNCTION_RECEIVE);
else
NextMemChannel(); // switch to next channel
}

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

View File

@@ -62,7 +62,7 @@ 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] >= 760 && gFM_Channels[Channel] < 1080));
}
uint8_t FM_FindNextChannel(uint8_t Channel, uint8_t Direction)
@@ -193,42 +193,37 @@ 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;
@@ -336,7 +331,7 @@ static void Key_DIGITS(KEY_Code_t Key, uint8_t state)
static void Key_FUNC(KEY_Code_t Key, uint8_t state)
{
if (state == BUTTON_EVENT_SHORT || state == BUTTON_EVENT_HELD)
if (state == BUTTON_EVENT_SHORT || state == BUTTON_EVENT_HELD)
{
bool autoScan = gWasFKeyPressed || (state == BUTTON_EVENT_HELD);
@@ -446,11 +441,9 @@ static void Key_MENU(uint8_t state)
if (gAskToSave)
{
gFM_Channels[gFM_ChannelPosition] = gEeprom.FM_FrequencyPlaying;
gAskToSave = false;
gRequestSaveFM = true;
gRequestSaveFM = true;
}
else
gAskToSave = true;
gAskToSave = !gAskToSave;
}
else
{
@@ -462,10 +455,9 @@ static void Key_MENU(uint8_t state)
BK1080_SetFrequency(gEeprom.FM_FrequencyPlaying);
gRequestSaveFM = true;
gAskToDelete = false;
}
else
gAskToDelete = true;
gAskToDelete = !gAskToDelete;
}
}
else
@@ -480,27 +472,23 @@ static void Key_MENU(uint8_t state)
if (gAskToSave)
{
gFM_Channels[gFM_ChannelPosition] = gEeprom.FM_FrequencyPlaying;
gAskToSave = false;
gRequestSaveFM = true;
}
else
gAskToSave = true;
gAskToSave = !gAskToSave;
}
}
static void Key_UP_DOWN(uint8_t state, int8_t Step)
{
if (state == BUTTON_EVENT_PRESSED) {
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;
} else if (gInputBoxIndex || state!=BUTTON_EVENT_HELD) {
return;
}
if (gAskToSave) {
@@ -530,6 +518,7 @@ static void Key_UP_DOWN(uint8_t state, int8_t Step)
}
else {
uint16_t Frequency = gEeprom.FM_SelectedFrequency + Step;
if (Frequency < gEeprom.FM_LowerLimit)
Frequency = gEeprom.FM_UpperLimit;
else
@@ -552,8 +541,6 @@ void FM_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
{
uint8_t state = bKeyPressed + 2 * bKeyHeld;
switch (Key)
{
case KEY_0:
@@ -570,10 +557,10 @@ void FM_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
break;
case KEY_STAR:
Key_FUNC(Key, state);
break;
break;
case KEY_MENU:
Key_MENU(state);
return;
break;
case KEY_UP:
Key_UP_DOWN(state, 1);
break;
@@ -636,6 +623,7 @@ void FM_Play(void)
void FM_Start(void)
{
gDualWatchActive = false;
gFmRadioMode = true;
gFM_ScanState = FM_SCAN_OFF;
gFM_RestoreCountdown_10ms = 0;

View File

@@ -38,7 +38,6 @@ 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);
@@ -59,4 +58,3 @@ void FM_Start(void);
#endif
#endif

View File

@@ -107,7 +107,7 @@ 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

View File

@@ -46,7 +46,7 @@
void toggle_chan_scanlist(void)
{ // toggle the selected channels scanlist setting
if ( SCANNER_IsScanning())
if (SCANNER_IsScanning())
return;
if(!IS_MR_CHANNEL(gTxVfo->CHANNEL_SAVE)) {
@@ -55,20 +55,11 @@ void toggle_chan_scanlist(void)
#endif
return;
}
if (gTxVfo->SCANLIST1_PARTICIPATION)
{
if (gTxVfo->SCANLIST2_PARTICIPATION)
gTxVfo->SCANLIST1_PARTICIPATION = 0;
else
gTxVfo->SCANLIST2_PARTICIPATION = 1;
}
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);
@@ -79,7 +70,6 @@ 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)
@@ -113,66 +103,63 @@ 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 && !gCssBackgroundScan)
{
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;
}
}
else
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
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 = Band;
gTxVfo->Band += 1;
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;
@@ -332,8 +319,6 @@ static void MAIN_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
if (IS_MR_CHANNEL(gTxVfo->CHANNEL_SAVE))
{ // user is entering channel number
uint16_t Channel;
if (gInputBoxIndex != 3)
{
#ifdef ENABLE_VOICE
@@ -345,7 +330,7 @@ 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))
{
@@ -371,19 +356,17 @@ 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;
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
bool isGigaF = gTxVfo->pRX->Frequency >= _1GHz_in_KHz;
if (gInputBoxIndex < 6 + isGigaF)
{
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
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)
@@ -397,51 +380,42 @@ static void MAIN_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
Frequency = (Frequency < center) ? BX4819_band1.upper : BX4819_band2.lower;
}
else
if (Frequency > frequencyBandTable[ARRAY_SIZE(frequencyBandTable) - 1].upper)
if (Frequency > frequencyBandTable[BAND_N_ELEM - 1].upper)
{
Frequency = frequencyBandTable[ARRAY_SIZE(frequencyBandTable) - 1].upper;
Frequency = frequencyBandTable[BAND_N_ELEM - 1].upper;
}
const FREQUENCY_Band_t band = FREQUENCY_GetBand(Frequency);
if (gTxVfo->Band != band)
{
const FREQUENCY_Band_t band = FREQUENCY_GetBand(Frequency);
gTxVfo->Band = band;
gEeprom.ScreenChannel[Vfo] = band + FREQ_CHANNEL_FIRST;
gEeprom.FreqChannel[Vfo] = band + FREQ_CHANNEL_FIRST;
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
SETTINGS_SaveVfoIndices();
if (gTxVfo->Band != band)
{
gTxVfo->Band = band;
gEeprom.ScreenChannel[Vfo] = band + FREQ_CHANNEL_FIRST;
gEeprom.FreqChannel[Vfo] = band + FREQ_CHANNEL_FIRST;
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)
{
#ifdef ENABLE_VOICE
@@ -453,7 +427,7 @@ static void MAIN_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
gInputBoxIndex = 0;
Channel = (gInputBox[0] * 10) + gInputBox[1];
uint8_t Channel = (gInputBox[0] * 10) + gInputBox[1];
if (Channel >= 1 && Channel <= ARRAY_SIZE(NoaaFrequencyTable))
{
Channel += NOAA_CHANNEL_FIRST;
@@ -583,7 +557,7 @@ static void MAIN_Key_MENU(const bool bKeyPressed, const bool bKeyHeld)
if (!bKeyPressed && !gDTMF_InputMode)
{ // menu key released
const bool bFlag = (gInputBoxIndex == 0);
const bool bFlag = !gInputBoxIndex;
gInputBoxIndex = 0;
if (bFlag)
@@ -631,8 +605,6 @@ static void MAIN_Key_STAR(bool bKeyPressed, bool bKeyHeld)
if (bKeyPressed) // just pressed
{
// gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
gBeepToPlay = BEEP_880HZ_40MS_OPTIONAL;
return;
}
@@ -640,14 +612,16 @@ 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
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
memmove(gDTMF_InputBox, gDTMF_String, MIN(sizeof(gDTMF_InputBox), sizeof(gDTMF_String) - 1));
gDTMF_InputBox_Index = 0;
gDTMF_InputMode = true;
@@ -656,6 +630,8 @@ 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
@@ -676,7 +652,6 @@ static void MAIN_Key_STAR(bool bKeyPressed, bool bKeyHeld)
}
gPttWasReleased = true;
gUpdateStatus = true;
}

View File

@@ -40,7 +40,6 @@
#endif
#include "ui/inputbox.h"
#include "ui/menu.h"
#include "ui/menu.h"
#include "ui/ui.h"
#ifndef ARRAY_SIZE
@@ -123,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:
@@ -198,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:
@@ -224,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
@@ -382,7 +374,6 @@ void MENU_AcceptSetting(void)
{
int32_t Min;
int32_t Max;
uint8_t Code;
FREQ_Config_t *pConfig = &gTxVfo->freq_config_RX;
if (!MENU_GetLimits(UI_MENU_GetCurrentMenuId(), &Min, &Max))
@@ -421,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;
@@ -521,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:
@@ -546,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;
@@ -630,7 +597,7 @@ void MENU_AcceptSetting(void)
case MENU_MIC:
gEeprom.MIC_SENSITIVITY = gSubMenuSelection;
BOARD_EEPROM_LoadCalibration();
SETTINGS_LoadCalibration();
gFlagReconfigureVfos = true;
break;
@@ -740,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;
@@ -762,7 +721,7 @@ void MENU_AcceptSetting(void)
return;
case MENU_RESET:
BOARD_FactoryReset(gSubMenuSelection);
SETTINGS_FactoryReset(gSubMenuSelection);
return;
case MENU_350TX:
@@ -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;
@@ -1474,7 +1426,7 @@ static void MENU_Key_MENU(const bool bKeyPressed, const bool bKeyHeld)
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);

View File

@@ -15,18 +15,21 @@
*/
#include "app/spectrum.h"
#include "driver/backlight.h"
#include "am_fix.h"
#include "audio.h"
#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;
@@ -42,6 +45,7 @@ bool redrawScreen = false;
bool newScanStart = true;
bool preventKeypress = true;
bool audioState = true;
bool lockAGC = false;
State currentState = SPECTRUM, previousState = SPECTRUM;
@@ -53,22 +57,22 @@ 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];
@@ -99,17 +103,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;
@@ -276,7 +291,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) {
@@ -294,6 +314,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);
@@ -381,21 +402,21 @@ static void Measure() { rssiHistory[scanInfo.i] = scanInfo.rssi = GetRssi(); }
// 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();
@@ -475,6 +496,8 @@ static void ToggleModulation() {
settings.modulationType = MODULATION_FM;
}
RADIO_SetModulation(settings.modulationType);
RelaunchScan();
redrawScreen = true;
}
@@ -534,8 +557,8 @@ static void UpdateFreqInput(KEY_Code_t key) {
}
if (key == KEY_EXIT) {
freqInputIndex--;
if(freqInputDotIndex==freqInputIndex)
freqInputDotIndex = 0;
if (freqInputDotIndex == freqInputIndex)
freqInputDotIndex = 0;
} else {
freqInputArr[freqInputIndex++] = key;
}
@@ -549,7 +572,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] = '-';
}
@@ -557,14 +580,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;
}
}
@@ -588,7 +611,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;
}
@@ -615,11 +638,12 @@ static void DrawStatus() {
#endif
GUI_DisplaySmallest(String, 0, 1, true, true);
BOARD_ADC_GetBatteryInfo(&gBatteryVoltages[gBatteryCheckCounter++ % 4], &gBatteryCurrent);
BOARD_ADC_GetBatteryInfo(&gBatteryVoltages[gBatteryCheckCounter++ % 4],
&gBatteryCurrent);
uint16_t voltage = (gBatteryVoltages[0] + gBatteryVoltages[1] + gBatteryVoltages[2] +
gBatteryVoltages[3]) /
4 * 760 / gBatteryCalibration[3];
uint16_t voltage = (gBatteryVoltages[0] + gBatteryVoltages[1] +
gBatteryVoltages[2] + gBatteryVoltages[3]) /
4 * 760 / gBatteryCalibration[3];
unsigned perc = BATTERY_VoltsToPercent(voltage);
@@ -631,9 +655,9 @@ static void DrawStatus() {
for (int i = 118; i <= 126; i++) {
gStatusLine[i] = 0b00100010;
}
for (unsigned i = 127; i >= 118; i--) {
if (127 - i <= (perc+5)*9/100) {
if (127 - i <= (perc + 5) * 9 / 100) {
gStatusLine[i] = 0b00111110;
}
}
@@ -886,6 +910,7 @@ void OnKeyDownStill(KEY_Code_t key) {
case KEY_EXIT:
if (!menuState) {
SetState(SPECTRUM);
lockAGC = false;
monitorMode = false;
RelaunchScan();
break;
@@ -897,9 +922,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));
@@ -921,14 +944,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);
@@ -999,13 +1022,12 @@ bool HandleUserInput() {
kbd.current = GetKey();
if (kbd.current != KEY_INVALID && kbd.current == kbd.prev) {
if(kbd.counter < 16)
if (kbd.counter < 16)
kbd.counter++;
else
kbd.counter-=3;
kbd.counter -= 3;
SYSTEM_DelayMs(20);
}
else {
} else {
kbd.counter = 0;
}
@@ -1104,6 +1126,15 @@ static void UpdateListening() {
}
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
if (!preventKeypress) {
HandleUserInput();
}
@@ -1133,8 +1164,10 @@ 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
currentFreq = initialFreq = gEeprom.VfoInfo[vfo].pRX->Frequency -
((GetStepsCount() / 2) * GetScanStep());
BackupRegisters();
@@ -1144,14 +1177,13 @@ void APP_RunSpectrum() {
newScanStart = true;
ToggleRX(true), ToggleRX(false); // hack to prevent noise when squelch off
RADIO_SetModulation(settings.modulationType = MODULATION_FM);
RADIO_SetModulation(settings.modulationType = gRxVfo->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"

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;
@@ -552,7 +560,7 @@ void UART_HandleCommand(void)
CMD_052F(UART_Command.Buffer);
break;
case 0x05DD:
case 0x05DD: // reset
#if defined(ENABLE_OVERLAY)
overlay_FLASH_RebootToBootloader();
#else

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;
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

115
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,

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];

401
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)
@@ -504,397 +493,11 @@ void BOARD_Init(void)
BOARD_GPIO_Init();
BACKLIGHT_InitHardware();
BOARD_ADC_Init();
ST7565_Init(true);
ST7565_Init();
#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;
#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
{ // 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();
#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;
// 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;
#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] : (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, 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");
}
#endif
// 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] < 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)) ? 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));
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 (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

@@ -2,8 +2,10 @@
#define DEBUGGING_H
#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)
@@ -11,8 +13,23 @@ static inline void LogUart(char * str)
UART_Send(str, strlen(str));
}
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

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,42 +54,30 @@ 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)) * 10;
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)) * 120;
break;
case 7: // always on
gBacklightCountdown = 0;
gBacklightCountdown_500ms = 0;
break;
}
gBacklightCountdown *= 2;
}
void BACKLIGHT_TurnOff()
@@ -106,7 +94,7 @@ void BACKLIGHT_TurnOff()
#else
BACKLIGHT_SetBrightness(gEeprom.BACKLIGHT_MIN);
#endif
gBacklightCountdown = 0;
gBacklightCountdown_500ms = 0;
backlightOn = false;
}

View File

@@ -20,7 +20,7 @@
#include <stdint.h>
#include <stdbool.h>
extern uint16_t gBacklightCountdown;
extern uint16_t gBacklightCountdown_500ms;
extern uint8_t gBacklightBrightness;
#ifdef ENABLE_BLMIN_TMP_OFF
@@ -38,4 +38,3 @@ bool BACKLIGHT_IsOn();
void BACKLIGHT_SetBrightness(uint8_t brigtness);
#endif

View File

@@ -41,10 +41,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 +77,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 +111,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,
};

View File

@@ -55,8 +55,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
@@ -236,19 +236,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
// <9:8> LNA Gain Short
// 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
@@ -276,74 +303,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)
@@ -699,7 +712,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));
@@ -828,16 +841,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)
@@ -1130,11 +1145,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)

View File

@@ -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);
@@ -136,6 +136,8 @@ void BK4819_EnableCDCSS(void);
void BK4819_EnableCTCSS(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);

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

@@ -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,46 @@ 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
};
// 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_15kHz] = 1500,
[STEP_30kHz] = 3000,
[STEP_50kHz] = 5000,
[STEP_100kHz] = 10000,
[STEP_125kHz] = 12500,
[STEP_250kHz] = 25000,
[STEP_500kHz] = 50000
};
const uint8_t StepSortedIndexes[] = {
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_10kHz, STEP_12_5kHz, STEP_15kHz, STEP_25kHz, STEP_30kHz, STEP_50kHz, STEP_100kHz,
STEP_125kHz, STEP_250kHz, STEP_500kHz
};
uint8_t FREQUENCY_GetStepIdxFromSortedIdx(uint8_t sortedIdx)
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 +109,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)
@@ -124,17 +148,20 @@ uint32_t FREQUENCY_RoundToStep(uint32_t freq, uint16_t step)
int chno = (freq - base) / 700; // convert entered aviation 8.33Khz channel number scheme to actual frequency.
return base + (chno * 833) + (chno == 3);
}
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
@@ -196,7 +223,7 @@ int TX_freq_check(const uint32_t Frequency)
break;
case F_LOCK_NONE:
for (uint8_t i = 0; i < ARRAY_SIZE(frequencyBandTable); i++)
for (uint32_t i = 0; i < ARRAY_SIZE(frequencyBandTable); i++)
if (Frequency >= frequencyBandTable[i].lower && Frequency < frequencyBandTable[i].upper)
return 0;
break;
@@ -206,11 +233,11 @@ int TX_freq_check(const uint32_t 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,21 +29,22 @@ 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 {
// standard steps
STEP_2_5kHz,
STEP_5kHz,
STEP_6_25kHz,
@@ -49,6 +52,7 @@ typedef enum {
STEP_12_5kHz,
STEP_25kHz,
STEP_8_33kHz,
// custom steps
STEP_0_01kHz,
STEP_0_05kHz,
STEP_0_1kHz,
@@ -63,10 +67,11 @@ typedef enum {
STEP_125kHz,
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 +81,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,6 +42,14 @@
FUNCTION_Type_t gCurrentFunction;
inline bool FUNCTION_IsRx()
{
return gCurrentFunction == FUNCTION_MONITOR ||
gCurrentFunction == FUNCTION_INCOMING ||
gCurrentFunction == FUNCTION_RECEIVE;
}
void FUNCTION_Init(void)
{
#ifdef ENABLE_NOAA
@@ -84,10 +92,150 @@ void FUNCTION_Init(void)
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;
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_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;
@@ -101,155 +249,23 @@ void FUNCTION_Select(FUNCTION_Type_t Function)
switch (Function)
{
case FUNCTION_FOREGROUND:
#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)
break;
#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;
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();
#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;
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:
break;
}
@@ -257,7 +273,7 @@ void FUNCTION_Select(FUNCTION_Type_t Function)
gBatterySaveCountdown_10ms = battery_save_count_10ms;
gSchedulePowerSave = false;
#if defined(ENABLE_FMRADIO)
gFM_RestoreCountdown_10ms = 0;
#endif
#if defined(ENABLE_FMRADIO)
gFM_RestoreCountdown_10ms = 0;
#endif
}

View File

@@ -36,6 +36,6 @@ extern FUNCTION_Type_t gCurrentFunction;
void FUNCTION_Init(void);
void FUNCTION_Select(FUNCTION_Type_t Function);
bool FUNCTION_IsRx();
#endif

6
main.c
View File

@@ -83,9 +83,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);

19
misc.c
View File

@@ -89,14 +89,12 @@ bool gSetting_350EN;
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
@@ -162,7 +160,6 @@ bool gCssBackgroundScan;
volatile bool gScheduleScanListen = true;
volatile uint16_t gScanPauseDelayIn_10ms;
bool gUpdateRSSI;
#if defined(ENABLE_ALARM) || defined(ENABLE_TX1750)
AlarmState_t gAlarmState;
#endif
@@ -201,8 +198,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;
@@ -218,9 +216,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
@@ -252,11 +247,11 @@ volatile bool gFlagTailNoteEliminationComplete;
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)
{
@@ -281,4 +276,4 @@ unsigned long StrToUL(const char * str)
ul = ul * 10 + (uint8_t)(c-'0');
}
return ul;
}
}

28
misc.h
View File

@@ -47,13 +47,6 @@ enum {
LAST_CHANNEL
};
enum {
FLASHLIGHT_OFF = 0,
FLASHLIGHT_ON,
FLASHLIGHT_BLINK,
FLASHLIGHT_SOS
};
enum {
VFO_CONFIGURE_NONE = 0,
VFO_CONFIGURE,
@@ -63,7 +56,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;
@@ -153,14 +146,12 @@ extern bool gSetting_350EN;
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
@@ -249,7 +240,6 @@ enum
extern volatile bool gScheduleScanListen;
extern volatile uint16_t gScanPauseDelayIn_10ms;
extern bool gUpdateRSSI;
extern AlarmState_t gAlarmState;
extern uint16_t gMenuCountdown;
extern bool gPttWasReleased;
@@ -288,8 +278,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;
@@ -304,9 +295,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;
@@ -334,12 +322,14 @@ 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

214
radio.c
View File

@@ -16,6 +16,7 @@
#include <string.h>
#include "am_fix.h"
#include "app/dtmf.h"
#ifdef ENABLE_FMRADIO
#include "app/fm.h"
@@ -41,18 +42,19 @@ VFO_Info_t *gCurrentVfo;
DCS_CodeType_t gCurrentCodeType;
VfoState_t VfoState[2];
const char gModulationStr[][4] =
{
"FM",
"AM",
"USB",
const char gModulationStr[MODULATION_UKNOWN][4] = {
[MODULATION_FM]="FM",
[MODULATION_AM]="AM",
[MODULATION_USB]="USB",
#ifdef ENABLE_BYP_RAW_DEMODULATORS
"BYP",
"RAW"
[MODULATION_BYP]="BYP",
[MODULATION_RAW]="RAW"
#endif
};
bool RADIO_CheckValidChannel(uint16_t Channel, bool bCheckScanList, uint8_t VFO)
{ // return true if the channel appears valid
@@ -143,7 +145,7 @@ void RADIO_InitInfo(VFO_Info_t *pInfo, const uint8_t ChannelSave, const uint32_t
pInfo->Modulation = MODULATION_AM;
else
pInfo->Modulation = MODULATION_FM;
RADIO_ConfigureSquelchAndOutputPower(pInfo);
}
@@ -247,11 +249,11 @@ void RADIO_ConfigureChannel(const unsigned int VFO, const unsigned int configure
pVfo->TX_OFFSET_FREQUENCY_DIRECTION = tmp;
tmp = data[3] >> 4;
if (tmp >= MODULATION_UKNOWN)
tmp = MODULATION_FM;
tmp = MODULATION_FM;
pVfo->Modulation = tmp;
tmp = data[6];
if (tmp >= ARRAY_SIZE(gStepFrequencyTable))
if (tmp >= STEP_N_ELEM)
tmp = STEP_12_5kHz;
pVfo->STEP_SETTING = tmp;
pVfo->StepFrequency = gStepFrequencyTable[tmp];
@@ -351,8 +353,9 @@ void RADIO_ConfigureChannel(const unsigned int VFO, const unsigned int configure
else
pVfo->freq_config_RX.Frequency = info.Frequency;
if (info.Offset >= 100000000)
info.Offset = 1000000;
if (info.Offset >= _1GHz_in_KHz)
info.Offset = _1GHz_in_KHz / 100;
pVfo->TX_OFFSET_FREQUENCY = info.Offset;
// ***************
@@ -379,11 +382,9 @@ void RADIO_ConfigureChannel(const unsigned int VFO, const unsigned int configure
RADIO_ApplyOffset(pVfo);
memset(pVfo->Name, 0, sizeof(pVfo->Name));
if (IS_MR_CHANNEL(channel))
{ // 16 bytes allocated to the channel name but only 10 used, the rest are 0's
EEPROM_ReadBuffer(0x0F50 + (channel * 16), pVfo->Name + 0, 8);
EEPROM_ReadBuffer(0x0F58 + (channel * 16), pVfo->Name + 8, 2);
SETTINGS_FetchChannelName(pVfo->Name, channel);
}
if (!pVfo->FrequencyReverse)
@@ -404,14 +405,6 @@ void RADIO_ConfigureChannel(const unsigned int VFO, const unsigned int configure
pConfig->Frequency = 43300000;
}
if (pVfo->Modulation != MODULATION_FM)
{ // freq/chan is in AM mode
pVfo->SCRAMBLING_TYPE = 0;
// pVfo->DTMF_DECODING_ENABLE = false; // no reason to disable DTMF decoding, aircraft use it on SSB
pVfo->freq_config_RX.CodeType = CODE_TYPE_OFF;
pVfo->freq_config_TX.CodeType = CODE_TYPE_OFF;
}
pVfo->Compander = att.compander;
RADIO_ConfigureSquelchAndOutputPower(pVfo);
@@ -419,13 +412,12 @@ void RADIO_ConfigureChannel(const unsigned int VFO, const unsigned int configure
void RADIO_ConfigureSquelchAndOutputPower(VFO_Info_t *pInfo)
{
uint8_t Txp[3];
FREQUENCY_Band_t Band;
// *******************************
// squelch
Band = FREQUENCY_GetBand(pInfo->pRX->Frequency);
FREQUENCY_Band_t Band = FREQUENCY_GetBand(pInfo->pRX->Frequency);
uint16_t Base = (Band < BAND4_174MHz) ? 0x1E60 : 0x1E00;
if (gEeprom.SQUELCH_LEVEL == 0)
@@ -505,12 +497,12 @@ void RADIO_ConfigureSquelchAndOutputPower(VFO_Info_t *pInfo)
// *******************************
// output power
Band = FREQUENCY_GetBand(pInfo->pTX->Frequency);
uint8_t Txp[3];
EEPROM_ReadBuffer(0x1ED0 + (Band * 16) + (pInfo->OUTPUT_POWER * 3), Txp, 3);
#ifdef ENABLE_REDUCE_LOW_MID_TX_POWER
// make low and mid even lower
if (pInfo->OUTPUT_POWER == OUTPUT_POWER_LOW) {
@@ -555,16 +547,15 @@ void RADIO_ApplyOffset(VFO_Info_t *pInfo)
if (Frequency < frequencyBandTable[0].lower)
Frequency = frequencyBandTable[0].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;
pInfo->freq_config_TX.Frequency = Frequency;
}
static void RADIO_SelectCurrentVfo(void)
{
// if crossband is active and DW not the gCurrentVfo is gTxVfo (gTxVfo/TX_VFO is only ever changed by the user)
// if crossband is active and DW not the gCurrentVfo is gTxVfo (gTxVfo/TX_VFO is only ever changed by the user)
// otherwise it is set to gRxVfo which is set to gTxVfo in RADIO_SelectVfos
// so in the end gCurrentVfo is equal to gTxVfo unless dual watch changes it on incomming transmition (again, this can only happen when XB off)
// note: it is called only in certain situations so could be not up-to-date
@@ -585,8 +576,6 @@ void RADIO_SelectVfos(void)
void RADIO_SetupRegisters(bool switchToForeground)
{
BK4819_FilterBandwidth_t Bandwidth = gRxVfo->CHANNEL_BANDWIDTH;
uint16_t InterruptMask;
uint32_t Frequency;
AUDIO_AudioPathOff();
@@ -630,6 +619,7 @@ void RADIO_SetupRegisters(bool switchToForeground)
// mic gain 0.5dB/step 0 to 31
BK4819_WriteRegister(BK4819_REG_7D, 0xE940 | (gEeprom.MIC_SENSITIVITY_TUNING & 0x1f));
uint32_t Frequency;
#ifdef ENABLE_NOAA
if (!IS_NOAA_CHANNEL(gRxVfo->CHANNEL_SAVE) || !gIsNoaaMode)
Frequency = gRxVfo->pRX->Frequency;
@@ -659,7 +649,7 @@ void RADIO_SetupRegisters(bool switchToForeground)
(gEeprom.DAC_GAIN << 0)); // AF DAC Gain (after Gain-1 and Gain-2)
InterruptMask = BK4819_REG_3F_SQUELCH_FOUND | BK4819_REG_3F_SQUELCH_LOST;
uint16_t InterruptMask = BK4819_REG_3F_SQUELCH_FOUND | BK4819_REG_3F_SQUELCH_LOST;
#ifdef ENABLE_NOAA
if (!IS_NOAA_CHANNEL(gRxVfo->CHANNEL_SAVE))
@@ -781,6 +771,8 @@ void RADIO_SetupRegisters(bool switchToForeground)
}
#endif
RADIO_SetupAGC(gRxVfo->Modulation == MODULATION_AM, false);
// enable/disable BK4819 selected interrupts
BK4819_WriteRegister(BK4819_REG_3F, InterruptMask);
@@ -924,38 +916,61 @@ void RADIO_SetModulation(ModulationMode_t modulation)
}
BK4819_SetAF(mod);
BK4819_SetRegValue(afDacGainRegSpec, 0xF);
BK4819_WriteRegister(BK4819_REG_3D, modulation == MODULATION_USB ? 0 : 0x2AAB);
BK4819_SetRegValue(afcDisableRegSpec, modulation != MODULATION_FM);
RADIO_SetupAGC(modulation == MODULATION_AM, false);
}
void RADIO_SetupAGC(bool listeningAM, bool disable)
{
static uint8_t lastSettings;
uint8_t newSettings = (listeningAM << 1) | (disable << 1);
if(lastSettings == newSettings)
return;
lastSettings = newSettings;
if(!listeningAM) { // if not actively listening AM we don't need any AM specific regulation
BK4819_SetAGC(!disable);
BK4819_InitAGC(false);
}
else {
#ifdef ENABLE_AM_FIX
if(gSetting_AM_fix) { // if AM fix active lock AGC so AM-fix can do it's job
BK4819_SetAGC(0);
AM_fix_enable(!disable);
}
else
#endif
{
BK4819_SetAGC(!disable);
BK4819_InitAGC(true);
}
}
}
void RADIO_SetVfoState(VfoState_t State)
{
if (State == VFO_STATE_NORMAL)
{
if (State == VFO_STATE_NORMAL) {
VfoState[0] = VFO_STATE_NORMAL;
VfoState[1] = VFO_STATE_NORMAL;
gVFOStateResumeCountdown_500ms = 0;
}
else
{
if (State == VFO_STATE_VOLTAGE_HIGH)
{
VfoState[0] = VFO_STATE_VOLTAGE_HIGH;
VfoState[1] = VFO_STATE_TX_DISABLE;
}
else
{ // 1of11
const unsigned int vfo = (gEeprom.CROSS_BAND_RX_TX == CROSS_BAND_OFF) ? gEeprom.RX_VFO : gEeprom.TX_VFO;
VfoState[vfo] = State;
}
gVFOStateResumeCountdown_500ms = vfo_state_resume_countdown_500ms;
} else if (State == VFO_STATE_VOLTAGE_HIGH) {
VfoState[0] = VFO_STATE_VOLTAGE_HIGH;
VfoState[1] = VFO_STATE_TX_DISABLE;
} else {
// 1of11
const unsigned int vfo = (gEeprom.CROSS_BAND_RX_TX == CROSS_BAND_OFF) ? gEeprom.RX_VFO : gEeprom.TX_VFO;
VfoState[vfo] = State;
}
gVFOStateResumeCountdown_500ms = (State == VFO_STATE_NORMAL) ? 0 : vfo_state_resume_countdown_500ms;
gUpdateDisplay = true;
}
void RADIO_PrepareTX(void)
{
VfoState_t State = VFO_STATE_NORMAL; // default to OK to TX
@@ -980,52 +995,40 @@ void RADIO_PrepareTX(void)
RADIO_SelectCurrentVfo();
#if defined(ENABLE_ALARM) && defined(ENABLE_TX1750)
if (gAlarmState == ALARM_STATE_OFF ||
gAlarmState == ALARM_STATE_TX1750 ||
(gAlarmState == ALARM_STATE_ALARM && gEeprom.ALARM_MODE == ALARM_MODE_TONE))
#elif defined(ENABLE_ALARM)
if (gAlarmState == ALARM_STATE_OFF ||
(gAlarmState == ALARM_STATE_ALARM && gEeprom.ALARM_MODE == ALARM_MODE_TONE))
#elif defined(ENABLE_TX1750)
if (gAlarmState == ALARM_STATE_OFF ||
gAlarmState == ALARM_STATE_TX1750)
#endif
{
#ifndef ENABLE_TX_WHEN_AM
if (gCurrentVfo->Modulation != MODULATION_FM)
{ // not allowed to TX if in AM mode
State = VFO_STATE_TX_DISABLE;
}
else
#endif
if (gSerialConfigCountDown_500ms > 0)
{ // TX is disabled or config upload/download in progress
State = VFO_STATE_TX_DISABLE;
}
else
if (TX_freq_check(gCurrentVfo->pTX->Frequency) == 0)
{ // TX frequency is allowed
if (gCurrentVfo->BUSY_CHANNEL_LOCK && gCurrentFunction == FUNCTION_RECEIVE)
State = VFO_STATE_BUSY; // busy RX'ing a station
else
if (gBatteryDisplayLevel == 0)
State = VFO_STATE_BAT_LOW; // charge your battery !
else
if (gBatteryDisplayLevel > 6)
State = VFO_STATE_VOLTAGE_HIGH; // over voltage .. this is being a pain
}
else
State = VFO_STATE_TX_DISABLE; // TX frequency not allowed
if(TX_freq_check(gCurrentVfo->pTX->Frequency) != 0
#if defined(ENABLE_ALARM) || defined(ENABLE_TX1750)
&& gAlarmState != ALARM_STATE_SITE_ALARM
#endif
){
// TX frequency not allowed
State = VFO_STATE_TX_DISABLE;
} else if (SerialConfigInProgress()) {
// TX is disabled or config upload/download in progress
State = VFO_STATE_TX_DISABLE;
} else if (gCurrentVfo->BUSY_CHANNEL_LOCK && gCurrentFunction == FUNCTION_RECEIVE) {
// busy RX'ing a station
State = VFO_STATE_BUSY;
} else if (gBatteryDisplayLevel == 0) {
// charge your battery !git co
State = VFO_STATE_BAT_LOW;
} else if (gBatteryDisplayLevel > 6) {
// over voltage .. this is being a pain
State = VFO_STATE_VOLTAGE_HIGH;
}
#ifndef ENABLE_TX_WHEN_AM
else if (gCurrentVfo->Modulation != MODULATION_FM) {
// not allowed to TX if in AM mode
State = VFO_STATE_TX_DISABLE;
}
#endif
if (State != VFO_STATE_NORMAL)
{ // TX not allowed
if (State != VFO_STATE_NORMAL) {
// TX not allowed
RADIO_SetVfoState(State);
#if defined(ENABLE_ALARM) || defined(ENABLE_TX1750)
gAlarmState = ALARM_STATE_OFF;
#endif
#if defined(ENABLE_ALARM) || defined(ENABLE_TX1750)
gAlarmState = ALARM_STATE_OFF;
#endif
#ifdef ENABLE_DTMF_CALLING
gDTMF_ReplyState = DTMF_REPLY_NONE;
@@ -1041,14 +1044,14 @@ void RADIO_PrepareTX(void)
{
if (gDTMF_CallMode == DTMF_CALL_MODE_DTMF)
{
gDTMF_IsTx = true;
gDTMF_CallState = DTMF_CALL_STATE_NONE;
gDTMF_IsTx = true;
gDTMF_CallState = DTMF_CALL_STATE_NONE;
gDTMF_TxStopCountdown_500ms = DTMF_txstop_countdown_500ms;
}
else
{
gDTMF_IsTx = false;
gDTMF_CallState = DTMF_CALL_STATE_CALL_OUT;
gDTMF_IsTx = false;
}
}
#endif
@@ -1058,19 +1061,18 @@ void RADIO_PrepareTX(void)
gTxTimerCountdown_500ms = 0; // no timeout
#if defined(ENABLE_ALARM) || defined(ENABLE_TX1750)
if (gAlarmState == ALARM_STATE_OFF)
if (gAlarmState == ALARM_STATE_OFF)
#endif
{
if (gEeprom.TX_TIMEOUT_TIMER == 0)
gTxTimerCountdown_500ms = 60; // 30 sec
else
if (gEeprom.TX_TIMEOUT_TIMER < (ARRAY_SIZE(gSubMenu_TOT) - 1))
else if (gEeprom.TX_TIMEOUT_TIMER < (ARRAY_SIZE(gSubMenu_TOT) - 1))
gTxTimerCountdown_500ms = 120 * gEeprom.TX_TIMEOUT_TIMER; // minutes
else
gTxTimerCountdown_500ms = 120 * 15; // 15 minutes
}
gTxTimeoutReached = false;
gTxTimeoutReached = false;
gFlagEndTransmission = false;
gRTTECountdown = 0;
@@ -1138,10 +1140,10 @@ void RADIO_SendEndOfTransmission(void)
gEeprom.DTMF_HASH_CODE_PERSIST_TIME,
gEeprom.DTMF_CODE_PERSIST_TIME,
gEeprom.DTMF_CODE_INTERVAL_TIME);
AUDIO_AudioPathOff();
gEnableSpeaker = false;
}
BK4819_ExitDTMF_TX(true);
}
}

View File

@@ -50,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;
@@ -159,6 +160,7 @@ void RADIO_SetupRegisters(bool bSwitchToFunction0);
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);

View File

@@ -16,16 +16,418 @@
#include <string.h>
#include "app/dtmf.h"
#ifdef ENABLE_FMRADIO
#include "app/fm.h"
#endif
#include "driver/bk4819.h"
#include "driver/eeprom.h"
#include "driver/uart.h"
#include "misc.h"
#include "settings.h"
#include "ui/menu.h"
static const uint32_t gDefaultFrequencyTable[] =
{
14500000, //
14550000, //
43300000, //
43320000, //
43350000 //
};
EEPROM_Config_t gEeprom;
void SETTINGS_InitEEPROM(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;
#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
{ // 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();
#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);
memmove(&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
gEeprom.S0_LEVEL = (Data[1] < 0xFF) ? Data[1] : 130;
gEeprom.S9_LEVEL = (Data[2] < gEeprom.S0_LEVEL-9) ? Data[2] : 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] : (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, 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");
}
#endif
// 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] < 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)) ? 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));
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 (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;
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);
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)
{
@@ -126,8 +528,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;
@@ -200,8 +607,7 @@ void SETTINGS_SaveChannel(uint8_t Channel, uint8_t VFO, const VFO_Info_t *pVFO,
if (!IS_NOAA_CHANNEL(Channel))
#endif
{
const uint16_t OffsetMR = Channel * 16;
uint16_t OffsetVFO = OffsetMR;
uint16_t OffsetVFO = Channel * 16;
if (!IS_MR_CHANNEL(Channel))
{ // it's a VFO, not a channel
@@ -212,50 +618,42 @@ void SETTINGS_SaveChannel(uint8_t Channel, uint8_t VFO, const VFO_Info_t *pVFO,
if (Mode >= 2 || !IS_MR_CHANNEL(Channel))
{ // copy VFO to a channel
uint8_t State[8];
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
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[5] = ((pVFO->DTMF_PTT_ID_TX_MODE & 7u) << 1)
State._8[5] = ((pVFO->DTMF_PTT_ID_TX_MODE & 7u) << 1)
#ifdef ENABLE_DTMF_CALLING
| ((pVFO->DTMF_DECODING_ENABLE & 1u) << 0)
#endif
;
State[6] = pVFO->STEP_SETTING;
State[7] = pVFO->SCRAMBLING_TYPE;
EEPROM_WriteBuffer(OffsetVFO + 8, State);
State._8[6] = pVFO->STEP_SETTING;
State._8[7] = pVFO->SCRAMBLING_TYPE;
EEPROM_WriteBuffer(OffsetVFO + 8, State._8);
SETTINGS_UpdateChannel(Channel, pVFO, true);
if (IS_MR_CHANNEL(Channel))
{ // it's a memory channel
if (IS_MR_CHANNEL(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);
SETTINGS_SaveChannelName(Channel, "");
#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);
if (Mode >= 3) {
SETTINGS_SaveChannelName(Channel, pVFO->Name);
}
#endif
}
@@ -273,6 +671,16 @@ void SETTINGS_SaveBatteryCalibration(const uint16_t * batteryCalibration)
EEPROM_WriteBuffer(0x1F48, buf);
}
void SETTINGS_SaveChannelName(uint8_t channel, const char * name)
{
uint16_t offset = channel * 16;
uint8_t buf[16];
memset(&buf, 0x00, sizeof(buf));
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
@@ -305,13 +713,57 @@ void SETTINGS_UpdateChannel(uint8_t channel, const VFO_Info_t *pVFO, bool keep)
gMR_ChannelAttributes[channel] = att;
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, 0x00, sizeof(state));
EEPROM_WriteBuffer(0x0F50 + OffsetMR, state);
EEPROM_WriteBuffer(0x0F58 + OffsetMR, state);
SETTINGS_SaveChannelName(channel, "");
}
}
}
}
void SETTINGS_WriteBuildOptions(void)
{
uint8_t buf[8]= {};
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
;
EEPROM_WriteBuffer(0x1FF0, buf);
}

View File

@@ -33,7 +33,7 @@ enum POWER_OnDisplayMode_t {
};
typedef enum POWER_OnDisplayMode_t POWER_OnDisplayMode_t;
enum {
enum TxLockModes_t {
F_LOCK_DEF, //all default frequencies + configurable
F_LOCK_FCC,
F_LOCK_CE,
@@ -75,7 +75,7 @@ enum {
OUTPUT_POWER_HIGH
};
enum {
enum ACTION_OPT_t {
ACTION_OPT_NONE = 0,
ACTION_OPT_FLASHLIGHT,
ACTION_OPT_POWER,
@@ -89,9 +89,7 @@ enum {
ACTION_OPT_A_B,
ACTION_OPT_VFO_MR,
ACTION_OPT_SWITCH_DEMODUL,
#ifdef ENABLE_BLMIN_TMP_OFF
ACTION_OPT_BLMIN_TMP_OFF, //BackLight Minimum Temporay OFF
#endif
ACTION_OPT_LEN
};
@@ -249,17 +247,28 @@ typedef struct {
#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_WriteBuildOptions(void);
#endif

View File

@@ -52,5 +52,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

@@ -184,10 +184,11 @@ void UI_DisplayFrequency(const char *string, uint8_t X, uint8_t Y, bool center)
void UI_DrawPixelBuffer(uint8_t (*buffer)[128], uint8_t x, uint8_t y, bool black)
{
const uint8_t pattern = 1 << (y % 8);
if(black)
buffer[y/8][x] |= 1 << (y%8);
buffer[y/8][x] |= pattern;
else
buffer[y/8][x] &= ~(1 << (y%8));
buffer[y/8][x] &= ~pattern;
}
static void sort(int16_t *a, int16_t *b)

255
ui/main.c
View File

@@ -37,8 +37,30 @@
#include "ui/main.h"
#include "ui/ui.h"
#include "debugging.h"
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)
@@ -140,73 +162,69 @@ 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,
};
if (gEeprom.KEY_LOCK && gKeypadLocked > 0)
return; // display is in use
if (gEeprom.KEY_LOCK && gKeypadLocked > 0)
return; // display is in use
if (gCurrentFunction == FUNCTION_TRANSMIT ||
gScreenToDisplay != DISPLAY_MAIN
if (gCurrentFunction == FUNCTION_TRANSMIT ||
gScreenToDisplay != DISPLAY_MAIN
#ifdef ENABLE_DTMF_CALLING
|| gDTMF_CallState != DTMF_CALL_STATE_NONE
|| gDTMF_CallState != DTMF_CALL_STATE_NONE
#endif
)
return; // display is in use
)
return; // display is in use
if (now)
memset(p_line, 0, LCD_WIDTH);
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
};
if (now)
memset(p_line, 0, LCD_WIDTH);
const int16_t s0_dBm = -130; // S0 .. base level
const int16_t rssi_dBm = (rssi / 2) - 160 + dBmCorrTable[gRxVfo->Band];
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));
}
UI_PrintStringSmall(str, 2, 0, line);
DrawLevelBar(bar_x, line, s_level + overS9Bars);
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];
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);
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_PrintStringSmall(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]) {
@@ -225,37 +243,74 @@ static void DisplayRSSIBar(const int16_t rssi, const bool now)
if (now)
memset(pLine, 0, 23);
DrawSmallAntennaAndBars(pLine, Level);
if (now)
ST7565_BlitFullScreen();
#endif
if (now)
ST7565_BlitFullScreen();
}
void UI_UpdateRSSI(const int16_t rssi, const int vfo)
#ifdef ENABLE_AGC_SHOW_DATA
static void 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_PrintStringSmall(buf, 2, 0, 3);
if(now)
ST7565_BlitLine(3);
}
#endif
void UI_MAIN_TimeSlice500ms(void)
{
if(gScreenToDisplay==DISPLAY_MAIN) {
#ifdef ENABLE_AGC_SHOW_DATA
PrintAGC(true);
return;
#endif
const bool rx = (gCurrentFunction == FUNCTION_RECEIVE ||
gCurrentFunction == FUNCTION_MONITOR ||
gCurrentFunction == FUNCTION_INCOMING);
if(rx)
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;
@@ -278,13 +333,15 @@ void UI_DisplayMain(void)
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
{
@@ -365,14 +422,14 @@ void UI_DisplayMain(void)
{ // 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;
mode = VFO_MODE_TX;
#ifdef ENABLE_SMALL_BOLD
UI_PrintStringSmallBold("TX", 14, 0, line);
#else
@@ -383,12 +440,8 @@ void UI_DisplayMain(void)
}
else
{ // receiving .. show the RX symbol
mode = 2;
if ((gCurrentFunction == FUNCTION_RECEIVE ||
gCurrentFunction == FUNCTION_MONITOR ||
gCurrentFunction == FUNCTION_INCOMING) &&
gEeprom.RX_VFO == vfo_num)
{
mode = VFO_MODE_RX;
if (FUNCTION_IsRx() && gEeprom.RX_VFO == vfo_num) {
#ifdef ENABLE_SMALL_BOLD
UI_PrintStringSmallBold("RX", 14, 0, line);
#else
@@ -411,7 +464,7 @@ void UI_DisplayMain(void)
{ // 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);
}
@@ -432,10 +485,10 @@ void UI_DisplayMain(void)
// ************
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;
}
@@ -445,14 +498,13 @@ 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) {
@@ -502,7 +554,7 @@ 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);
String[7] = 0;
@@ -526,7 +578,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);
@@ -554,7 +606,7 @@ 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);
String[7] = 0;
@@ -584,7 +636,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)
{
@@ -594,7 +646,7 @@ void UI_DisplayMain(void)
}
}
else
if (mode == 2)
if (mode == VFO_MODE_RX)
{ // RX signal level
#ifndef ENABLE_RSSI_BAR
// bar graph
@@ -615,7 +667,7 @@ void UI_DisplayMain(void)
const ModulationMode_t mod = gEeprom.VfoInfo[vfo_num].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) ? gEeprom.VfoInfo[vfo_num].pTX : gEeprom.VfoInfo[vfo_num].pRX;
const unsigned int code_type = pConfig->CodeType;
const char *code_list[] = {"", "CT", "DCS", "DCR"};
if (code_type < ARRAY_SIZE(code_list))
@@ -671,12 +723,15 @@ void UI_DisplayMain(void)
UI_PrintStringSmall("SCR", LCD_WIDTH + 106, 0, line + 1);
}
#ifdef ENABLE_AGC_SHOW_DATA
center_line = CENTER_LINE_IN_USE;
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) {
@@ -706,7 +761,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

View File

@@ -26,13 +26,20 @@ 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);
#endif

View File

@@ -117,9 +117,6 @@ const t_menu_item MenuList[] =
#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
@@ -309,16 +306,6 @@ const char gSubMenu_RX_TX[][6] =
"TX/RX"
};
#ifdef ENABLE_AM_FIX_TEST1
const char gSubMenu_AM_fix_test1[][8] =
{
"LNA-S 0",
"LNA-S 1",
"LNA-S 2",
"LNA-S 3"
};
#endif
const char gSubMenu_BAT_TXT[][8] =
{
"NONE",
@@ -347,10 +334,12 @@ const char gSubMenu_SCRAMBLER[][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},
@@ -374,8 +363,8 @@ const t_sidefunction SIDEFUNCTIONS[] =
{"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;
@@ -611,13 +600,6 @@ void UI_DisplayMenu(void)
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;
@@ -662,7 +644,7 @@ 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);
}
@@ -680,11 +662,11 @@ 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);
SETTINGS_FetchChannelName(String, gSubMenuSelection);
if (String[0] == 0)
strcpy(String, "--");
UI_PrintString(String, menu_item_x1, menu_item_x2, 2, 8);
@@ -762,11 +744,11 @@ void UI_DisplayMenu(void)
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
@@ -932,7 +914,7 @@ void UI_DisplayMenu(void)
UI_PrintString(String, menu_item_x1, menu_item_x2, 0, 8);
// channel name
BOARD_fetchChannelName(String, gSubMenuSelection);
SETTINGS_FetchChannelName(String, gSubMenuSelection);
if (String[0] == 0)
strcpy(String, "--");
UI_PrintString(String, menu_item_x1, menu_item_x2, 2, 8);
@@ -943,7 +925,7 @@ void UI_DisplayMenu(void)
UI_PrintString(String, menu_item_x1, menu_item_x2, 0, 8);
// channel name
BOARD_fetchChannelName(String, gSubMenuSelection);
SETTINGS_FetchChannelName(String, gSubMenuSelection);
if (String[0] == 0)
strcpy(String, "--");
UI_PrintStringSmall(String, menu_item_x1, menu_item_x2, 2);
@@ -967,7 +949,7 @@ void UI_DisplayMenu(void)
UI_MENU_GetCurrentMenuId() == MENU_1_CALL)
{ // display the channel name
char s[11];
BOARD_fetchChannelName(s, gSubMenuSelection);
SETTINGS_FetchChannelName(s, gSubMenuSelection);
if (s[0] == 0)
strcpy(s, "--");
UI_PrintString(s, menu_item_x1, menu_item_x2, 2, 8);
@@ -975,15 +957,6 @@ void UI_DisplayMenu(void)
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 (UI_MENU_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 (UI_MENU_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);
#ifdef ENABLE_DTMF_CALLING
if (UI_MENU_GetCurrentMenuId() == MENU_D_LIST && gIsDtmfContactValid)

View File

@@ -104,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
@@ -158,16 +155,13 @@ extern const char gSubMenu_RESET[2][4];
extern const char* 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;

View File

@@ -36,172 +36,139 @@
void UI_DisplayStatus()
{
uint8_t *line = gStatusLine;
unsigned int x = 0;
unsigned int x1 = 0;
gUpdateStatus = false;
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
#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)
{
if (gSetting_KILLED) {
memset(line + x, 0xFF, 10);
x1 = x + 10;
}
else
#endif
{
// SCAN indicator
if (gScanStateDir != SCAN_OFF || SCANNER_IsScanning())
{
#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) && !SCANNER_IsScanning())
{ // 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;
UI_PrintStringSmallBuffer(s, line + x + 1);
x1 = x + 10;
}
}
x += 7; // font character width
x += 10; // 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
#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
x++;
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)
memmove(line + x, BITMAP_TDR1, sizeof(BITMAP_TDR1) - (dw==1?0:5));
memcpy(line + x + (dw==1?0:2), BITMAP_TDR1, sizeof(BITMAP_TDR1) - (dw==1?0:5));
else
memmove(line + x + 3, BITMAP_TDR2, sizeof(BITMAP_TDR2));
memcpy(line + x + 3, BITMAP_TDR2, sizeof(BITMAP_TDR2));
}
else if(dw == 2) { // XB - crossband
memmove(line + x, BITMAP_XB, sizeof(BITMAP_XB));
memcpy(line + x + 2, BITMAP_XB, sizeof(BITMAP_XB));
}
}
x += sizeof(BITMAP_TDR1) + 2;
x += sizeof(BITMAP_TDR1) + 1;
#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
#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(x, 61u);
x1 = x;
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_PrintStringSmallBuffer(s, line + x2 - space_needed);
}
// move to right side of the screen
@@ -209,7 +176,7 @@ void UI_DisplayStatus()
// 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

49
ui/ui.c
View File

@@ -14,6 +14,7 @@
* limitations under the License.
*/
#include <assert.h>
#include <string.h>
#include "app/chFrScanner.h"
@@ -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]();
}
}

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