UA1ZBE Custom Firmware v1.0

Features:
- VFO mode with direct frequency input
- POCSAG decoder (512/1200 baud) with BCH(31,21) correction
- Full-screen Spectrum analyzer
- FM Radio receiver
- RSSI signal indicator overlay
- Custom boot splash (UA1ZBE / POCSAG pager / build date)

Architecture:
- app/mode.c — mode dispatcher (VFO/POCSAG/Spectrum/FM)
- app/boot_splash.c — 2-second boot splash
- app/pocsag/ — POCSAG decoder + BCH correction
- app/display_rssi.c — RSSI indicator
- main.c — entry point with custom init
- syscalls.c — bare-metal _sbrk stub

Build: arm-none-eabi-gcc -Os -flto -Wall -Werror -Wextra
Size: 57.9KB Flash / 3.6KB RAM

Controls:
- 0-9: Direct frequency input (VFO)
- SK2: POCSAG mode
- SK1: Spectrum analyzer
- 0: FM Radio
- EXIT: Return to VFO
- F/*: Toggle 512/1200 baud (in POCSAG)
This commit is contained in:
2026-04-12 00:44:05 +03:00
parent 5c1229659b
commit a1206d6fd4
3435 changed files with 593221 additions and 2 deletions

11
.gitignore vendored Normal file
View File

@@ -0,0 +1,11 @@
*.d
*.o
firmware
/firmware.packed.bin
/firmware.bin
/compiled-firmware
.cache
compile_commands.json
.vscode
/docs
k5_eeprom.raw

302
DOCUMENTATION.md Normal file
View File

@@ -0,0 +1,302 @@
# UA1ZBE Custom Firmware — Полная документация
## 1. Обзор архитектуры
Прошивка заменяет стандартное меню и создаёт три режима: VFO, POCSAG, Spectrum + FM.
### Точка входа: `main.c`
```
Main()
├── SYSTICK_Init(), BOARD_Init()
├── BK4819_Init()
├── SETTINGS_InitEEPROM()
├── RADIO_ConfigureChannel()
├── BOOT_SplashShow() ← 2 сек заставка
├── RSSI_Init()
├── MODE_Init() ← VFO режим по умолчанию
└── while(1):
├── APP_Update()
├── if (gNextTimeslice):
│ ├── RSSI_Update()
│ └── MODE_TimeSlice10ms()
└── if (gNextTimeslice_500ms):
└── MODE_TimeSlice500ms()
```
### Диспетчер режимов: `app/mode.c`
```
MODE_TimeSlice10ms()
├── MODE_VFO:
│ └── APP_TimeSlice10ms() ← оригинальный VFO цикл
│ └── RSSI_Draw() ← overlay индикатор
├── MODE_POCSAG:
│ └── POCSAG_FeedSample() × 80 ← аудио сэмплинг
│ └── POCSAG_Process()
│ └── pocsag_draw()
├── MODE_SPECTRUM:
│ └── MODE_Switch(MODE_VFO) ← после возврата из spectrum
└── MODE_FM:
└── FM_Play()
```
---
## 2. Все ошибки при создании и их исправления
### Ошибка 1: `static_assert` не работает в C99
```
error: expected declaration specifiers or '...' before '(' token
static_assert(ARRAY_SIZE(ProcessKeysFunctions) == DISPLAY_N_ELEM);
```
**Причина:** `static_assert` — C11 feature. В `-std=c99` недоступен.
**Исправление:** Заменил `-std=c99` на `-std=gnu11` в Makefile.
---
### Ошибка 2: `[[fallthrough]]` не поддерживается GCC 9
```
error: expected expression before '[' token
[[fallthrough]];
```
**Причина:** Атрибут `[[fallthrough]]` — синтаксис C23. GCC 9.2.1 не понимает.
**Исправление:**
```bash
sed -i 's/\[\[fallthrough\]\]/__attribute__((fallthrough))/g' \
radio.c audio.c app/menu.c app/dtmf.c app/chFrScanner.c
```
---
### Ошибка 3: `SYSTICK_GetTickCounter()` не существует
**Причина:** В egzumer нет этой функции.
**Исправление:** В `pocsag.c` использован собственный статический счётчик `s_tick_counter`, инкрементируемый при каждом вызове `POCSAG_FeedSample()`.
---
### Ошибка 4: Сравнение `uint8_t >= 576` — всегда false
```
error: comparison is always false due to limited range of data type
if (s_preamble_alt_count >= POCSAG_PREAMBLE_MIN_BITS)
```
**Причина:** `s_preamble_alt_count` был `uint8_t` (макс 255), а `POCSAG_PREAMBLE_MIN_BITS` = 576.
**Исправление:**
```c
static uint16_t s_preamble_alt_count; // было uint8_t
```
---
### Ошибка 5: `dBmCorrTable` undeclared
```
error: 'dBmCorrTable' undeclared (first use in this function)
```
**Причина:** Таблица в `ui/main.c`, но нет extern в заголовке.
**Исправление:** Добавил в `display_rssi.c`:
```c
extern const int8_t dBmCorrTable[7];
```
---
### Ошибка 6: `display_rssi.h` не найден
```
fatal error: display_rssi.h: No such file or directory
```
**Исправление:** Заменил `#include "display_rssi.h"` на `#include "app/display_rssi.h"` везде.
---
### Ошибка 7: `sizeof` к неполному типу
```
error: invalid application of 'sizeof' to incomplete type 'char[]'
```
**Исправление:** Добавил `#include "app/dtmf.h"` в `main.c` — там полное объявление `extern char gDTMF_String[15]`.
---
### Ошибка 8: 40+ undefined reference
```
undefined reference to `gScreenToDisplay'
undefined reference to `GUI_SelectNextDisplay'
undefined reference to `GENERIC_Key_F', `ACTION_Scan'...
```
**Причина:** Исключил модули, но `app/app.c` и `app/main.c` их используют.
**Исправление:** Вернул в Makefile: `ui/ui.o`, `ui/inputbox.o`, `ui/menu.o`, `ui/welcome.o`, `ui/scanner.o`, `app/menu.o`, `app/generic.o`, `app/action.o`, `app/dtmf.o`
---
### Ошибка 9: `_sbrk` undefined
```
undefined reference to `_sbrk'
```
**Исправление:** Создал `syscalls.c`:
```c
caddr_t _sbrk(int incr) {
(void)incr;
return (caddr_t)0;
}
```
---
### Ошибка 10: `UI_DisplayReleaseKeys` / `UI_DisplayScanner`
**Исправление:** Добавил `ui/welcome.o` и `ui/scanner.o`.
---
## 3. Известные проблемы для доработки
### 3.1. POCSAG — недостаточно сэмплов
**Проблема:** `POCSAG_FeedSample()` вызывается ~1 раз/10мс. Для 1200 бод нужно ~1 раз/125мкс.
**Решение:**
```c
// В mode.c, case MODE_POCSAG:
for (int i = 0; i < 80; i++) {
uint16_t audio = BK4819_GetVoiceAmplitudeOut();
POCSAG_FeedSample(audio);
SYSTEM_DelayUs(125);
}
```
### 3.2. Нет отображения текста POCSAG сообщений
**Решение:** В `pocsag_draw()` добавить:
```c
static pocsag_msg_t last_msg;
if (POCSAG_GetMessage(&last_msg)) {
UI_PrintStringSmallNormal(last_msg.text, 0, 120, 28);
}
```
### 3.3. Дублирование APP_TimeSlice
`MODE_TimeSlice10ms()` вызывает `APP_TimeSlice10ms()`, что дублирует обработку.
**Решение:** Разделить — для VFO вызывать `APP_TimeSlice10ms()`, для POCSAG — только `CheckRadioInterrupts()`.
### 3.4. Flash на пределе (94.3%)
Осталось ~3.5 КБ. Для экономии можно отключить:
```makefile
ENABLE_FMRADIO = 0 # -2 КБ
ENABLE_SPECTRUM = 0 # -5 КБ
```
---
## 4. Инструкция по сборке
```bash
# Тулчейн
sudo apt-get install gcc-arm-none-eabi
# Сборка
cd uv-k5-firmware-custom
make clean && make
# Результат
arm-none-eabi-size firmware
# text data bss dec hex filename
# 57708 204 3364 61276 ef5c firmware
```
---
## 5. Инструкция по прошивке
### Вариант 1: SWD (J-Link)
```bash
# Установка OpenOCD
sudo apt-get install openocd
# Подключение:
# J-Link Pin 1 (VTref) — 3.3V
# J-Link Pin 2 (GND) — GND
# J-Link Pin 7 (SWDIO) — SWDIO на плате
# J-Link Pin 9 (SWCLK) — SWCLK на плате
make flash
# Или вручную:
openocd -f interface/jlink.cfg -f dp32g030.cfg \
-c "write_image firmware.bin 0; shutdown;"
```
### Вариант 2: UART
```bash
git clone https://github.com/piotr02/k5prog.git
cd k5prog && make && sudo cp k5prog /usr/local/bin/
# Включить рацию с зажатой SK2
k5prog -f firmware.bin -p /dev/ttyUSB0 -w
```
### Вариант 3: USB
```bash
# Выключить → зажать PTT+SK2 → включить
k5prog -f firmware.bin -w
```
---
## 6. Структура файлов
| Файл | Назначение |
|------|-----------|
| `Makefile` | Конфигурация сборки, флаги |
| `main.c` | Точка входа, инициализация, главный цикл |
| `syscalls.c` | Заглушка _sbrk для bare-metal |
| `app/boot_splash.c` | Заставка UA1ZBE / 2 сек |
| `app/display_rssi.c` | RSSI индикатор в dBm |
| `app/mode.c` | Диспетчер режимов |
| `app/pocsag/pocsag.c` | POCSAG декодер |
| `app/pocsag/bch31.c` | BCH(31,21) коррекция |
---
## 7. Отладочные команды
```bash
# Размер секций
arm-none-eabi-size -A firmware | sort -n -k2 | tail -20
# Символы
arm-none-eabi-nm --size-sort firmware | tail -30
# Дизассемблер
arm-none-eabi-objdump -d firmware | grep -A20 "<POCSAG_FeedSample>:"
# Проверка переполнения
SIZE=$(wc -c < firmware.bin)
[ $SIZE -gt 61440 ] && echo "OVERFLOW!" || echo "OK: $SIZE / 61440"
```

12
Dockerfile Normal file
View File

@@ -0,0 +1,12 @@
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
RUN pacman -Syyu git --noconfirm
RUN pacman -Syyu python-pip --noconfirm
RUN pacman -Syyu python-crcmod --noconfirm
WORKDIR /app
COPY . .
RUN git submodule update --init --recursive
#RUN make && cp firmware* compiled-firmware/

17
Doxyfile Normal file
View File

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

201
LICENSE Normal file
View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

425
Makefile Normal file
View File

@@ -0,0 +1,425 @@
# =============================================================================
# UA1ZBE Custom Firmware for Quansheng UV-K5/K6
# Based on egzumer/uv-k5-firmware-custom
# Three modes: VFO, POCSAG, Spectrum + FM Radio
# =============================================================================
# ---- FEATURES ----
ENABLE_UART ?= 0
ENABLE_AIRCOPY ?= 0
ENABLE_FMRADIO ?= 1
ENABLE_NOAA ?= 0
ENABLE_VOICE ?= 0
ENABLE_VOX ?= 0
ENABLE_ALARM ?= 0
ENABLE_TX1750 ?= 0
ENABLE_PWRON_PASSWORD ?= 0
ENABLE_DTMF_CALLING ?= 0
ENABLE_FLASHLIGHT ?= 0
# ---- CUSTOM MODS ----
ENABLE_BIG_FREQ ?= 1
ENABLE_SMALL_BOLD ?= 0
ENABLE_CUSTOM_MENU_LAYOUT ?= 0
ENABLE_KEEP_MEM_NAME ?= 0
ENABLE_WIDE_RX ?= 1
ENABLE_TX_WHEN_AM ?= 0
ENABLE_F_CAL_MENU ?= 0
ENABLE_CTCSS_TAIL_PHASE_SHIFT ?= 0
ENABLE_BOOT_BEEPS ?= 0
ENABLE_SHOW_CHARGE_LEVEL ?= 0
ENABLE_REVERSE_BAT_SYMBOL ?= 0
ENABLE_NO_CODE_SCAN_TIMEOUT ?= 0
ENABLE_AM_FIX ?= 0
ENABLE_SQUELCH_MORE_SENSITIVE ?= 0
ENABLE_FASTER_CHANNEL_SCAN ?= 0
ENABLE_RSSI_BAR ?= 1
ENABLE_AUDIO_BAR ?= 0
ENABLE_COPY_CHAN_TO_VFO ?= 0
ENABLE_SPECTRUM ?= 1
ENABLE_REDUCE_LOW_MID_TX_POWER?= 0
ENABLE_BYP_RAW_DEMODULATORS ?= 0
ENABLE_BLMIN_TMP_OFF ?= 0
ENABLE_SCAN_RANGES ?= 0
# ---- DEBUGGING ----
ENABLE_AM_FIX_SHOW_DATA ?= 0
ENABLE_AGC_SHOW_DATA ?= 0
ENABLE_UART_RW_BK_REGS ?= 0
# ---- COMPILER/LINKER OPTIONS ----
ENABLE_CLANG ?= 0
ENABLE_SWD ?= 0
ENABLE_OVERLAY ?= 0
ENABLE_LTO ?= 1
# ---- POCSAG DECODER ----
ENABLE_POCSAG ?= 1
#############################################################
TARGET = firmware
ifeq ($(ENABLE_CLANG),1)
ENABLE_LTO := 0
endif
ifeq ($(ENABLE_LTO),1)
ENABLE_OVERLAY := 0
endif
BSP_DEFINITIONS := $(wildcard hardware/*/*.def)
BSP_HEADERS := $(patsubst hardware/%,bsp/%,$(BSP_DEFINITIONS))
BSP_HEADERS := $(patsubst %.def,%.h,$(BSP_HEADERS))
OBJS =
# Startup files
OBJS += start.o
OBJS += init.o
ifeq ($(ENABLE_OVERLAY),1)
OBJS += sram-overlay.o
endif
OBJS += external/printf/printf.o
# Drivers
OBJS += driver/adc.o
ifeq ($(ENABLE_UART),1)
OBJS += driver/aes.o
endif
OBJS += driver/backlight.o
ifeq ($(ENABLE_FMRADIO),1)
OBJS += driver/bk1080.o
endif
OBJS += driver/bk4819.o
ifeq ($(filter $(ENABLE_AIRCOPY) $(ENABLE_UART),1),1)
OBJS += driver/crc.o
endif
OBJS += driver/eeprom.o
ifeq ($(ENABLE_OVERLAY),1)
OBJS += driver/flash.o
endif
OBJS += driver/gpio.o
OBJS += driver/i2c.o
OBJS += driver/keyboard.o
OBJS += driver/spi.o
OBJS += driver/st7565.o
OBJS += driver/system.o
OBJS += driver/systick.o
ifeq ($(ENABLE_UART),1)
OBJS += driver/uart.o
endif
# App core
OBJS += app/app.o
OBJS += app/common.o
OBJS += app/chFrScanner.o
OBJS += app/scanner.o
OBJS += app/main.o
OBJS += app/mode.o
# POCSAG decoder
ifeq ($(ENABLE_POCSAG),1)
OBJS += app/pocsag/pocsag.o
OBJS += app/pocsag/bch31.o
endif
# FM Radio
ifeq ($(ENABLE_FMRADIO),1)
OBJS += app/fm.o
OBJS += ui/fmradio.o
endif
# Spectrum analyzer
ifeq ($(ENABLE_SPECTRUM),1)
OBJS += app/spectrum.o
endif
# Reduced UI (no menu but needed for symbols)
OBJS += app/boot_splash.o
OBJS += app/display_rssi.o
OBJS += ui/inputbox.o
OBJS += ui/ui.o
OBJS += ui/menu.o
OBJS += app/menu.o
OBJS += app/generic.o
OBJS += app/action.o
OBJS += app/dtmf.o
# UI modules
OBJS += ui/main.o
OBJS += ui/helper.o
OBJS += ui/status.o
OBJS += ui/battery.o
OBJS += ui/welcome.o
OBJS += ui/scanner.o
# Core modules
OBJS += audio.o
OBJS += bitmaps.o
OBJS += board.o
OBJS += dcs.o
OBJS += font.o
OBJS += frequencies.o
OBJS += functions.o
OBJS += radio.o
OBJS += settings.o
OBJS += misc.o
OBJS += version.o
OBJS += main.o
OBJS += syscalls.o
OBJS += helper/battery.o
OBJS += helper/boot.o
ifeq ($(OS), Windows_NT)
TOP := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
RM = del /Q
FixPath = $(subst /,\,$1)
WHERE = where
NULL_OUTPUT = nul
else
TOP := $(shell pwd)
RM = rm -f
FixPath = $1
WHERE = which
NULL_OUTPUT = /dev/null
endif
AS = arm-none-eabi-gcc
LD = arm-none-eabi-gcc
ifeq ($(ENABLE_CLANG),0)
CC = arm-none-eabi-gcc
else
CC = clang --sysroot=/usr/arm-none-eabi --target=arm-none-eabi
endif
OBJCOPY = arm-none-eabi-objcopy
SIZE = arm-none-eabi-size
AUTHOR_STRING ?= UA1ZBE
ifneq (, $(shell $(WHERE) git))
VERSION_STRING ?= $(shell git describe --tags --exact-match 2>$(NULL_OUTPUT))
ifeq (, $(VERSION_STRING))
VERSION_STRING := $(shell git rev-parse --short HEAD)
endif
endif
ifeq (, $(VERSION_STRING))
VERSION_STRING := NOGIT
endif
ASFLAGS = -c -mcpu=cortex-m0
ifeq ($(ENABLE_OVERLAY),1)
ASFLAGS += -DENABLE_OVERLAY
endif
CFLAGS =
ifeq ($(ENABLE_CLANG),0)
CFLAGS += -Os -Wall -Werror -Wextra -mcpu=cortex-m0 -fno-builtin -fshort-enums -fno-delete-null-pointer-checks -std=gnu11 -MMD
else
CFLAGS += -Oz -Wall -Werror -mcpu=cortex-m0 -fno-builtin -fshort-enums -fno-delete-null-pointer-checks -std=c99 -MMD
endif
ifeq ($(ENABLE_LTO),1)
CFLAGS += -flto=auto
else
CFLAGS += -ffunction-sections -fdata-sections
endif
CFLAGS += -DPRINTF_INCLUDE_CONFIG_H
CFLAGS += -DAUTHOR_STRING=\"$(AUTHOR_STRING)\" -DVERSION_STRING=\"$(VERSION_STRING)\"
CFLAGS += -DBUILD_DATE=\"$(shell date +%Y-%m-%d)\"
# Feature defines
ifeq ($(ENABLE_SPECTRUM),1)
CFLAGS += -DENABLE_SPECTRUM
endif
ifeq ($(ENABLE_SWD),1)
CFLAGS += -DENABLE_SWD
endif
ifeq ($(ENABLE_OVERLAY),1)
CFLAGS += -DENABLE_OVERLAY
endif
ifeq ($(ENABLE_AIRCOPY),1)
CFLAGS += -DENABLE_AIRCOPY
endif
ifeq ($(ENABLE_FMRADIO),1)
CFLAGS += -DENABLE_FMRADIO
endif
ifeq ($(ENABLE_UART),1)
CFLAGS += -DENABLE_UART
endif
ifeq ($(ENABLE_BIG_FREQ),1)
CFLAGS += -DENABLE_BIG_FREQ
endif
ifeq ($(ENABLE_SMALL_BOLD),1)
CFLAGS += -DENABLE_SMALL_BOLD
endif
ifeq ($(ENABLE_NOAA),1)
CFLAGS += -DENABLE_NOAA
endif
ifeq ($(ENABLE_VOICE),1)
CFLAGS += -DENABLE_VOICE
endif
ifeq ($(ENABLE_VOX),1)
CFLAGS += -DENABLE_VOX
endif
ifeq ($(ENABLE_ALARM),1)
CFLAGS += -DENABLE_ALARM
endif
ifeq ($(ENABLE_TX1750),1)
CFLAGS += -DENABLE_TX1750
endif
ifeq ($(ENABLE_PWRON_PASSWORD),1)
CFLAGS += -DENABLE_PWRON_PASSWORD
endif
ifeq ($(ENABLE_KEEP_MEM_NAME),1)
CFLAGS += -DENABLE_KEEP_MEM_NAME
endif
ifeq ($(ENABLE_WIDE_RX),1)
CFLAGS += -DENABLE_WIDE_RX
endif
ifeq ($(ENABLE_TX_WHEN_AM),1)
CFLAGS += -DENABLE_TX_WHEN_AM
endif
ifeq ($(ENABLE_F_CAL_MENU),1)
CFLAGS += -DENABLE_F_CAL_MENU
endif
ifeq ($(ENABLE_CTCSS_TAIL_PHASE_SHIFT),1)
CFLAGS += -DENABLE_CTCSS_TAIL_PHASE_SHIFT
endif
ifeq ($(ENABLE_BOOT_BEEPS),1)
CFLAGS += -DENABLE_BOOT_BEEPS
endif
ifeq ($(ENABLE_SHOW_CHARGE_LEVEL),1)
CFLAGS += -DENABLE_SHOW_CHARGE_LEVEL
endif
ifeq ($(ENABLE_REVERSE_BAT_SYMBOL),1)
CFLAGS += -DENABLE_REVERSE_BAT_SYMBOL
endif
ifeq ($(ENABLE_NO_CODE_SCAN_TIMEOUT),1)
CFLAGS += -DENABLE_NO_CODE_SCAN_TIMEOUT
endif
ifeq ($(ENABLE_AM_FIX),1)
CFLAGS += -DENABLE_AM_FIX
endif
ifeq ($(ENABLE_AM_FIX_SHOW_DATA),1)
CFLAGS += -DENABLE_AM_FIX_SHOW_DATA
endif
ifeq ($(ENABLE_SQUELCH_MORE_SENSITIVE),1)
CFLAGS += -DENABLE_SQUELCH_MORE_SENSITIVE
endif
ifeq ($(ENABLE_FASTER_CHANNEL_SCAN),1)
CFLAGS += -DENABLE_FASTER_CHANNEL_SCAN
endif
ifeq ($(ENABLE_RSSI_BAR),1)
CFLAGS += -DENABLE_RSSI_BAR
endif
ifeq ($(ENABLE_AUDIO_BAR),1)
CFLAGS += -DENABLE_AUDIO_BAR
endif
ifeq ($(ENABLE_COPY_CHAN_TO_VFO),1)
CFLAGS += -DENABLE_COPY_CHAN_TO_VFO
endif
ifeq ($(ENABLE_SINGLE_VFO_CHAN),1)
CFLAGS += -DENABLE_SINGLE_VFO_CHAN
endif
ifeq ($(ENABLE_BAND_SCOPE),1)
CFLAGS += -DENABLE_BAND_SCOPE
endif
ifeq ($(ENABLE_REDUCE_LOW_MID_TX_POWER),1)
CFLAGS += -DENABLE_REDUCE_LOW_MID_TX_POWER
endif
ifeq ($(ENABLE_BYP_RAW_DEMODULATORS),1)
CFLAGS += -DENABLE_BYP_RAW_DEMODULATORS
endif
ifeq ($(ENABLE_BLMIN_TMP_OFF),1)
CFLAGS += -DENABLE_BLMIN_TMP_OFF
endif
ifeq ($(ENABLE_SCAN_RANGES),1)
CFLAGS += -DENABLE_SCAN_RANGES
endif
ifeq ($(ENABLE_DTMF_CALLING),1)
CFLAGS += -DENABLE_DTMF_CALLING
endif
ifeq ($(ENABLE_AGC_SHOW_DATA),1)
CFLAGS += -DENABLE_AGC_SHOW_DATA
endif
ifeq ($(ENABLE_FLASHLIGHT),1)
CFLAGS += -DENABLE_FLASHLIGHT
endif
ifeq ($(ENABLE_UART_RW_BK_REGS),1)
CFLAGS += -DENABLE_UART_RW_BK_REGS
endif
ifeq ($(ENABLE_CUSTOM_MENU_LAYOUT),1)
CFLAGS += -DENABLE_CUSTOM_MENU_LAYOUT
endif
ifeq ($(ENABLE_POCSAG),1)
CFLAGS += -DENABLE_POCSAG
endif
LDFLAGS =
LDFLAGS += -z noexecstack -mcpu=cortex-m0 -nostartfiles -Wl,-T,firmware.ld -Wl,--gc-sections
LDFLAGS += --specs=nano.specs
ifeq ($(DEBUG),1)
ASFLAGS += -g
CFLAGS += -g
LDFLAGS += -g
endif
INC =
INC += -I $(TOP)
INC += -I $(TOP)/external/CMSIS_5/CMSIS/Core/Include/
INC += -I $(TOP)/external/CMSIS_5/Device/ARM/ARMCM0/Include
LIBS =
DEPS = $(OBJS:.o=.d)
ifneq (, $(shell $(WHERE) python))
MY_PYTHON := python
else ifneq (, $(shell $(WHERE) python3))
MY_PYTHON := python3
endif
ifdef MY_PYTHON
HAS_CRCMOD := $(shell $(MY_PYTHON) -c "import crcmod" 2>&1)
endif
all: $(TARGET)
$(OBJCOPY) -O binary $< $<.bin
ifndef MY_PYTHON
$(info )
$(info !!!!!!!! PYTHON NOT FOUND, *.PACKED.BIN WON'T BE BUILT)
$(info )
else ifneq (,$(HAS_CRCMOD))
$(info )
$(info !!!!!!!! CRCMOD NOT INSTALLED, *.PACKED.BIN WON'T BE BUILT)
$(info !!!!!!!! run: pip install crcmod)
$(info )
else
-$(MY_PYTHON) fw-pack.py $<.bin $(AUTHOR_STRING) $(VERSION_STRING) $<.packed.bin
endif
$(SIZE) $<
version.o: .FORCE
$(TARGET): $(OBJS)
$(LD) $(LDFLAGS) $^ -o $@ $(LIBS)
bsp/dp32g030/%.h: hardware/dp32g030/%.def
%.o: %.c | $(BSP_HEADERS)
$(CC) $(CFLAGS) $(INC) -c $< -o $@
%.o: %.S
$(AS) $(ASFLAGS) $< -o $@
.FORCE:
-include $(DEPS)
clean:
$(RM) $(call FixPath, $(TARGET).bin $(TARGET).packed.bin $(TARGET) $(OBJS) $(DEPS))

View File

@@ -1,3 +1,42 @@
# uv-k5-ua1zbe-firmware
# UA1ZBE Custom Firmware — Quansheng UV-K5/K6
UA1ZBE Custom Firmware for Quansheng UV-K5/K6 - POCSAG, Spectrum, FM, RSSI
Кастомная прошивка на базе egzumer/uv-k5-firmware-custom.
## Возможности
| Функция | Описание |
|---------|----------|
| **VFO** | Основной режим — прямой ввод частоты с клавиатуры |
| **POCSAG** | Декодирование пейджинговых сообщений (512/1200 бод) |
| **Spectrum** | Полноэкранный спектр-анализатор |
| **FM Radio** | Приём FM-радио |
| **RSSI** | Индикатор уровня сигнала на дисплее |
| **Boot Splash** | Кастомная заставка при старте |
## Управление
| Кнопка | Действие |
|--------|----------|
| `0-9` | Прямой ввод частоты в VFO |
| `SK2` (нижняя боковая) | POCSAG режим |
| `SK1` (средняя боковая) | Спектр-анализатор |
| `0` (короткое) | FM-радио |
| `EXIT` | Возврат в VFO |
| `F` / `*` (в POCSAG) | Переключение 512 ↔ 1200 бод |
## Сборка
```bash
sudo apt-get install gcc-arm-none-eabi
make clean && make
arm-none-eabi-size firmware
```
## Размеры прошивки
```
text data bss dec hex filename
57708 204 3364 61276 ef5c firmware
```
Flash: 57.9 КБ / 60 КБ | RAM: 3.6 КБ / 16 КБ

397
am_fix.c Normal file
View File

@@ -0,0 +1,397 @@
/* Copyright 2023 OneOfEleven
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// code to 'try' and reduce the AM demodulator saturation problem
//
// that is until someone works out how to properly configure the BK chip !
#include <string.h>
#include "am_fix.h"
#include "app/main.h"
#include "board.h"
#include "driver/bk4819.h"
#include "external/printf/printf.h"
#include "frequencies.h"
#include "functions.h"
#include "misc.h"
#include "settings.h"
#ifdef ENABLE_AGC_SHOW_DATA
#include "ui/main.h"
#endif
#ifdef ENABLE_AM_FIX
typedef struct
{
uint16_t reg_val;
int8_t gain_dB;
} __attribute__((packed)) t_gain_table;
// 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
//
//// static const int16_t lna_short_dB[] = { -19, -16, -11, 0}; // was (but wrong)
// 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
//
#define LOOKUP_TABLE 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
t_gain_table gain_table[100] = {{0x03BE, -7}}; //original
uint8_t gain_table_size = 0;
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
counter = 0;
#endif
prev_rssi[vfo] = 0;
hold_counter[vfo] = 0;
gain_table_index_prev[vfo] = 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;
if (gCurrentFunction != FUNCTION_FOREGROUND && !FUNCTION_IsRx()) {
#ifdef ENABLE_AM_FIX_SHOW_DATA
counter = display_update_rate; // queue up a display update as soon as we switch to RX mode
#endif
return;
}
#ifdef ENABLE_AM_FIX_SHOW_DATA
if (counter > 0) {
if (++counter >= display_update_rate) { // trigger a display update
counter = 0;
gUpdateDisplay = true;
}
}
#endif
static uint32_t lastFreq[2];
if(gEeprom.VfoInfo[vfo].pRX->Frequency != lastFreq[vfo]) {
lastFreq[vfo] = gEeprom.VfoInfo[vfo].pRX->Frequency;
AM_fix_reset(vfo);
}
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
{ // 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
}
}
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] = MIN(index, gain_table_size - 1u);
}
{ // 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;
currentGainDiff = gain_table[0].gain_dB - gain_table[index].gain_dB;
BK4819_WriteRegister(BK4819_REG_13, gain_table[index].reg_val);
#ifdef ENABLE_AGC_SHOW_DATA
UI_MAIN_PrintAGC(true);
#endif
}
#ifdef ENABLE_AM_FIX_SHOW_DATA
if (counter == 0) {
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
int8_t AM_fix_get_gain_diff()
{
return currentGainDiff;
}
void AM_fix_enable(bool on)
{
enabled = on;
}
#endif

35
am_fix.h Normal file
View File

@@ -0,0 +1,35 @@
/* Copyright 2023 OneOfEleven
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef AM_FIXH
#include <stdint.h>
#include <stdbool.h>
#ifdef ENABLE_AM_FIX
void AM_fix_init(void);
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 unsigned vfo, char *s);
#endif
int8_t AM_fix_get_gain_diff();
void AM_fix_enable(bool on);
#endif
#endif

453
app/action.c Normal file
View File

@@ -0,0 +1,453 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <assert.h>
#include <string.h>
#include "app/action.h"
#include "app/app.h"
#include "app/chFrScanner.h"
#include "app/common.h"
#include "app/dtmf.h"
#ifdef ENABLE_FLASHLIGHT
#include "app/flashlight.h"
#endif
#ifdef ENABLE_FMRADIO
#include "app/fm.h"
#endif
#include "app/scanner.h"
#include "audio.h"
#include "bsp/dp32g030/gpio.h"
#ifdef ENABLE_FMRADIO
#include "driver/bk1080.h"
#endif
#include "driver/bk4819.h"
#include "driver/gpio.h"
#include "driver/backlight.h"
#include "functions.h"
#include "misc.h"
#include "settings.h"
#include "ui/inputbox.h"
#include "ui/ui.h"
#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
#ifdef ENABLE_SPECTRUM
#include "app/spectrum.h"
#endif
inline static void ACTION_ScanRestart() { ACTION_Scan(true); };
void (*action_opt_table[])(void) = {
[ACTION_OPT_NONE] = &FUNCTION_NOP,
[ACTION_OPT_POWER] = &ACTION_Power,
[ACTION_OPT_MONITOR] = &ACTION_Monitor,
[ACTION_OPT_SCAN] = &ACTION_ScanRestart,
[ACTION_OPT_KEYLOCK] = &COMMON_KeypadLockToggle,
[ACTION_OPT_A_B] = &COMMON_SwitchVFOs,
[ACTION_OPT_VFO_MR] = &COMMON_SwitchVFOMode,
[ACTION_OPT_SWITCH_DEMODUL] = &ACTION_SwitchDemodul,
#ifdef ENABLE_FLASHLIGHT
[ACTION_OPT_FLASHLIGHT] = &ACTION_FlashLight,
#else
[ACTION_OPT_FLASHLIGHT] = &FUNCTION_NOP,
#endif
#ifdef ENABLE_VOX
[ACTION_OPT_VOX] = &ACTION_Vox,
#else
[ACTION_OPT_VOX] = &FUNCTION_NOP,
#endif
#ifdef ENABLE_FMRADIO
[ACTION_OPT_FM] = &ACTION_FM,
#else
[ACTION_OPT_FM] = &FUNCTION_NOP,
#endif
#ifdef ENABLE_ALARM
[ACTION_OPT_ALARM] = &ACTION_Alarm,
#else
[ACTION_OPT_ALARM] = &FUNCTION_NOP,
#endif
#ifdef ENABLE_TX1750
[ACTION_OPT_1750] = &ACTION_1750,
#else
[ACTION_OPT_1750] = &FUNCTION_NOP,
#endif
#ifdef ENABLE_BLMIN_TMP_OFF
[ACTION_OPT_BLMIN_TMP_OFF] = &ACTION_BlminTmpOff,
#else
[ACTION_OPT_BLMIN_TMP_OFF] = &FUNCTION_NOP,
#endif
#ifdef ENABLE_SPECTRUM
[ACTION_OPT_SPECTRUM] = &APP_RunSpectrum,
#else
[ACTION_OPT_SPECTRUM] = &FUNCTION_NOP,
#endif
};
static_assert(ARRAY_SIZE(action_opt_table) == ACTION_OPT_LEN);
void ACTION_Power(void)
{
if (++gTxVfo->OUTPUT_POWER > OUTPUT_POWER_HIGH)
gTxVfo->OUTPUT_POWER = OUTPUT_POWER_LOW;
gRequestSaveChannel = 1;
gRequestDisplayScreen = gScreenToDisplay;
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_POWER;
#endif
}
void ACTION_Monitor(void)
{
if (gCurrentFunction != FUNCTION_MONITOR) { // enable the monitor
RADIO_SelectVfos();
#ifdef ENABLE_NOAA
if (IS_NOAA_CHANNEL(gRxVfo->CHANNEL_SAVE) && gIsNoaaMode)
gNoaaChannel = gRxVfo->CHANNEL_SAVE - NOAA_CHANNEL_FIRST;
#endif
RADIO_SetupRegisters(true);
APP_StartListening(FUNCTION_MONITOR);
return;
}
gMonitor = false;
if (gScanStateDir != SCAN_OFF) {
gScanPauseDelayIn_10ms = scan_pause_delay_in_1_10ms;
gScheduleScanListen = false;
gScanPauseMode = true;
}
#ifdef ENABLE_NOAA
if (gEeprom.DUAL_WATCH == DUAL_WATCH_OFF && gIsNoaaMode) {
gNOAA_Countdown_10ms = NOAA_countdown_10ms;
gScheduleNOAA = false;
}
#endif
RADIO_SetupRegisters(true);
#ifdef ENABLE_FMRADIO
if (gFmRadioMode) {
FM_Start();
gRequestDisplayScreen = DISPLAY_FM;
}
else
#endif
gRequestDisplayScreen = gScreenToDisplay;
}
void ACTION_Scan(bool bRestart)
{
(void)bRestart;
#ifdef ENABLE_FMRADIO
if (gFmRadioMode) {
ACTION_Scan_FM(bRestart);
return;
}
#endif
if (SCANNER_IsScanning()) {
return;
}
// not scanning
gMonitor = false;
#ifdef ENABLE_DTMF_CALLING
DTMF_clear_RX();
#endif
gDTMF_RX_live_timeout = 0;
memset(gDTMF_RX_live, 0, sizeof(gDTMF_RX_live));
RADIO_SelectVfos();
#ifdef ENABLE_NOAA
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;
}
void ACTION_SwitchDemodul(void)
{
gRequestSaveChannel = 1;
gTxVfo->Modulation++;
if(gTxVfo->Modulation == MODULATION_UKNOWN)
gTxVfo->Modulation = MODULATION_FM;
}
void ACTION_Handle(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
{
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;
}
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;
funcLong = gEeprom.KEY_1_LONG_PRESS_ACTION;
break;
case KEY_SIDE2:
funcShort = gEeprom.KEY_2_SHORT_PRESS_ACTION;
funcLong = gEeprom.KEY_2_LONG_PRESS_ACTION;
break;
case KEY_MENU:
funcLong = gEeprom.KEY_M_LONG_PRESS_ACTION;
break;
default:
break;
}
if (!bKeyHeld && bKeyPressed) // button pushed
{
return;
}
// held or released beyond this point
if(!(bKeyHeld && !bKeyPressed)) // don't beep on released after hold
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
if (bKeyHeld || bKeyPressed) // held
{
funcShort = funcLong;
if (!bKeyPressed) //ignore release if held
return;
}
// held or released after short press beyond this point
action_opt_table[funcShort]();
}
#ifdef ENABLE_FMRADIO
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 freq;
if (bRestart) {
gFM_AutoScan = true;
gFM_ChannelPosition = 0;
FM_EraseChannels();
freq = BK1080_GetFreqLoLimit(gEeprom.FM_Band);
} else {
gFM_AutoScan = false;
gFM_ChannelPosition = 0;
freq = gEeprom.FM_FrequencyPlaying;
}
BK1080_GetFrequencyDeviation(freq);
FM_Tune(freq, 1, bRestart);
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_SCANNING_BEGIN;
#endif
}
#endif
#if defined(ENABLE_ALARM) || defined(ENABLE_TX1750)
static void ACTION_AlarmOr1750(const bool b1750)
{
#if defined(ENABLE_ALARM)
const AlarmState_t alarm_mode = (gEeprom.ALARM_MODE == ALARM_MODE_TONE) ? ALARM_STATE_TXALARM : ALARM_STATE_SITE_ALARM;
gAlarmRunningCounter = 0;
#endif
#if defined(ENABLE_ALARM) && defined(ENABLE_TX1750)
gAlarmState = b1750 ? ALARM_STATE_TX1750 : alarm_mode;
#elif defined(ENABLE_ALARM)
gAlarmState = alarm_mode;
#else
gAlarmState = ALARM_STATE_TX1750;
#endif
(void)b1750;
gInputBoxIndex = 0;
gFlagPrepareTX = gAlarmState != ALARM_STATE_OFF;
if (gScreenToDisplay != DISPLAY_MENU) // 1of11 .. don't close the menu
gRequestDisplayScreen = DISPLAY_MAIN;
}
#endif
#ifdef ENABLE_VOX
void ACTION_Vox(void)
{
gEeprom.VOX_SWITCH = !gEeprom.VOX_SWITCH;
gRequestSaveSettings = true;
gFlagReconfigureVfos = true;
gUpdateStatus = true;
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_VOX;
#endif
}
#endif
#ifdef ENABLE_BLMIN_TMP_OFF
void ACTION_BlminTmpOff(void)
{
if(++gEeprom.BACKLIGHT_MIN_STAT == BLMIN_STAT_UNKNOWN) {
gEeprom.BACKLIGHT_MIN_STAT = BLMIN_STAT_ON;
BACKLIGHT_SetBrightness(gEeprom.BACKLIGHT_MIN);
} else {
BACKLIGHT_SetBrightness(0);
}
}
#endif

40
app/action.h Normal file
View File

@@ -0,0 +1,40 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef APP_ACTION_H
#define APP_ACTION_H
#include "driver/keyboard.h"
void ACTION_Power(void);
void ACTION_Monitor(void);
void ACTION_Scan(bool bRestart);
#ifdef ENABLE_VOX
void ACTION_Vox(void);
#endif
#ifdef ENABLE_FMRADIO
void ACTION_FM(void);
#endif
void ACTION_SwitchDemodul(void);
#ifdef ENABLE_BLMIN_TMP_OFF
void ACTION_BlminTmpOff(void);
#endif
void ACTION_Handle(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld);
#endif

242
app/aircopy.c Normal file
View File

@@ -0,0 +1,242 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef ENABLE_AIRCOPY
#include "app/aircopy.h"
#include "audio.h"
#include "driver/bk4819.h"
#include "driver/crc.h"
#include "driver/eeprom.h"
#include "frequencies.h"
#include "misc.h"
#include "radio.h"
#include "ui/helper.h"
#include "ui/inputbox.h"
#include "ui/ui.h"
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 g_FSK_Buffer[36];
bool AIRCOPY_SendMessage(void)
{
static uint8_t gAircopySendCountdown = 1;
if (gAircopyState != AIRCOPY_TRANSFER) {
return 1;
}
if (--gAircopySendCountdown) {
return 1;
}
g_FSK_Buffer[1] = (gAirCopyBlockNumber & 0x3FF) << 6;
EEPROM_ReadBuffer(g_FSK_Buffer[1], &g_FSK_Buffer[2], 64);
g_FSK_Buffer[34] = CRC_Calculate(&g_FSK_Buffer[1], 2 + 64);
for (unsigned int i = 0; i < 34; i++) {
g_FSK_Buffer[i + 1] ^= Obfuscation[i % 8];
}
if (++gAirCopyBlockNumber >= 0x78) {
gAircopyState = AIRCOPY_COMPLETE;
}
RADIO_SetTxParameters();
BK4819_SendFSKData(g_FSK_Buffer);
BK4819_SetupPowerAmplifier(0, 0);
BK4819_ToggleGpioOut(BK4819_GPIO1_PIN29_PA_ENABLE, false);
gAircopySendCountdown = 30;
return 0;
}
void AIRCOPY_StorePacket(void)
{
if (gFSKWriteIndex < 36) {
return;
}
gFSKWriteIndex = 0;
gUpdateDisplay = true;
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) {
gErrorsDuringAirCopy++;
return;
}
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) {
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) {
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) {
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;
}
}
#endif

46
app/aircopy.h Normal file
View File

@@ -0,0 +1,46 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef APP_AIRCOPY_H
#define APP_AIRCOPY_H
#ifdef ENABLE_AIRCOPY
#include "driver/keyboard.h"
enum AIRCOPY_State_t
{
AIRCOPY_READY = 0,
AIRCOPY_TRANSFER,
AIRCOPY_COMPLETE
};
typedef enum AIRCOPY_State_t AIRCOPY_State_t;
extern AIRCOPY_State_t gAircopyState;
extern uint16_t gAirCopyBlockNumber;
extern uint16_t gErrorsDuringAirCopy;
extern uint8_t gAirCopyIsSendMode;
extern uint16_t g_FSK_Buffer[36];
bool AIRCOPY_SendMessage(void);
void AIRCOPY_StorePacket(void);
void AIRCOPY_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld);
#endif
#endif

1888
app/app.c Normal file

File diff suppressed because it is too large Load Diff

35
app/app.h Normal file
View File

@@ -0,0 +1,35 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef APP_APP_H
#define APP_APP_H
#include <stdbool.h>
#include "functions.h"
#include "frequencies.h"
#include "radio.h"
void APP_EndTransmission(void);
void APP_StartListening(FUNCTION_Type_t function);
uint32_t APP_SetFreqByStepAndLimits(VFO_Info_t *pInfo, int8_t direction, uint32_t lower, uint32_t upper);
uint32_t APP_SetFrequencyByStep(VFO_Info_t *pInfo, int8_t direction);
void APP_Update(void);
void APP_TimeSlice10ms(void);
void APP_TimeSlice500ms(void);
#endif

53
app/boot_splash.c Normal file
View File

@@ -0,0 +1,53 @@
/* UA1ZBE Custom Firmware - Boot Splash Screen
* Displays:
* Line 1 (top, large): UA1ZBE
* Line 2 (center): POCSAG pager
* Line 3 (bottom): YYYY-MM-DD (build date)
* Then fades to VFO mode after 2 seconds.
*/
#include <string.h>
#include "driver/st7565.h"
#include "driver/system.h"
#include "ui/helper.h"
#include "font.h"
#ifndef BUILD_DATE
#define BUILD_DATE "unknown"
#endif
void BOOT_SplashShow(void)
{
/* Clear screen */
ST7565_FillScreen(0x00);
memset(gStatusLine, 0, sizeof(gStatusLine));
for (int line = 0; line < FRAME_LINES; line++)
memset(gFrameBuffer[line], 0, LCD_WIDTH);
/* Line 1: UA1ZBE — large font, centered, top */
UI_PrintString("UA1ZBE", 0, LCD_WIDTH, 0, 12);
/* Line 2: "POCSAG pager" — small font, centered */
/* Small font is 6 pixels tall, at y-offset line 3 (~24px) */
const char *line2 = "POCSAG pager";
int len2 = 0;
while (line2[len2]) len2++;
int x2 = (LCD_WIDTH - len2 * 6) / 2;
if (x2 < 0) x2 = 0;
UI_PrintStringSmallNormal(line2, x2, LCD_WIDTH, 24);
/* Line 3: BUILD_DATE — small font, centered, bottom */
const char *date_str = BUILD_DATE;
int len3 = 0;
while (date_str[len3]) len3++;
int x3 = (LCD_WIDTH - len3 * 6) / 2;
if (x3 < 0) x3 = 0;
UI_PrintStringSmallNormal(date_str, x3, LCD_WIDTH, 48);
/* Blit to screen */
ST7565_BlitStatusLine();
ST7565_BlitFullScreen();
/* Hold for 2 seconds */
SYSTEM_DelayMs(2000);
}

7
app/boot_splash.h Normal file
View File

@@ -0,0 +1,7 @@
/* UA1ZBE Custom Firmware - Boot Splash Screen */
#ifndef APP_BOOT_SPLASH_H
#define APP_BOOT_SPLASH_H
void BOOT_SplashShow(void);
#endif

273
app/chFrScanner.c Normal file
View File

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

23
app/chFrScanner.h Normal file
View File

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

77
app/common.c Normal file
View File

@@ -0,0 +1,77 @@
#include "app/chFrScanner.h"
#include "audio.h"
#include "functions.h"
#include "misc.h"
#include "settings.h"
#include "ui/ui.h"
void COMMON_KeypadLockToggle()
{
if (gScreenToDisplay != DISPLAY_MENU &&
gCurrentFunction != FUNCTION_TRANSMIT)
{ // toggle the keyboad lock
#ifdef ENABLE_VOICE
gAnotherVoiceID = gEeprom.KEY_LOCK ? VOICE_ID_UNLOCK : VOICE_ID_LOCK;
#endif
gEeprom.KEY_LOCK = !gEeprom.KEY_LOCK;
gRequestSaveSettings = true;
}
}
void COMMON_SwitchVFOs()
{
#ifdef ENABLE_SCAN_RANGES
gScanRangeStart = 0;
#endif
gEeprom.TX_VFO ^= 1;
if (gEeprom.CROSS_BAND_RX_TX != CROSS_BAND_OFF)
gEeprom.CROSS_BAND_RX_TX = gEeprom.TX_VFO + 1;
if (gEeprom.DUAL_WATCH != DUAL_WATCH_OFF)
gEeprom.DUAL_WATCH = gEeprom.TX_VFO + 1;
gRequestSaveSettings = 1;
gFlagReconfigureVfos = true;
gScheduleDualWatch = true;
gRequestDisplayScreen = DISPLAY_MAIN;
}
void COMMON_SwitchVFOMode()
{
#ifdef ENABLE_NOAA
if (gEeprom.VFO_OPEN && !IS_NOAA_CHANNEL(gTxVfo->CHANNEL_SAVE))
#else
if (gEeprom.VFO_OPEN)
#endif
{
if (IS_MR_CHANNEL(gTxVfo->CHANNEL_SAVE))
{ // swap to frequency mode
gEeprom.ScreenChannel[gEeprom.TX_VFO] = gEeprom.FreqChannel[gEeprom.TX_VFO];
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_FREQUENCY_MODE;
#endif
gRequestSaveVFO = true;
gVfoConfigureMode = VFO_CONFIGURE_RELOAD;
return;
}
uint8_t Channel = RADIO_FindNextChannel(gEeprom.MrChannel[gEeprom.TX_VFO], 1, false, 0);
if (Channel != 0xFF)
{ // swap to channel mode
gEeprom.ScreenChannel[gEeprom.TX_VFO] = Channel;
#ifdef ENABLE_VOICE
AUDIO_SetVoiceID(0, VOICE_ID_CHANNEL_MODE);
AUDIO_SetDigitVoice(1, Channel + 1);
gAnotherVoiceID = (VOICE_ID_t)0xFE;
#endif
gRequestSaveVFO = true;
gVfoConfigureMode = VFO_CONFIGURE_RELOAD;
return;
}
}
}

13
app/common.h Normal file
View File

@@ -0,0 +1,13 @@
#ifndef APP_COMMON_H
#define APP_COMMON_H
#include "functions.h"
#include "settings.h"
#include "ui/ui.h"
void COMMON_KeypadLockToggle();
void COMMON_SwitchVFOs();
void COMMON_SwitchVFOMode();
#endif

128
app/display_rssi.c Normal file
View File

@@ -0,0 +1,128 @@
/* UA1ZBE Custom Firmware - RSSI Display Implementation
*
* Reads RSSI from BK4819 REG_67 (9-bit value).
* Conversion: dBm = (raw / 2) - 160 + band_correction
*
* Displays as "S:XX" format with optional mini bar.
* Updates every ~150ms via internal counter.
*/
#include "display_rssi.h"
#include "driver/bk4819.h"
#include "driver/st7565.h"
#include "ui/helper.h"
#include "ui/main.h"
#include "misc.h"
#include "radio.h"
#include <string.h>
#include <stdio.h>
/* dBm correction table — defined in ui/main.c */
extern const int8_t dBmCorrTable[7];
/* === Internal state === */
static int16_t s_rssi_dbm;
static uint16_t s_rssi_raw;
static uint8_t s_s_level;
static uint16_t s_update_counter;
/* Update interval: ~15 (150ms at 10ms tick) */
#define RSSI_UPDATE_INTERVAL 15
/* S-meter thresholds (dBm) — simplified from U8RssiMap */
static const int8_t s_thresholds[] = {
-121, -115, -109, -103, -97, -91, -85, -79, -73, -63
};
void RSSI_Init(void)
{
s_rssi_dbm = -160;
s_rssi_raw = 0;
s_s_level = 0;
s_update_counter = 0;
}
void RSSI_Update(void)
{
s_update_counter++;
if (s_update_counter < RSSI_UPDATE_INTERVAL)
return;
s_update_counter = 0;
/* Read raw RSSI from BK4819 */
s_rssi_raw = BK4819_GetRSSI();
/* Convert to dBm: (raw / 2) - 160 + band_correction
* Avoid division: raw >> 1 */
int8_t band_corr = dBmCorrTable[gRxVfo->Band];
s_rssi_dbm = (int16_t)(s_rssi_raw >> 1) - 160 + band_corr;
/* Calculate S-level */
s_s_level = 0;
for (uint8_t i = 0; i < ARRAY_SIZE(s_thresholds); i++) {
if (s_rssi_dbm >= s_thresholds[i]) {
s_s_level = i + 1;
}
}
if (s_s_level > 9)
s_s_level = 9;
}
int16_t RSSI_GetdBm(void)
{
return s_rssi_dbm;
}
uint16_t RSSI_GetRaw(void)
{
return s_rssi_raw;
}
uint8_t RSSI_GetSLevel(void)
{
return s_s_level;
}
/*
* Draw RSSI indicator.
* Format: "S:42" or raw dBm with mini bar.
* Uses small font to fit in upper-right corner.
*/
void RSSI_Draw(int x, int y, bool with_bar)
{
static char buf[16];
/* Draw dBm value: "-87dBm" */
sprintf(buf, "%ddBm", s_rssi_dbm);
UI_PrintStringSmallNormal(buf, x, LCD_WIDTH, y);
if (with_bar) {
/* Draw mini signal bar below the text
* 5 bars, each 2px wide, 1px gap */
int bar_x = x;
int bar_y = y + 8;
uint8_t bars = (s_s_level + 1) / 2; /* 0-5 bars from S0-S9 */
if (bars > 5) bars = 5;
for (uint8_t i = 0; i < 5; i++) {
uint8_t h = 2 + i * 2; /* Bar heights: 2,4,6,8,10 */
if (i < bars) {
/* Draw filled bar */
for (uint8_t py = 0; py < h; py++) {
for (uint8_t px = 0; px < 2; px++) {
UI_DrawPixelBuffer(gFrameBuffer, bar_x + i * 3 + px, bar_y + (10 - h) + py, true);
}
}
} else {
/* Draw outline only */
UI_DrawPixelBuffer(gFrameBuffer, bar_x + i * 3, bar_y + (10 - h), false);
UI_DrawPixelBuffer(gFrameBuffer, bar_x + i * 3 + 1, bar_y + (10 - h), false);
UI_DrawPixelBuffer(gFrameBuffer, bar_x + i * 3, bar_y + 9, false);
UI_DrawPixelBuffer(gFrameBuffer, bar_x + i * 3 + 1, bar_y + 9, false);
UI_DrawPixelBuffer(gFrameBuffer, bar_x + i * 3, bar_y + (10 - h) + 1, false);
UI_DrawPixelBuffer(gFrameBuffer, bar_x + i * 3 + 1, bar_y + (10 - h) + 1, false);
}
}
}
}

36
app/display_rssi.h Normal file
View File

@@ -0,0 +1,36 @@
/* UA1ZBE Custom Firmware - RSSI Display Module
*
* Reads RSSI from BK4819 every 100-200ms, converts to dBm,
* and draws an indicator on the display.
*
* Format: "S:42" or "-87dBm" with mini bar
* Shown in upper-right corner of screen.
*/
#ifndef APP_DISPLAY_RSSI_H
#define APP_DISPLAY_RSSI_H
#include <stdbool.h>
#include <stdint.h>
/* Initialize RSSI display module */
void RSSI_Init(void);
/* Call from 10ms timeslice to update RSSI reading */
void RSSI_Update(void);
/* Draw RSSI indicator on the screen
* x, y: position on screen
* with_bar: if true, draw a mini signal bar next to the value */
void RSSI_Draw(int x, int y, bool with_bar);
/* Get current RSSI value in dBm */
int16_t RSSI_GetdBm(void);
/* Get raw RSSI value (0-511 from BK4819 REG_67) */
uint16_t RSSI_GetRaw(void);
/* Get S-meter level (0-9) */
uint8_t RSSI_GetSLevel(void);
#endif

504
app/dtmf.c Normal file
View File

@@ -0,0 +1,504 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include <stdio.h> // NULL
#include "app/chFrScanner.h"
#ifdef ENABLE_FMRADIO
#include "app/fm.h"
#endif
#include "app/scanner.h"
#include "bsp/dp32g030/gpio.h"
#include "audio.h"
#include "driver/bk4819.h"
#include "driver/eeprom.h"
#include "driver/gpio.h"
#include "driver/system.h"
#include "dtmf.h"
#include "external/printf/printf.h"
#include "misc.h"
#include "settings.h"
#include "ui/ui.h"
char gDTMF_String[15];
char gDTMF_InputBox[15];
uint8_t gDTMF_InputBox_Index = 0;
bool gDTMF_InputMode = false;
uint8_t gDTMF_PreviousIndex = 0;
char gDTMF_RX_live[20];
uint8_t gDTMF_RX_live_timeout = 0;
#ifdef ENABLE_DTMF_CALLING
char gDTMF_RX[17];
uint8_t gDTMF_RX_index = 0;
uint8_t gDTMF_RX_timeout = 0;
bool gDTMF_RX_pending = false;
bool gIsDtmfContactValid;
char gDTMF_ID[4];
char gDTMF_Caller[4];
char gDTMF_Callee[4];
DTMF_State_t gDTMF_State;
uint8_t gDTMF_DecodeRingCountdown_500ms;
uint8_t gDTMF_chosen_contact;
uint8_t gDTMF_auto_reset_time_500ms;
DTMF_CallState_t gDTMF_CallState;
DTMF_CallMode_t gDTMF_CallMode;
bool gDTMF_IsTx;
uint8_t gDTMF_TxStopCountdown_500ms;
bool gDTMF_IsGroupCall;
#endif
DTMF_ReplyState_t gDTMF_ReplyState;
#ifdef ENABLE_DTMF_CALLING
void DTMF_clear_RX(void)
{
gDTMF_RX_timeout = 0;
gDTMF_RX_index = 0;
gDTMF_RX_pending = false;
memset(gDTMF_RX, 0, sizeof(gDTMF_RX));
}
#endif
void DTMF_SendEndOfTransmission(void)
{
if (gCurrentVfo->DTMF_PTT_ID_TX_MODE == PTT_ID_APOLLO)
BK4819_PlaySingleTone(2475, 250, 28, gEeprom.DTMF_SIDE_TONE);
else if ((gCurrentVfo->DTMF_PTT_ID_TX_MODE == PTT_ID_TX_DOWN || gCurrentVfo->DTMF_PTT_ID_TX_MODE == PTT_ID_BOTH)
#ifdef ENABLE_DTMF_CALLING
&& gDTMF_CallState == DTMF_CALL_STATE_NONE
#endif
) { // end-of-tx
if (gEeprom.DTMF_SIDE_TONE) {
AUDIO_AudioPathOn();
gEnableSpeaker = true;
SYSTEM_DelayMs(60);
}
BK4819_EnterDTMF_TX(gEeprom.DTMF_SIDE_TONE);
BK4819_PlayDTMFString(
gEeprom.DTMF_DOWN_CODE,
0,
gEeprom.DTMF_FIRST_CODE_PERSIST_TIME,
gEeprom.DTMF_HASH_CODE_PERSIST_TIME,
gEeprom.DTMF_CODE_PERSIST_TIME,
gEeprom.DTMF_CODE_INTERVAL_TIME);
AUDIO_AudioPathOff();
gEnableSpeaker = false;
}
BK4819_ExitDTMF_TX(true);
}
bool DTMF_ValidateCodes(char *pCode, const unsigned int size)
{
unsigned int i;
if (pCode[0] == 0xFF || pCode[0] == 0)
return false;
for (i = 0; i < size; i++)
{
if (pCode[i] == 0xFF || pCode[i] == 0)
{
pCode[i] = 0;
break;
}
if ((pCode[i] < '0' || pCode[i] > '9') && (pCode[i] < 'A' || pCode[i] > 'D') && pCode[i] != '*' && pCode[i] != '#')
return false;
}
return true;
}
#ifdef ENABLE_DTMF_CALLING
bool DTMF_GetContact(const int Index, char *pContact)
{
if (Index < 0 || Index >= MAX_DTMF_CONTACTS || pContact == NULL) {
return false;
}
EEPROM_ReadBuffer(0x1C00 + (Index * 16), pContact, 16);
// check whether the first character is printable or not
return (pContact[0] >= ' ' && pContact[0] < 127);
}
bool DTMF_FindContact(const char *pContact, char *pResult)
{
pResult[0] = 0;
for (unsigned int i = 0; i < MAX_DTMF_CONTACTS; i++) {
char Contact[16];
if (!DTMF_GetContact(i, Contact)) {
return false;
}
if (memcmp(pContact, Contact + 8, 3) == 0) {
memcpy(pResult, Contact, 8);
pResult[8] = 0;
return true;
}
}
return false;
}
#endif
char DTMF_GetCharacter(const unsigned int code)
{
switch (code)
{
case KEY_0: return '0';
case KEY_1: return '1';
case KEY_2: return '2';
case KEY_3: return '3';
case KEY_4: return '4';
case KEY_5: return '5';
case KEY_6: return '6';
case KEY_7: return '7';
case KEY_8: return '8';
case KEY_9: return '9';
case KEY_MENU: return 'A';
case KEY_UP: return 'B';
case KEY_DOWN: return 'C';
case KEY_EXIT: return 'D';
case KEY_STAR: return '*';
case KEY_F: return '#';
default: return 0xff;
}
}
#ifdef ENABLE_DTMF_CALLING
static bool CompareMessage(const char *pMsg, const char *pTemplate, const unsigned int size, const bool bCheckGroup)
{
unsigned int i;
for (i = 0; i < size; i++)
{
if (pMsg[i] != pTemplate[i])
{
if (!bCheckGroup || pMsg[i] != gEeprom.DTMF_GROUP_CALL_CODE)
return false;
gDTMF_IsGroupCall = true;
}
}
return true;
}
DTMF_CallMode_t DTMF_CheckGroupCall(const char *pMsg, const unsigned int size)
{
for (unsigned int i = 0; i < size; i++)
if (pMsg[i] == gEeprom.DTMF_GROUP_CALL_CODE) {
return DTMF_CALL_MODE_GROUP;
}
return DTMF_CALL_MODE_NOT_GROUP;
}
#endif
void DTMF_clear_input_box(void)
{
memset(gDTMF_InputBox, 0, sizeof(gDTMF_InputBox));
gDTMF_InputBox_Index = 0;
gDTMF_InputMode = false;
}
void DTMF_Append(const char code)
{
if (gDTMF_InputBox_Index == 0)
{
memset(gDTMF_InputBox, '-', sizeof(gDTMF_InputBox) - 1);
gDTMF_InputBox[sizeof(gDTMF_InputBox) - 1] = 0;
}
if (gDTMF_InputBox_Index < (sizeof(gDTMF_InputBox) - 1))
gDTMF_InputBox[gDTMF_InputBox_Index++] = code;
}
#ifdef ENABLE_DTMF_CALLING
void DTMF_HandleRequest(void)
{ // proccess the RX'ed DTMF characters
char String[21];
unsigned int Offset;
if (!gDTMF_RX_pending)
return; // nothing new received
if (gScanStateDir != SCAN_OFF || gCssBackgroundScan)
{ // we're busy scanning
DTMF_clear_RX();
return;
}
if (!gRxVfo->DTMF_DECODING_ENABLE && !gSetting_KILLED)
{ // D-DCD is disabled or we're alive
DTMF_clear_RX();
return;
}
gDTMF_RX_pending = false;
if (gDTMF_RX_index >= 9)
{ // look for the KILL code
sprintf(String, "%s%c%s", gEeprom.ANI_DTMF_ID, gEeprom.DTMF_SEPARATE_CODE, gEeprom.KILL_CODE);
Offset = gDTMF_RX_index - strlen(String);
if (CompareMessage(gDTMF_RX + Offset, String, strlen(String), true))
{ // bugger
if (gEeprom.PERMIT_REMOTE_KILL)
{
gSetting_KILLED = true; // oooerr !
DTMF_clear_RX();
SETTINGS_SaveSettings();
gDTMF_ReplyState = DTMF_REPLY_AB;
#ifdef ENABLE_FMRADIO
if (gFmRadioMode)
{
FM_TurnOff();
GUI_SelectNextDisplay(DISPLAY_MAIN);
}
#endif
}
else
{
gDTMF_ReplyState = DTMF_REPLY_NONE;
}
gDTMF_CallState = DTMF_CALL_STATE_NONE;
gUpdateDisplay = true;
gUpdateStatus = true;
return;
}
}
if (gDTMF_RX_index >= 9)
{ // look for the REVIVE code
sprintf(String, "%s%c%s", gEeprom.ANI_DTMF_ID, gEeprom.DTMF_SEPARATE_CODE, gEeprom.REVIVE_CODE);
Offset = gDTMF_RX_index - strlen(String);
if (CompareMessage(gDTMF_RX + Offset, String, strlen(String), true))
{ // shit, we're back !
gSetting_KILLED = false;
DTMF_clear_RX();
SETTINGS_SaveSettings();
gDTMF_ReplyState = DTMF_REPLY_AB;
gDTMF_CallState = DTMF_CALL_STATE_NONE;
gUpdateDisplay = true;
gUpdateStatus = true;
return;
}
}
if (gDTMF_RX_index >= 2)
{ // look for ACK reply
char *pPrintStr = "AB";
Offset = gDTMF_RX_index - strlen(pPrintStr);
if (CompareMessage(gDTMF_RX + Offset, pPrintStr, strlen(pPrintStr), true)) {
// ends with "AB"
if (gDTMF_ReplyState != DTMF_REPLY_NONE) // 1of11
// if (gDTMF_CallState != DTMF_CALL_STATE_NONE) // 1of11
// if (gDTMF_CallState == DTMF_CALL_STATE_CALL_OUT) // 1of11
{
gDTMF_State = DTMF_STATE_TX_SUCC;
DTMF_clear_RX();
gUpdateDisplay = true;
return;
}
}
}
if (gDTMF_CallState == DTMF_CALL_STATE_CALL_OUT &&
gDTMF_CallMode == DTMF_CALL_MODE_NOT_GROUP &&
gDTMF_RX_index >= 9)
{ // waiting for a reply
sprintf(String, "%s%c%s", gDTMF_String, gEeprom.DTMF_SEPARATE_CODE, "AAAAA");
Offset = gDTMF_RX_index - strlen(String);
if (CompareMessage(gDTMF_RX + Offset, String, strlen(String), false))
{ // we got a response
gDTMF_State = DTMF_STATE_CALL_OUT_RSP;
DTMF_clear_RX();
gUpdateDisplay = true;
}
}
if (gSetting_KILLED || gDTMF_CallState != DTMF_CALL_STATE_NONE)
{ // we've been killed or expecting a reply
return;
}
if (gDTMF_RX_index >= 7)
{ // see if we're being called
gDTMF_IsGroupCall = false;
sprintf(String, "%s%c", gEeprom.ANI_DTMF_ID, gEeprom.DTMF_SEPARATE_CODE);
Offset = gDTMF_RX_index - strlen(String) - 3;
if (CompareMessage(gDTMF_RX + Offset, String, strlen(String), true))
{ // it's for us !
gDTMF_CallState = DTMF_CALL_STATE_RECEIVED;
memset(gDTMF_Callee, 0, sizeof(gDTMF_Callee));
memset(gDTMF_Caller, 0, sizeof(gDTMF_Caller));
memcpy(gDTMF_Callee, gDTMF_RX + Offset + 0, 3);
memcpy(gDTMF_Caller, gDTMF_RX + Offset + 4, 3);
DTMF_clear_RX();
gUpdateDisplay = true;
switch (gEeprom.DTMF_DECODE_RESPONSE)
{
case DTMF_DEC_RESPONSE_BOTH:
gDTMF_DecodeRingCountdown_500ms = DTMF_decode_ring_countdown_500ms;
__attribute__((fallthrough));
case DTMF_DEC_RESPONSE_REPLY:
gDTMF_ReplyState = DTMF_REPLY_AAAAA;
break;
case DTMF_DEC_RESPONSE_RING:
gDTMF_DecodeRingCountdown_500ms = DTMF_decode_ring_countdown_500ms;
break;
default:
case DTMF_DEC_RESPONSE_NONE:
gDTMF_DecodeRingCountdown_500ms = 0;
gDTMF_ReplyState = DTMF_REPLY_NONE;
break;
}
if (gDTMF_IsGroupCall)
gDTMF_ReplyState = DTMF_REPLY_NONE;
}
}
}
#endif
void DTMF_Reply(void)
{
uint16_t Delay;
#ifdef ENABLE_DTMF_CALLING
char String[23];
#endif
const char *pString = NULL;
switch (gDTMF_ReplyState)
{
case DTMF_REPLY_ANI:
#ifdef ENABLE_DTMF_CALLING
if (gDTMF_CallMode != DTMF_CALL_MODE_DTMF)
{ // append our ID code onto the end of the DTMF code to send
sprintf(String, "%s%c%s", gDTMF_String, gEeprom.DTMF_SEPARATE_CODE, gEeprom.ANI_DTMF_ID);
pString = String;
}
else
#endif
{
pString = gDTMF_String;
}
break;
#ifdef ENABLE_DTMF_CALLING
case DTMF_REPLY_AB:
pString = "AB";
break;
case DTMF_REPLY_AAAAA:
sprintf(String, "%s%c%s", gEeprom.ANI_DTMF_ID, gEeprom.DTMF_SEPARATE_CODE, "AAAAA");
pString = String;
break;
#endif
default:
case DTMF_REPLY_NONE:
if (
#ifdef ENABLE_DTMF_CALLING
gDTMF_CallState != DTMF_CALL_STATE_NONE ||
#endif
gCurrentVfo->DTMF_PTT_ID_TX_MODE == PTT_ID_APOLLO ||
gCurrentVfo->DTMF_PTT_ID_TX_MODE == PTT_ID_OFF ||
gCurrentVfo->DTMF_PTT_ID_TX_MODE == PTT_ID_TX_DOWN)
{
gDTMF_ReplyState = DTMF_REPLY_NONE;
return;
}
// send TX-UP DTMF
pString = gEeprom.DTMF_UP_CODE;
break;
}
gDTMF_ReplyState = DTMF_REPLY_NONE;
if (pString == NULL)
return;
Delay = (gEeprom.DTMF_PRELOAD_TIME < 200) ? 200 : gEeprom.DTMF_PRELOAD_TIME;
if (gEeprom.DTMF_SIDE_TONE)
{ // the user will also hear the transmitted tones
AUDIO_AudioPathOn();
gEnableSpeaker = true;
}
SYSTEM_DelayMs(Delay);
BK4819_EnterDTMF_TX(gEeprom.DTMF_SIDE_TONE);
BK4819_PlayDTMFString(
pString,
1,
gEeprom.DTMF_FIRST_CODE_PERSIST_TIME,
gEeprom.DTMF_HASH_CODE_PERSIST_TIME,
gEeprom.DTMF_CODE_PERSIST_TIME,
gEeprom.DTMF_CODE_INTERVAL_TIME);
AUDIO_AudioPathOff();
gEnableSpeaker = false;
BK4819_ExitDTMF_TX(false);
}

119
app/dtmf.h Normal file
View File

@@ -0,0 +1,119 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef DTMF_H
#define DTMF_H
#include <stdbool.h>
#include <stdint.h>
#define MAX_DTMF_CONTACTS 16
enum DTMF_State_t {
DTMF_STATE_0 = 0,
DTMF_STATE_TX_SUCC,
DTMF_STATE_CALL_OUT_RSP
};
typedef enum DTMF_State_t DTMF_State_t;
enum DTMF_CallState_t {
DTMF_CALL_STATE_NONE = 0,
DTMF_CALL_STATE_CALL_OUT,
DTMF_CALL_STATE_RECEIVED,
DTMF_CALL_STATE_RECEIVED_STAY
};
enum DTMF_DecodeResponse_t {
DTMF_DEC_RESPONSE_NONE = 0,
DTMF_DEC_RESPONSE_RING,
DTMF_DEC_RESPONSE_REPLY,
DTMF_DEC_RESPONSE_BOTH
};
typedef enum DTMF_CallState_t DTMF_CallState_t;
enum DTMF_ReplyState_t {
DTMF_REPLY_NONE = 0,
DTMF_REPLY_ANI,
DTMF_REPLY_AB,
DTMF_REPLY_AAAAA
};
typedef enum DTMF_ReplyState_t DTMF_ReplyState_t;
enum DTMF_CallMode_t {
DTMF_CALL_MODE_NOT_GROUP = 0,
DTMF_CALL_MODE_GROUP,
DTMF_CALL_MODE_DTMF
};
enum { // seconds
DTMF_HOLD_MIN = 5,
DTMF_HOLD_MAX = 60
};
typedef enum DTMF_CallMode_t DTMF_CallMode_t;
extern char gDTMF_String[15];
extern char gDTMF_InputBox[15];
extern uint8_t gDTMF_InputBox_Index;
extern bool gDTMF_InputMode;
extern uint8_t gDTMF_PreviousIndex;
extern char gDTMF_RX_live[20];
extern uint8_t gDTMF_RX_live_timeout;
extern DTMF_ReplyState_t gDTMF_ReplyState;
bool DTMF_ValidateCodes(char *pCode, const unsigned int size);
char DTMF_GetCharacter(const unsigned int code);
void DTMF_clear_input_box(void);
void DTMF_Append(const char code);
void DTMF_Reply(void);
void DTMF_SendEndOfTransmission(void);
#ifdef ENABLE_DTMF_CALLING
extern char gDTMF_RX[17];
extern uint8_t gDTMF_RX_index;
extern uint8_t gDTMF_RX_timeout;
extern bool gDTMF_RX_pending;
extern bool gIsDtmfContactValid;
extern char gDTMF_ID[4];
extern char gDTMF_Caller[4];
extern char gDTMF_Callee[4];
extern DTMF_State_t gDTMF_State;
extern uint8_t gDTMF_DecodeRingCountdown_500ms;
extern uint8_t gDTMF_chosen_contact;
extern uint8_t gDTMF_auto_reset_time_500ms;
extern DTMF_CallState_t gDTMF_CallState;
extern DTMF_CallMode_t gDTMF_CallMode;
extern bool gDTMF_IsTx;
extern uint8_t gDTMF_TxStopCountdown_500ms;
void DTMF_clear_RX(void);
DTMF_CallMode_t DTMF_CheckGroupCall(const char *pDTMF, const unsigned int size);
bool DTMF_GetContact(const int Index, char *pContact);
bool DTMF_FindContact(const char *pContact, char *pResult);
void DTMF_HandleRequest(void);
#endif
#endif

66
app/flashlight.c Normal file
View File

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

23
app/flashlight.h Normal file
View File

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

605
app/fm.c Normal file
View File

@@ -0,0 +1,605 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef ENABLE_FMRADIO
#include <string.h>
#include "app/action.h"
#include "app/fm.h"
#include "app/generic.h"
#include "audio.h"
#include "bsp/dp32g030/gpio.h"
#include "driver/bk1080.h"
#include "driver/eeprom.h"
#include "driver/gpio.h"
#include "functions.h"
#include "misc.h"
#include "settings.h"
#include "ui/inputbox.h"
#include "ui/ui.h"
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
#endif
uint16_t gFM_Channels[20];
bool gFmRadioMode;
uint8_t gFmRadioCountdown_500ms;
volatile uint16_t gFmPlayCountdown_10ms;
volatile int8_t gFM_ScanState;
bool gFM_AutoScan;
uint8_t gFM_ChannelPosition;
bool gFM_FoundFrequency;
bool gFM_AutoScan;
uint16_t gFM_RestoreCountdown_10ms;
const uint8_t BUTTON_STATE_PRESSED = 1 << 0;
const uint8_t BUTTON_STATE_HELD = 1 << 1;
const uint8_t BUTTON_EVENT_PRESSED = BUTTON_STATE_PRESSED;
const uint8_t BUTTON_EVENT_HELD = BUTTON_STATE_PRESSED | BUTTON_STATE_HELD;
const uint8_t BUTTON_EVENT_SHORT = 0;
const uint8_t BUTTON_EVENT_LONG = BUTTON_STATE_HELD;
static void Key_FUNC(KEY_Code_t Key, uint8_t state);
bool FM_CheckValidChannel(uint8_t Channel)
{
return Channel < ARRAY_SIZE(gFM_Channels) &&
gFM_Channels[Channel] >= BK1080_GetFreqLoLimit(gEeprom.FM_Band) &&
gFM_Channels[Channel] < BK1080_GetFreqHiLimit(gEeprom.FM_Band);
}
uint8_t FM_FindNextChannel(uint8_t Channel, uint8_t Direction)
{
for (unsigned i = 0; i < ARRAY_SIZE(gFM_Channels); i++) {
if (Channel == 0xFF)
Channel = ARRAY_SIZE(gFM_Channels) - 1;
else if (Channel >= ARRAY_SIZE(gFM_Channels))
Channel = 0;
if (FM_CheckValidChannel(Channel))
return Channel;
Channel += Direction;
}
return 0xFF;
}
int FM_ConfigureChannelState(void)
{
gEeprom.FM_FrequencyPlaying = gEeprom.FM_SelectedFrequency;
if (gEeprom.FM_IsMrMode) {
const uint8_t Channel = FM_FindNextChannel(gEeprom.FM_SelectedChannel, FM_CHANNEL_UP);
if (Channel == 0xFF) {
gEeprom.FM_IsMrMode = false;
return -1;
}
gEeprom.FM_SelectedChannel = Channel;
gEeprom.FM_FrequencyPlaying = gFM_Channels[Channel];
}
return 0;
}
void FM_TurnOff(void)
{
gFmRadioMode = false;
gFM_ScanState = FM_SCAN_OFF;
gFM_RestoreCountdown_10ms = 0;
AUDIO_AudioPathOff();
gEnableSpeaker = false;
BK1080_Init0();
gUpdateStatus = true;
}
void FM_EraseChannels(void)
{
uint8_t Template[8];
memset(Template, 0xFF, sizeof(Template));
for (unsigned i = 0; i < 5; i++)
EEPROM_WriteBuffer(0x0E40 + (i * 8), Template);
memset(gFM_Channels, 0xFF, sizeof(gFM_Channels));
}
void FM_Tune(uint16_t Frequency, int8_t Step, bool bFlag)
{
AUDIO_AudioPathOff();
gEnableSpeaker = false;
gFmPlayCountdown_10ms = (gFM_ScanState == FM_SCAN_OFF) ? fm_play_countdown_noscan_10ms : fm_play_countdown_scan_10ms;
gScheduleFM = false;
gFM_FoundFrequency = false;
gAskToSave = false;
gAskToDelete = false;
gEeprom.FM_FrequencyPlaying = Frequency;
if (!bFlag) {
Frequency += Step;
if (Frequency < BK1080_GetFreqLoLimit(gEeprom.FM_Band))
Frequency = BK1080_GetFreqHiLimit(gEeprom.FM_Band);
else if (Frequency > BK1080_GetFreqHiLimit(gEeprom.FM_Band))
Frequency = BK1080_GetFreqLoLimit(gEeprom.FM_Band);
gEeprom.FM_FrequencyPlaying = Frequency;
}
gFM_ScanState = Step;
BK1080_SetFrequency(gEeprom.FM_FrequencyPlaying, gEeprom.FM_Band/*, gEeprom.FM_Space*/);
}
void FM_PlayAndUpdate(void)
{
gFM_ScanState = FM_SCAN_OFF;
if (gFM_AutoScan) {
gEeprom.FM_IsMrMode = true;
gEeprom.FM_SelectedChannel = 0;
}
FM_ConfigureChannelState();
BK1080_SetFrequency(gEeprom.FM_FrequencyPlaying, gEeprom.FM_Band/*, gEeprom.FM_Space*/);
SETTINGS_SaveFM();
gFmPlayCountdown_10ms = 0;
gScheduleFM = false;
gAskToSave = false;
AUDIO_AudioPathOn();
gEnableSpeaker = true;
}
int FM_CheckFrequencyLock(uint16_t Frequency, uint16_t LowerLimit)
{
int ret = -1;
const uint16_t Test2 = BK1080_ReadRegister(BK1080_REG_07);
// 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) {
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;
return ret;
}
static void Key_DIGITS(KEY_Code_t Key, uint8_t state)
{
enum { STATE_FREQ_MODE, STATE_MR_MODE, STATE_SAVE };
if (state == BUTTON_EVENT_SHORT && !gWasFKeyPressed) {
uint8_t State;
if (gAskToDelete) {
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
if (gAskToSave) {
State = STATE_SAVE;
}
else {
if (gFM_ScanState != FM_SCAN_OFF) {
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
State = gEeprom.FM_IsMrMode ? STATE_MR_MODE : STATE_FREQ_MODE;
}
INPUTBOX_Append(Key);
gRequestDisplayScreen = DISPLAY_FM;
if (State == STATE_FREQ_MODE) {
if (gInputBoxIndex == 1) {
if (gInputBox[0] > 1) {
gInputBox[1] = gInputBox[0];
gInputBox[0] = 0;
gInputBoxIndex = 2;
}
}
else if (gInputBoxIndex > 3) {
uint32_t Frequency;
gInputBoxIndex = 0;
Frequency = StrToUL(INPUTBOX_GetAscii());
if (Frequency < BK1080_GetFreqLoLimit(gEeprom.FM_Band) || BK1080_GetFreqHiLimit(gEeprom.FM_Band) < Frequency) {
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
gRequestDisplayScreen = DISPLAY_FM;
return;
}
gEeprom.FM_SelectedFrequency = (uint16_t)Frequency;
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
gEeprom.FM_FrequencyPlaying = gEeprom.FM_SelectedFrequency;
BK1080_SetFrequency(gEeprom.FM_FrequencyPlaying, gEeprom.FM_Band/*, gEeprom.FM_Space*/);
gRequestSaveFM = true;
return;
}
}
else if (gInputBoxIndex == 2) {
uint8_t Channel;
gInputBoxIndex = 0;
Channel = ((gInputBox[0] * 10) + gInputBox[1]) - 1;
if (State == STATE_MR_MODE) {
if (FM_CheckValidChannel(Channel)) {
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
gEeprom.FM_SelectedChannel = Channel;
gEeprom.FM_FrequencyPlaying = gFM_Channels[Channel];
BK1080_SetFrequency(gEeprom.FM_FrequencyPlaying, gEeprom.FM_Band/*, gEeprom.FM_Space*/);
gRequestSaveFM = true;
return;
}
}
else if (Channel < 20) {
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
gRequestDisplayScreen = DISPLAY_FM;
gInputBoxIndex = 0;
gFM_ChannelPosition = Channel;
return;
}
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
}
else
Key_FUNC(Key, state);
}
static void Key_FUNC(KEY_Code_t Key, uint8_t state)
{
if (state == BUTTON_EVENT_SHORT || state == BUTTON_EVENT_HELD) {
bool autoScan = gWasFKeyPressed || (state == BUTTON_EVENT_HELD);
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
gWasFKeyPressed = false;
gUpdateStatus = true;
gRequestDisplayScreen = DISPLAY_FM;
switch (Key) {
case KEY_0:
ACTION_FM();
break;
case KEY_1:
gEeprom.FM_Band++;
gRequestSaveFM = true;
break;
// case KEY_2:
// gEeprom.FM_Space = (gEeprom.FM_Space + 1) % 3;
// gRequestSaveFM = true;
// break;
case KEY_3:
gEeprom.FM_IsMrMode = !gEeprom.FM_IsMrMode;
if (!FM_ConfigureChannelState()) {
BK1080_SetFrequency(gEeprom.FM_FrequencyPlaying, gEeprom.FM_Band/*, gEeprom.FM_Space*/);
gRequestSaveFM = true;
}
else
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
break;
case KEY_STAR:
ACTION_Scan(autoScan);
break;
default:
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
break;
}
}
}
static void Key_EXIT(uint8_t state)
{
if (state != BUTTON_EVENT_SHORT)
return;
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
if (gFM_ScanState == FM_SCAN_OFF) {
if (gInputBoxIndex == 0) {
if (!gAskToSave && !gAskToDelete) {
ACTION_FM();
return;
}
gAskToSave = false;
gAskToDelete = false;
}
else {
gInputBox[--gInputBoxIndex] = 10;
if (gInputBoxIndex) {
if (gInputBoxIndex != 1) {
gRequestDisplayScreen = DISPLAY_FM;
return;
}
if (gInputBox[0] != 0) {
gRequestDisplayScreen = DISPLAY_FM;
return;
}
}
gInputBoxIndex = 0;
}
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_CANCEL;
#endif
}
else {
FM_PlayAndUpdate();
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_SCANNING_STOP;
#endif
}
gRequestDisplayScreen = DISPLAY_FM;
}
static void Key_MENU(uint8_t state)
{
if (state != BUTTON_EVENT_SHORT)
return;
gRequestDisplayScreen = DISPLAY_FM;
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
if (gFM_ScanState == FM_SCAN_OFF) {
if (!gEeprom.FM_IsMrMode) {
if (gAskToSave) {
gFM_Channels[gFM_ChannelPosition] = gEeprom.FM_FrequencyPlaying;
gRequestSaveFM = true;
}
gAskToSave = !gAskToSave;
}
else {
if (gAskToDelete) {
gFM_Channels[gEeprom.FM_SelectedChannel] = 0xFFFF;
FM_ConfigureChannelState();
BK1080_SetFrequency(gEeprom.FM_FrequencyPlaying, gEeprom.FM_Band/*, gEeprom.FM_Space*/);
gRequestSaveFM = true;
}
gAskToDelete = !gAskToDelete;
}
}
else {
if (gFM_AutoScan || !gFM_FoundFrequency) {
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
gInputBoxIndex = 0;
return;
}
if (gAskToSave) {
gFM_Channels[gFM_ChannelPosition] = gEeprom.FM_FrequencyPlaying;
gRequestSaveFM = true;
}
gAskToSave = !gAskToSave;
}
}
static void Key_UP_DOWN(uint8_t state, int8_t Step)
{
if (state == BUTTON_EVENT_PRESSED) {
if (gInputBoxIndex) {
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
} else if (gInputBoxIndex || state!=BUTTON_EVENT_HELD) {
return;
}
if (gAskToSave) {
gRequestDisplayScreen = DISPLAY_FM;
gFM_ChannelPosition = NUMBER_AddWithWraparound(gFM_ChannelPosition, Step, 0, 19);
return;
}
if (gFM_ScanState != FM_SCAN_OFF) {
if (gFM_AutoScan) {
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
FM_Tune(gEeprom.FM_FrequencyPlaying, Step, false);
gRequestDisplayScreen = DISPLAY_FM;
return;
}
if (gEeprom.FM_IsMrMode) {
const uint8_t Channel = FM_FindNextChannel(gEeprom.FM_SelectedChannel + Step, Step);
if (Channel == 0xFF || gEeprom.FM_SelectedChannel == Channel)
goto Bail;
gEeprom.FM_SelectedChannel = Channel;
gEeprom.FM_FrequencyPlaying = gFM_Channels[Channel];
}
else {
uint16_t Frequency = gEeprom.FM_SelectedFrequency + Step;
if (Frequency < BK1080_GetFreqLoLimit(gEeprom.FM_Band))
Frequency = BK1080_GetFreqHiLimit(gEeprom.FM_Band);
else if (Frequency > BK1080_GetFreqHiLimit(gEeprom.FM_Band))
Frequency = BK1080_GetFreqLoLimit(gEeprom.FM_Band);
gEeprom.FM_FrequencyPlaying = Frequency;
gEeprom.FM_SelectedFrequency = gEeprom.FM_FrequencyPlaying;
}
gRequestSaveFM = true;
Bail:
BK1080_SetFrequency(gEeprom.FM_FrequencyPlaying, gEeprom.FM_Band/*, gEeprom.FM_Space*/);
gRequestDisplayScreen = DISPLAY_FM;
}
void FM_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
{
uint8_t state = bKeyPressed + 2 * bKeyHeld;
switch (Key) {
case KEY_0...KEY_9:
Key_DIGITS(Key, state);
break;
case KEY_STAR:
Key_FUNC(Key, state);
break;
case KEY_MENU:
Key_MENU(state);
break;
case KEY_UP:
Key_UP_DOWN(state, 1);
break;
case KEY_DOWN:
Key_UP_DOWN(state, -1);
break;;
case KEY_EXIT:
Key_EXIT(state);
break;
case KEY_F:
GENERIC_Key_F(bKeyPressed, bKeyHeld);
break;
case KEY_PTT:
GENERIC_Key_PTT(bKeyPressed);
break;
default:
if (!bKeyHeld && bKeyPressed)
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
break;
}
}
void FM_Play(void)
{
if (!FM_CheckFrequencyLock(gEeprom.FM_FrequencyPlaying, BK1080_GetFreqLoLimit(gEeprom.FM_Band))) {
if (!gFM_AutoScan) {
gFmPlayCountdown_10ms = 0;
gFM_FoundFrequency = true;
if (!gEeprom.FM_IsMrMode)
gEeprom.FM_SelectedFrequency = gEeprom.FM_FrequencyPlaying;
AUDIO_AudioPathOn();
gEnableSpeaker = true;
GUI_SelectNextDisplay(DISPLAY_FM);
return;
}
if (gFM_ChannelPosition < 20)
gFM_Channels[gFM_ChannelPosition++] = gEeprom.FM_FrequencyPlaying;
if (gFM_ChannelPosition >= 20) {
FM_PlayAndUpdate();
GUI_SelectNextDisplay(DISPLAY_FM);
return;
}
}
if (gFM_AutoScan && gEeprom.FM_FrequencyPlaying >= BK1080_GetFreqHiLimit(1))
FM_PlayAndUpdate();
else
FM_Tune(gEeprom.FM_FrequencyPlaying, gFM_ScanState, false);
GUI_SelectNextDisplay(DISPLAY_FM);
}
void FM_Start(void)
{
gDualWatchActive = false;
gFmRadioMode = true;
gFM_ScanState = FM_SCAN_OFF;
gFM_RestoreCountdown_10ms = 0;
BK1080_Init(gEeprom.FM_FrequencyPlaying, gEeprom.FM_Band/*, gEeprom.FM_Space*/);
AUDIO_AudioPathOn();
gEnableSpeaker = true;
gUpdateStatus = true;
}
#endif

61
app/fm.h Normal file
View File

@@ -0,0 +1,61 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef APP_FM_H
#define APP_FM_H
#ifdef ENABLE_FMRADIO
#include "driver/keyboard.h"
#define FM_CHANNEL_UP 0x01
#define FM_CHANNEL_DOWN 0xFF
enum {
FM_SCAN_OFF = 0U,
};
extern uint16_t gFM_Channels[20];
extern bool gFmRadioMode;
extern uint8_t gFmRadioCountdown_500ms;
extern volatile uint16_t gFmPlayCountdown_10ms;
extern volatile int8_t gFM_ScanState;
extern bool gFM_AutoScan;
extern uint8_t gFM_ChannelPosition;
// Doubts about whether this should be signed or not
extern uint16_t gFM_FrequencyDeviation;
extern bool gFM_FoundFrequency;
extern uint16_t gFM_RestoreCountdown_10ms;
bool FM_CheckValidChannel(uint8_t Channel);
// returns first valid channel starting at Channel
uint8_t FM_FindNextChannel(uint8_t Channel, uint8_t Direction);
int FM_ConfigureChannelState(void);
void FM_TurnOff(void);
void FM_EraseChannels(void);
void FM_Tune(uint16_t Frequency, int8_t Step, bool bFlag);
void FM_PlayAndUpdate(void);
int FM_CheckFrequencyLock(uint16_t Frequency, uint16_t LowerLimit);
void FM_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld);
void FM_Play(void);
void FM_Start(void);
#endif
#endif

225
app/generic.c Normal file
View File

@@ -0,0 +1,225 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include "app/app.h"
#include "app/chFrScanner.h"
#include "app/common.h"
#ifdef ENABLE_FMRADIO
#include "app/fm.h"
#endif
#include "app/generic.h"
#include "app/menu.h"
#include "app/scanner.h"
#include "audio.h"
#include "driver/keyboard.h"
#include "dtmf.h"
#include "external/printf/printf.h"
#include "functions.h"
#include "misc.h"
#include "settings.h"
#include "ui/inputbox.h"
#include "ui/ui.h"
void GENERIC_Key_F(bool bKeyPressed, bool bKeyHeld)
{
if (gInputBoxIndex > 0) {
if (!bKeyHeld && bKeyPressed) // short pressed
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
if (bKeyHeld || !bKeyPressed) { // held or released
if (bKeyHeld || bKeyPressed) { // held or pressed (cannot be held and not pressed I guess, so it checks only if HELD?)
if (!bKeyHeld) // won't ever pass
return;
if (!bKeyPressed) // won't ever pass
return;
COMMON_KeypadLockToggle();
}
else { // released
#ifdef ENABLE_FMRADIO
if ((gFmRadioMode || gScreenToDisplay != DISPLAY_MAIN) && gScreenToDisplay != DISPLAY_FM)
return;
#else
if (gScreenToDisplay != DISPLAY_MAIN)
return;
#endif
gWasFKeyPressed = !gWasFKeyPressed; // toggle F function
if (gWasFKeyPressed)
gKeyInputCountdown = key_input_timeout_500ms;
#ifdef ENABLE_VOICE
if (!gWasFKeyPressed)
gAnotherVoiceID = VOICE_ID_CANCEL;
#endif
gUpdateStatus = true;
}
}
else { // short pressed
#ifdef ENABLE_FMRADIO
if (gScreenToDisplay != DISPLAY_FM)
#endif
{
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
return;
}
#ifdef ENABLE_FMRADIO
if (gFM_ScanState == FM_SCAN_OFF) { // not scanning
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
return;
}
#endif
gBeepToPlay = BEEP_440HZ_500MS;
gPttWasReleased = true;
}
}
void GENERIC_Key_PTT(bool bKeyPressed)
{
gInputBoxIndex = 0;
if (!bKeyPressed || SerialConfigInProgress())
{ // PTT released
if (gCurrentFunction == FUNCTION_TRANSMIT) {
// we are transmitting .. stop
if (gFlagEndTransmission) {
FUNCTION_Select(FUNCTION_FOREGROUND);
}
else {
APP_EndTransmission();
if (gEeprom.REPEATER_TAIL_TONE_ELIMINATION == 0)
FUNCTION_Select(FUNCTION_FOREGROUND);
else
gRTTECountdown_10ms = gEeprom.REPEATER_TAIL_TONE_ELIMINATION * 10;
}
gFlagEndTransmission = false;
#ifdef ENABLE_VOX
gVOX_NoiseDetected = false;
#endif
RADIO_SetVfoState(VFO_STATE_NORMAL);
if (gScreenToDisplay != DISPLAY_MENU) // 1of11 .. don't close the menu
gRequestDisplayScreen = DISPLAY_MAIN;
}
return;
}
// PTT pressed
if (SCANNER_IsScanning()) {
SCANNER_Stop(); // CTCSS/CDCSS scanning .. stop
goto cancel_tx;
}
if (gScanStateDir != SCAN_OFF) {
CHFRSCANNER_Stop(); // frequency/channel scanning . .stop
goto cancel_tx;
}
#ifdef ENABLE_FMRADIO
if (gFM_ScanState != FM_SCAN_OFF) { // FM radio is scanning .. stop
FM_PlayAndUpdate();
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_SCANNING_STOP;
#endif
gRequestDisplayScreen = DISPLAY_FM;
goto cancel_tx;
}
#endif
#ifdef ENABLE_FMRADIO
if (gScreenToDisplay == DISPLAY_FM)
goto start_tx; // listening to the FM radio .. start TX'ing
#endif
if (gCurrentFunction == FUNCTION_TRANSMIT && gRTTECountdown_10ms == 0) {// already transmitting
gInputBoxIndex = 0;
return;
}
if (gScreenToDisplay != DISPLAY_MENU) // 1of11 .. don't close the menu
gRequestDisplayScreen = DISPLAY_MAIN;
if (!gDTMF_InputMode && gDTMF_InputBox_Index == 0)
goto start_tx; // wasn't entering a DTMF code .. start TX'ing (maybe)
// was entering a DTMF string
if (gDTMF_InputBox_Index > 0 || gDTMF_PreviousIndex > 0) { // going to transmit a DTMF string
if (gDTMF_InputBox_Index == 0 && gDTMF_PreviousIndex > 0)
gDTMF_InputBox_Index = gDTMF_PreviousIndex; // use the previous DTMF string
if (gDTMF_InputBox_Index < sizeof(gDTMF_InputBox))
gDTMF_InputBox[gDTMF_InputBox_Index] = 0; // NULL term the string
#ifdef ENABLE_DTMF_CALLING
// append our DTMF ID to the inputted DTMF code -
// IF the user inputted code is exactly 3 digits long and D-DCD is enabled
if (gDTMF_InputBox_Index == 3 && gTxVfo->DTMF_DECODING_ENABLE > 0)
gDTMF_CallMode = DTMF_CheckGroupCall(gDTMF_InputBox, 3);
else
gDTMF_CallMode = DTMF_CALL_MODE_DTMF;
gDTMF_State = DTMF_STATE_0;
#endif
// remember the DTMF string
gDTMF_PreviousIndex = gDTMF_InputBox_Index;
strcpy(gDTMF_String, gDTMF_InputBox);
gDTMF_ReplyState = DTMF_REPLY_ANI;
}
DTMF_clear_input_box();
start_tx:
// request start TX
gFlagPrepareTX = true;
goto done;
cancel_tx:
if (gPttIsPressed) {
gPttWasPressed = true;
}
done:
gPttDebounceCounter = 0;
if (gScreenToDisplay != DISPLAY_MENU
#ifdef ENABLE_FMRADIO
&& gRequestDisplayScreen != DISPLAY_FM
#endif
) {
// 1of11 .. don't close the menu
gRequestDisplayScreen = DISPLAY_MAIN;
}
gUpdateStatus = true;
gUpdateDisplay = true;
}

26
app/generic.h Normal file
View File

@@ -0,0 +1,26 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef APP_GENERIC_H
#define APP_GENERIC_H
#include <stdbool.h>
void GENERIC_Key_F(bool bKeyPressed, bool bKeyHeld);
void GENERIC_Key_PTT(bool bKeyPressed);
#endif

743
app/main.c Normal file
View File

@@ -0,0 +1,743 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include "app/action.h"
#include "app/app.h"
#include "app/chFrScanner.h"
#include "app/common.h"
#ifdef ENABLE_FMRADIO
#include "app/fm.h"
#endif
#include "app/generic.h"
#include "app/main.h"
#include "app/scanner.h"
#ifdef ENABLE_SPECTRUM
#include "app/spectrum.h"
#endif
#include "audio.h"
#include "board.h"
#include "driver/bk4819.h"
#include "dtmf.h"
#include "frequencies.h"
#include "misc.h"
#include "radio.h"
#include "settings.h"
#include "ui/inputbox.h"
#include "ui/ui.h"
#include <stdlib.h>
void toggle_chan_scanlist(void)
{ // toggle the selected channels scanlist setting
if (SCANNER_IsScanning())
return;
if(!IS_MR_CHANNEL(gTxVfo->CHANNEL_SAVE)) {
#ifdef ENABLE_SCAN_RANGES
gScanRangeStart = gScanRangeStart ? 0 : gTxVfo->pRX->Frequency;
gScanRangeStop = gEeprom.VfoInfo[!gEeprom.TX_VFO].freq_config_RX.Frequency;
if(gScanRangeStart > gScanRangeStop)
SWAP(gScanRangeStart, gScanRangeStop);
#endif
return;
}
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);
gVfoConfigureMode = VFO_CONFIGURE;
gFlagResetVfos = true;
}
static void processFKeyFunction(const KEY_Code_t Key, const bool beep)
{
uint8_t Vfo = gEeprom.TX_VFO;
if (gScreenToDisplay == DISPLAY_MENU) {
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
switch (Key) {
case KEY_0:
#ifdef ENABLE_FMRADIO
ACTION_FM();
#endif
break;
case KEY_1:
if (!IS_FREQ_CHANNEL(gTxVfo->CHANNEL_SAVE)) {
gWasFKeyPressed = false;
gUpdateStatus = true;
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
#ifdef ENABLE_COPY_CHAN_TO_VFO
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;
}
#ifdef ENABLE_WIDE_RX
if(gTxVfo->Band == BAND7_470MHz && gTxVfo->pRX->Frequency < _1GHz_in_KHz) {
gTxVfo->pRX->Frequency = _1GHz_in_KHz;
return;
}
#endif
gTxVfo->Band += 1;
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;
gRequestDisplayScreen = DISPLAY_MAIN;
if (beep)
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
break;
case KEY_2:
COMMON_SwitchVFOs();
if (beep)
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
break;
case KEY_3:
COMMON_SwitchVFOMode();
if (beep)
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
break;
case KEY_4:
gWasFKeyPressed = false;
gBackup_CROSS_BAND_RX_TX = gEeprom.CROSS_BAND_RX_TX;
gEeprom.CROSS_BAND_RX_TX = CROSS_BAND_OFF;
gUpdateStatus = true;
if (beep)
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
SCANNER_Start(false);
gRequestDisplayScreen = DISPLAY_SCANNER;
break;
case KEY_5:
if(beep) {
#ifdef ENABLE_NOAA
if (!IS_NOAA_CHANNEL(gTxVfo->CHANNEL_SAVE)) {
gEeprom.ScreenChannel[Vfo] = gEeprom.NoaaChannel[gEeprom.TX_VFO];
}
else {
gEeprom.ScreenChannel[Vfo] = gEeprom.FreqChannel[gEeprom.TX_VFO];
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_FREQUENCY_MODE;
#endif
}
gRequestSaveVFO = true;
gVfoConfigureMode = VFO_CONFIGURE_RELOAD;
#elif defined(ENABLE_SPECTRUM)
APP_RunSpectrum();
gRequestDisplayScreen = DISPLAY_MAIN;
#endif
}
else {
#ifdef ENABLE_VOX
toggle_chan_scanlist();
#endif
}
break;
case KEY_6:
ACTION_Power();
break;
case KEY_7:
#ifdef ENABLE_VOX
ACTION_Vox();
#else
toggle_chan_scanlist();
#endif
break;
case KEY_8:
gTxVfo->FrequencyReverse = gTxVfo->FrequencyReverse == false;
gRequestSaveChannel = 1;
break;
case KEY_9:
if (RADIO_CheckValidChannel(gEeprom.CHAN_1_CALL, false, 0)) {
gEeprom.MrChannel[Vfo] = gEeprom.CHAN_1_CALL;
gEeprom.ScreenChannel[Vfo] = gEeprom.CHAN_1_CALL;
#ifdef ENABLE_VOICE
AUDIO_SetVoiceID(0, VOICE_ID_CHANNEL_MODE);
AUDIO_SetDigitVoice(1, gEeprom.CHAN_1_CALL + 1);
gAnotherVoiceID = (VOICE_ID_t)0xFE;
#endif
gRequestSaveVFO = true;
gVfoConfigureMode = VFO_CONFIGURE_RELOAD;
break;
}
if (beep)
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
break;
default:
gUpdateStatus = true;
gWasFKeyPressed = false;
if (beep)
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
break;
}
}
static void MAIN_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
{
if (bKeyHeld) { // key held down
if (bKeyPressed) {
if (gScreenToDisplay == DISPLAY_MAIN) {
if (gInputBoxIndex > 0) { // delete any inputted chars
gInputBoxIndex = 0;
gRequestDisplayScreen = DISPLAY_MAIN;
}
gWasFKeyPressed = false;
gUpdateStatus = true;
processFKeyFunction(Key, false);
}
}
return;
}
if (bKeyPressed)
{ // key is pressed
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL; // beep when key is pressed
return; // don't use the key till it's released
}
if (!gWasFKeyPressed) { // F-key wasn't pressed
const uint8_t Vfo = gEeprom.TX_VFO;
gKeyInputCountdown = key_input_timeout_500ms;
INPUTBOX_Append(Key);
gRequestDisplayScreen = DISPLAY_MAIN;
if (IS_MR_CHANNEL(gTxVfo->CHANNEL_SAVE)) { // user is entering channel number
if (gInputBoxIndex != 3) {
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
gRequestDisplayScreen = DISPLAY_MAIN;
return;
}
gInputBoxIndex = 0;
const uint16_t Channel = ((gInputBox[0] * 100) + (gInputBox[1] * 10) + gInputBox[2]) - 1;
if (!RADIO_CheckValidChannel(Channel, false, 0)) {
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
gEeprom.MrChannel[Vfo] = (uint8_t)Channel;
gEeprom.ScreenChannel[Vfo] = (uint8_t)Channel;
gRequestSaveVFO = true;
gVfoConfigureMode = VFO_CONFIGURE_RELOAD;
return;
}
// #ifdef ENABLE_NOAA
// if (!IS_NOAA_CHANNEL(gTxVfo->CHANNEL_SAVE))
// #endif
if (IS_FREQ_CHANNEL(gTxVfo->CHANNEL_SAVE))
{ // user is entering a frequency
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
bool isGigaF = gTxVfo->pRX->Frequency >= _1GHz_in_KHz;
if (gInputBoxIndex < 6 + isGigaF) {
return;
}
gInputBoxIndex = 0;
uint32_t Frequency = StrToUL(INPUTBOX_GetAscii()) * 100;
// clamp the frequency entered to some valid value
if (Frequency < frequencyBandTable[0].lower) {
Frequency = frequencyBandTable[0].lower;
}
else if (Frequency >= BX4819_band1.upper && Frequency < BX4819_band2.lower) {
const uint32_t center = (BX4819_band1.upper + BX4819_band2.lower) / 2;
Frequency = (Frequency < center) ? BX4819_band1.upper : BX4819_band2.lower;
}
else if (Frequency > frequencyBandTable[BAND_N_ELEM - 1].upper) {
Frequency = frequencyBandTable[BAND_N_ELEM - 1].upper;
}
const FREQUENCY_Band_t band = FREQUENCY_GetBand(Frequency);
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;
}
#ifdef ENABLE_NOAA
else
if (IS_NOAA_CHANNEL(gTxVfo->CHANNEL_SAVE))
{ // user is entering NOAA channel
if (gInputBoxIndex != 2) {
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
gRequestDisplayScreen = DISPLAY_MAIN;
return;
}
gInputBoxIndex = 0;
uint8_t Channel = (gInputBox[0] * 10) + gInputBox[1];
if (Channel >= 1 && Channel <= ARRAY_SIZE(NoaaFrequencyTable)) {
Channel += NOAA_CHANNEL_FIRST;
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
gEeprom.NoaaChannel[Vfo] = Channel;
gEeprom.ScreenChannel[Vfo] = Channel;
gRequestSaveVFO = true;
gVfoConfigureMode = VFO_CONFIGURE_RELOAD;
return;
}
}
#endif
gRequestDisplayScreen = DISPLAY_MAIN;
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
gWasFKeyPressed = false;
gUpdateStatus = true;
processFKeyFunction(Key, true);
}
static void MAIN_Key_EXIT(bool bKeyPressed, bool bKeyHeld)
{
if (!bKeyHeld && bKeyPressed) { // exit key pressed
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
#ifdef ENABLE_DTMF_CALLING
if (gDTMF_CallState != DTMF_CALL_STATE_NONE && gCurrentFunction != FUNCTION_TRANSMIT)
{ // clear CALL mode being displayed
gDTMF_CallState = DTMF_CALL_STATE_NONE;
gUpdateDisplay = true;
return;
}
#endif
#ifdef ENABLE_FMRADIO
if (!gFmRadioMode)
#endif
{
if (gScanStateDir == SCAN_OFF) {
if (gInputBoxIndex == 0)
return;
gInputBox[--gInputBoxIndex] = 10;
gKeyInputCountdown = key_input_timeout_500ms;
#ifdef ENABLE_VOICE
if (gInputBoxIndex == 0)
gAnotherVoiceID = VOICE_ID_CANCEL;
#endif
}
else {
gScanKeepResult = false;
CHFRSCANNER_Stop();
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_SCANNING_STOP;
#endif
}
gRequestDisplayScreen = DISPLAY_MAIN;
return;
}
#ifdef ENABLE_FMRADIO
ACTION_FM();
#endif
return;
}
if (bKeyHeld && bKeyPressed) { // exit key held down
if (gInputBoxIndex > 0 || gDTMF_InputBox_Index > 0 || gDTMF_InputMode)
{ // cancel key input mode (channel/frequency entry)
gDTMF_InputMode = false;
gDTMF_InputBox_Index = 0;
memset(gDTMF_String, 0, sizeof(gDTMF_String));
gInputBoxIndex = 0;
gRequestDisplayScreen = DISPLAY_MAIN;
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
}
}
}
static void MAIN_Key_MENU(const bool bKeyPressed, const bool bKeyHeld)
{
if (bKeyPressed && !bKeyHeld) // menu key pressed
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
if (bKeyHeld) { // menu key held down (long press)
if (bKeyPressed) { // long press MENU key
gWasFKeyPressed = false;
if (gScreenToDisplay == DISPLAY_MAIN) {
if (gInputBoxIndex > 0) { // delete any inputted chars
gInputBoxIndex = 0;
gRequestDisplayScreen = DISPLAY_MAIN;
}
gWasFKeyPressed = false;
gUpdateStatus = true;
ACTION_Handle(KEY_MENU, bKeyPressed, bKeyHeld);
}
}
return;
}
if (!bKeyPressed && !gDTMF_InputMode) { // menu key released
const bool bFlag = !gInputBoxIndex;
gInputBoxIndex = 0;
if (bFlag) {
if (gScanStateDir != SCAN_OFF) {
CHFRSCANNER_Stop();
return;
}
gFlagRefreshSetting = true;
gRequestDisplayScreen = DISPLAY_MENU;
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_MENU;
#endif
}
else {
gRequestDisplayScreen = DISPLAY_MAIN;
}
}
}
static void MAIN_Key_STAR(bool bKeyPressed, bool bKeyHeld)
{
if (gCurrentFunction == FUNCTION_TRANSMIT)
return;
if (gInputBoxIndex) {
if (!bKeyHeld && bKeyPressed)
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
if (bKeyHeld && !gWasFKeyPressed){ // long press
if (!bKeyPressed) // released
return;
ACTION_Scan(false);// toggle scanning
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
return;
}
if (bKeyPressed) { // just pressed
return;
}
// just released
if (!gWasFKeyPressed) // pressed without the F-key
{
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;
memcpy(gDTMF_InputBox, gDTMF_String, MIN(sizeof(gDTMF_InputBox), sizeof(gDTMF_String) - 1));
gDTMF_InputBox_Index = 0;
gDTMF_InputMode = true;
gKeyInputCountdown = key_input_timeout_500ms;
gRequestDisplayScreen = DISPLAY_MAIN;
}
else
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
}
else
{ // with the F-key
gWasFKeyPressed = false;
#ifdef ENABLE_NOAA
if (IS_NOAA_CHANNEL(gTxVfo->CHANNEL_SAVE)) {
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
#endif
// scan the CTCSS/DCS code
gBackup_CROSS_BAND_RX_TX = gEeprom.CROSS_BAND_RX_TX;
gEeprom.CROSS_BAND_RX_TX = CROSS_BAND_OFF;
SCANNER_Start(true);
gRequestDisplayScreen = DISPLAY_SCANNER;
}
gPttWasReleased = true;
gUpdateStatus = true;
}
static void MAIN_Key_UP_DOWN(bool bKeyPressed, bool bKeyHeld, int8_t Direction)
{
uint8_t Channel = gEeprom.ScreenChannel[gEeprom.TX_VFO];
if (bKeyHeld || !bKeyPressed) { // key held or released
if (gInputBoxIndex > 0)
return; // leave if input box active
if (!bKeyPressed) {
if (!bKeyHeld || IS_FREQ_CHANNEL(Channel))
return;
// if released long button press and not in freq mode
#ifdef ENABLE_VOICE
AUDIO_SetDigitVoice(0, gTxVfo->CHANNEL_SAVE + 1); // say channel number
gAnotherVoiceID = (VOICE_ID_t)0xFE;
#endif
return;
}
}
else { // short pressed
if (gInputBoxIndex > 0) {
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
}
if (gScanStateDir == SCAN_OFF) {
#ifdef ENABLE_NOAA
if (!IS_NOAA_CHANNEL(Channel))
#endif
{
uint8_t Next;
if (IS_FREQ_CHANNEL(Channel)) { // step/down in frequency
const uint32_t frequency = APP_SetFrequencyByStep(gTxVfo, Direction);
if (RX_freq_check(frequency) < 0) { // frequency not allowed
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
gTxVfo->freq_config_RX.Frequency = frequency;
BK4819_SetFrequency(frequency);
BK4819_RX_TurnOn();
gRequestSaveChannel = 1;
return;
}
Next = RADIO_FindNextChannel(Channel + Direction, Direction, false, 0);
if (Next == 0xFF)
return;
if (Channel == Next)
return;
gEeprom.MrChannel[gEeprom.TX_VFO] = Next;
gEeprom.ScreenChannel[gEeprom.TX_VFO] = Next;
if (!bKeyHeld) {
#ifdef ENABLE_VOICE
AUDIO_SetDigitVoice(0, Next + 1);
gAnotherVoiceID = (VOICE_ID_t)0xFE;
#endif
}
}
#ifdef ENABLE_NOAA
else {
Channel = NOAA_CHANNEL_FIRST + NUMBER_AddWithWraparound(gEeprom.ScreenChannel[gEeprom.TX_VFO] - NOAA_CHANNEL_FIRST, Direction, 0, 9);
gEeprom.NoaaChannel[gEeprom.TX_VFO] = Channel;
gEeprom.ScreenChannel[gEeprom.TX_VFO] = Channel;
}
#endif
gRequestSaveVFO = true;
gVfoConfigureMode = VFO_CONFIGURE_RELOAD;
return;
}
// jump to the next channel
CHFRSCANNER_Start(false, Direction);
gScanPauseDelayIn_10ms = 1;
gScheduleScanListen = false;
gPttWasReleased = true;
}
void MAIN_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
{
#ifdef ENABLE_FMRADIO
if (gFmRadioMode && Key != KEY_PTT && Key != KEY_EXIT) {
if (!bKeyHeld && bKeyPressed)
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
#endif
if (gDTMF_InputMode && bKeyPressed && !bKeyHeld) {
const char Character = DTMF_GetCharacter(Key);
if (Character != 0xFF)
{ // add key to DTMF string
DTMF_Append(Character);
gKeyInputCountdown = key_input_timeout_500ms;
gRequestDisplayScreen = DISPLAY_MAIN;
gPttWasReleased = true;
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
return;
}
}
// TODO: ???
// if (Key > KEY_PTT)
// {
// Key = KEY_SIDE2; // what's this doing ???
// }
switch (Key) {
case KEY_0...KEY_9:
MAIN_Key_DIGITS(Key, bKeyPressed, bKeyHeld);
break;
case KEY_MENU:
MAIN_Key_MENU(bKeyPressed, bKeyHeld);
break;
case KEY_UP:
MAIN_Key_UP_DOWN(bKeyPressed, bKeyHeld, 1);
break;
case KEY_DOWN:
MAIN_Key_UP_DOWN(bKeyPressed, bKeyHeld, -1);
break;
case KEY_EXIT:
MAIN_Key_EXIT(bKeyPressed, bKeyHeld);
break;
case KEY_STAR:
MAIN_Key_STAR(bKeyPressed, bKeyHeld);
break;
case KEY_F:
GENERIC_Key_F(bKeyPressed, bKeyHeld);
break;
case KEY_PTT:
GENERIC_Key_PTT(bKeyPressed);
break;
default:
if (!bKeyHeld && bKeyPressed)
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
break;
}
}

25
app/main.h Normal file
View File

@@ -0,0 +1,25 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef APP_MAIN_H
#define APP_MAIN_H
#include "driver/keyboard.h"
void MAIN_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld);
#endif

1739
app/menu.c Normal file

File diff suppressed because it is too large Load Diff

38
app/menu.h Normal file
View File

@@ -0,0 +1,38 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef APP_MENU_H
#define APP_MENU_H
#include "driver/keyboard.h"
#ifdef ENABLE_F_CAL_MENU
void writeXtalFreqCal(const int32_t value, const bool update_eeprom);
#endif
extern uint8_t gUnlockAllTxConfCnt;
int MENU_GetLimits(uint8_t menu_id, int32_t *pMin, int32_t *pMax);
void MENU_AcceptSetting(void);
void MENU_ShowCurrentSetting(void);
void MENU_StartCssScan(void);
void MENU_CssScanFound(void);
void MENU_StopCssScan(void);
void MENU_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld);
#endif

333
app/mode.c Normal file
View File

@@ -0,0 +1,333 @@
/* UA1ZBE Custom Firmware - Mode Dispatcher Implementation
*
* Central dispatcher for VFO, POCSAG, Spectrum, and FM modes.
*
* Architecture:
* - VFO mode: use full APP_TimeSlice infrastructure
* - POCSAG mode: use APP_TimeSlice for interrupts but intercept keys
* - Spectrum: blocking loop, returns to VFO
* - FM: uses FM radio subsystem
*/
#include "mode.h"
#include "app/app.h"
#include "app/common.h"
#include "app/display_rssi.h"
#include "driver/bk4819.h"
#include "driver/keyboard.h"
#include "driver/st7565.h"
#include "driver/system.h"
#include "ui/helper.h"
#include "ui/main.h"
#include "misc.h"
#include "radio.h"
#include "settings.h"
#include "functions.h"
#include <string.h>
#include <stdio.h>
#ifdef ENABLE_POCSAG
#include "pocsag/pocsag.h"
#endif
#ifdef ENABLE_SPECTRUM
#include "app/spectrum.h"
#endif
#ifdef ENABLE_FMRADIO
#include "app/fm.h"
#endif
/* === State === */
static op_mode_t s_current_mode = MODE_VFO;
static GUI_DisplayType_t s_saved_display_type;
/* === Mode entry/exit === */
static void mode_enter_vfo(void)
{
RADIO_SetupRegisters(true);
gScreenToDisplay = s_saved_display_type;
gUpdateDisplay = true;
}
static void mode_enter_pocsag(void)
{
#ifdef ENABLE_POCSAG
POCSAG_ConfigureRadio(gRxVfo->freq_config_RX.Frequency);
POCSAG_Init(POCSAG_BAUD_1200);
/* Save current display type and set to INVALID to skip standard key handling */
s_saved_display_type = gScreenToDisplay;
gScreenToDisplay = DISPLAY_INVALID;
ST7565_FillScreen(0x00);
for (int line = 0; line < FRAME_LINES; line++)
memset(gFrameBuffer[line], 0, LCD_WIDTH);
memset(gStatusLine, 0, sizeof(gStatusLine));
#endif
}
static void mode_enter_fm(void)
{
#ifdef ENABLE_FMRADIO
s_saved_display_type = gScreenToDisplay;
gFmRadioMode = false;
#endif
}
static void mode_exit_current(void)
{
switch (s_current_mode) {
case MODE_POCSAG:
#ifdef ENABLE_POCSAG
POCSAG_Stop();
gScreenToDisplay = s_saved_display_type;
#endif
break;
case MODE_FM:
#ifdef ENABLE_FMRADIO
FM_TurnOff();
gFmRadioMode = false;
gScreenToDisplay = s_saved_display_type;
#endif
break;
default:
break;
}
}
/* === Mode switching === */
void MODE_Switch(op_mode_t mode)
{
if (mode == s_current_mode || mode >= MODE_COUNT)
return;
mode_exit_current();
s_current_mode = mode;
switch (mode) {
case MODE_VFO: mode_enter_vfo(); break;
case MODE_POCSAG: mode_enter_pocsag(); break;
case MODE_SPECTRUM: /* Spectrum is blocking */ break;
case MODE_FM: mode_enter_fm(); break;
default: break;
}
gUpdateDisplay = true;
}
op_mode_t MODE_GetCurrent(void)
{
return s_current_mode;
}
void MODE_Init(void)
{
s_current_mode = MODE_VFO;
s_saved_display_type = DISPLAY_MAIN;
mode_enter_vfo();
}
/* === POCSAG display === */
static void pocsag_draw(void)
{
#ifdef ENABLE_POCSAG
ST7565_FillScreen(0x00);
for (int line = 0; line < FRAME_LINES; line++)
memset(gFrameBuffer[line], 0, LCD_WIDTH);
memset(gStatusLine, 0, sizeof(gStatusLine));
char buf[32];
/* Header */
uint32_t baud = POCSAG_GetBaud();
sprintf(buf, "POCSAG %lu", baud);
UI_PrintString(buf, 0, LCD_WIDTH, 0, 10);
/* Status */
const char *state_str = POCSAG_StateString(POCSAG_GetState());
UI_PrintStringSmallNormal(state_str, 0, LCD_WIDTH, 16);
if (POCSAG_SignalDetected())
UI_PrintStringSmallNormal("SIG", 100, LCD_WIDTH, 16);
/* Message count and stats */
sprintf(buf, "Msgs:%d W:%lu", gPocsag.msg_count, gPocsag.total_words);
UI_PrintStringSmallNormal(buf, 0, LCD_WIDTH, 28);
sprintf(buf, "Corr:%lu", gPocsag.corrected_errors);
UI_PrintStringSmallNormal(buf, 0, LCD_WIDTH, 38);
/* RSSI */
sprintf(buf, "%ddBm", RSSI_GetdBm());
UI_PrintStringSmallNormal(buf, 0, LCD_WIDTH, 48);
/* Help */
UI_PrintStringSmallNormal("F=512/1200 X=VFO", 0, LCD_WIDTH, 56);
ST7565_BlitStatusLine();
ST7565_BlitFullScreen();
#endif
}
/* === Key debounce for POCSAG === */
static KEY_Code_t s_last_key = KEY_INVALID;
static uint16_t s_key_debounce = 0;
static KEY_Code_t read_key_debounced(void)
{
KEY_Code_t key = KEYBOARD_Poll();
if (key == s_last_key) {
if (s_key_debounce < 3) {
s_key_debounce++;
return KEY_INVALID;
}
} else {
s_last_key = key;
s_key_debounce = 0;
return KEY_INVALID;
}
return key;
}
/* === Timeslice handlers === */
void MODE_TimeSlice10ms(void)
{
/* Always call standard app processing for interrupts, etc. */
APP_TimeSlice10ms();
/* Mode-specific processing */
switch (s_current_mode) {
case MODE_VFO:
/* VFO display already handled by APP_TimeSlice10ms.
* Add RSSI overlay on top. */
if (gScreenToDisplay == DISPLAY_MAIN) {
RSSI_Draw(95, 0, false);
ST7565_BlitFullScreen();
}
break;
case MODE_POCSAG:
#ifdef ENABLE_POCSAG
/* Feed audio samples to POCSAG decoder */
{
uint16_t audio = BK4819_GetVoiceAmplitudeOut();
POCSAG_FeedSample(audio);
}
POCSAG_Process();
/* Check for messages */
if (POCSAG_MessageAvailable()) {
pocsag_msg_t msg;
if (POCSAG_GetMessage(&msg)) {
/* New message received */
}
}
/* Process POCSAG-specific keys (gScreenToDisplay is INVALID) */
{
KEY_Code_t Key = read_key_debounced();
if (Key != KEY_INVALID) {
if (Key == KEY_EXIT) {
MODE_Switch(MODE_VFO);
} else if (Key == KEY_F || Key == KEY_STAR) {
uint32_t cur = POCSAG_GetBaud();
POCSAG_SwitchBaud(cur == POCSAG_BAUD_1200
? POCSAG_BAUD_512
: POCSAG_BAUD_1200);
}
}
}
/* Redraw POCSAG display periodically */
{
static uint16_t rc = 0;
if (++rc >= 5) {
rc = 0;
pocsag_draw();
}
}
#endif
break;
case MODE_SPECTRUM:
/* Spectrum has returned — go back to VFO */
MODE_Switch(MODE_VFO);
break;
case MODE_FM:
#ifdef ENABLE_FMRADIO
if (!gFmRadioMode)
MODE_Switch(MODE_VFO);
#endif
break;
default:
break;
}
}
void MODE_TimeSlice500ms(void)
{
switch (s_current_mode) {
case MODE_VFO:
APP_TimeSlice500ms();
break;
default:
break;
}
}
/* === External key processing hook === */
bool MODE_ProcessKey(int key, bool pressed, bool held)
{
KEY_Code_t k = (KEY_Code_t)key;
if (k == KEY_EXIT && pressed && !held) {
if (s_current_mode != MODE_VFO) {
MODE_Switch(MODE_VFO);
return true;
}
return false;
}
if (pressed && !held) {
switch (s_current_mode) {
case MODE_VFO:
if (k == KEY_SIDE2) {
#ifdef ENABLE_POCSAG
MODE_Switch(MODE_POCSAG);
return true;
#endif
}
if (k == KEY_SIDE1) {
#ifdef ENABLE_SPECTRUM
MODE_Switch(MODE_SPECTRUM);
return true;
#endif
}
if (k == KEY_0) {
#ifdef ENABLE_FMRADIO
MODE_Switch(MODE_FM);
FM_Start();
return true;
#endif
}
return false;
default:
return false;
}
}
return false;
}

50
app/mode.h Normal file
View File

@@ -0,0 +1,50 @@
/* UA1ZBE Custom Firmware - Mode Dispatcher
*
* Manages switching between operating modes:
* MODE_VFO — Main VFO mode (default)
* MODE_POCSAG — POCSAG decoder
* MODE_SPECTRUM — Spectrum analyzer
* MODE_FM — FM radio receiver
*
* Key mappings:
* KEY_SIDE2 (SK2) → POCSAG mode
* KEY_SIDE1 (SK1) → Spectrum mode
* KEY_EXIT → Return to VFO
* KEY_0 (short) → FM mode
*/
#ifndef APP_MODE_H
#define APP_MODE_H
#include <stdint.h>
#include <stdbool.h>
/* Operating modes */
typedef enum {
MODE_VFO = 0,
MODE_POCSAG,
MODE_SPECTRUM,
MODE_FM,
MODE_COUNT
} op_mode_t;
/* Get current mode */
op_mode_t MODE_GetCurrent(void);
/* Switch to a mode */
void MODE_Switch(op_mode_t mode);
/* Initialize mode dispatcher (call once at boot) */
void MODE_Init(void);
/* Call from 10ms timeslice */
void MODE_TimeSlice10ms(void);
/* Call from 500ms timeslice */
void MODE_TimeSlice500ms(void);
/* Process key press for mode switching.
* Returns true if the key was consumed by mode switch. */
bool MODE_ProcessKey(int key, bool pressed, bool held);
#endif

228
app/pocsag/bch31.c Normal file
View File

@@ -0,0 +1,228 @@
/* UA1ZBE Custom Firmware - BCH(31,21) Decoder for POCSAG
*
* POCSAG uses a shortened BCH(31,21) code:
* - 31-bit codeword (n=31)
* - 21 data bits (k=21)
* - 10 parity/check bits (n-k=10)
* - Can correct up to 2 bit errors per codeword
*
* Generator polynomial: g(x) = x^10 + x^9 + x^8 + x^6 + x^5 + x^3 + 1
* = 0x72D (binary: 111 0010 1101)
*
* The full 32-bit word includes:
* - Bit 31: even parity bit (bit 0 of the word after inversion)
* - Bits 30-0: 31-bit BCH codeword
*
* This implementation avoids hardware division (Cortex-M0 has no DIV unit).
* All operations use shifts and XOR (GF(2) arithmetic).
*/
#include "pocsag.h"
#include <stdint.h>
#include <stdbool.h>
/* Generator polynomial for BCH(31,21): x^10 + x^9 + x^8 + x^6 + x^5 + x^3 + 1 */
#define BCH31_GEN_POLY 0x72DU /* 11100101101 binary */
/* POCSAG sync word (32-bit) */
#define POCSAG_SYNC_WORD 0x7CD21538U
/* POCSAG idle word */
#define POCSAG_IDLE_WORD 0x7A89C197U
/* Parity check mask for even parity */
#define BCH31_PARITY_MASK 0x80000000U
/*
* Calculate syndrome of a 31-bit BCH codeword.
* The syndrome is the remainder of dividing the received word by g(x).
* If syndrome == 0, the word is valid (no errors or undetectable errors).
*
* word: 31-bit codeword (bits 30:0, parity bit excluded)
* Returns: 10-bit syndrome value
*/
static uint16_t bch31_syndrome(uint32_t word)
{
uint32_t reg = word & 0x7FFFFFFFU; /* Mask to 31 bits */
int i;
/* Polynomial division in GF(2) using shift-and-XOR */
/* We process from MSB to LSB, XORing with generator when MSB is 1 */
for (i = 30; i >= 10; i--) {
if (reg & ((uint32_t)1 << i)) {
reg ^= (BCH31_GEN_POLY << (i - 10));
}
}
/* The remainder is in the lower 10 bits */
return (uint16_t)(reg & 0x03FFU);
}
/*
* Check even parity of a 32-bit word.
* Returns true if parity is correct (even number of 1-bits).
*/
static bool bch31_check_parity(uint32_t word)
{
/* Count set bits using a lookup-free method (no division needed) */
uint32_t v = word;
v = v - ((v >> 1) & 0x55555555U);
v = (v & 0x33333333U) + ((v >> 2) & 0x33333333U);
v = (v + (v >> 4)) & 0x0F0F0F0FU;
v = (v * 0x01010101U) >> 24; /* Sum of all bytes */
return (v & 1U) == 0; /* Even parity = even number of 1-bits */
}
/*
* Find error position from syndrome.
* For single-bit errors, the syndrome directly maps to the error position.
* For double-bit errors, we need more complex correction.
*
* syndrome: 10-bit syndrome value
* Returns: bit position (0-30) if single error, 0 if no error,
* or a special value for double errors.
*/
static int bch31_find_single_error(uint16_t syndrome)
{
if (syndrome == 0)
return -1; /* No error */
/* For single-bit errors, syndrome = x^i mod g(x) for error at position i.
* We try each position by computing the expected syndrome.
* This avoids division — just shift and XOR. */
uint32_t test_syn = 1; /* Start with x^0 mod g(x) = 1 */
for (int i = 0; i < 31; i++) {
if (test_syn == syndrome)
return i; /* Error at position i */
/* Multiply by x in GF(2^10 / g(x)):
* Shift left; if bit 10 is set, XOR with generator */
test_syn <<= 1;
if (test_syn & 0x0400U) { /* Bit 10 set */
test_syn ^= BCH31_GEN_POLY;
}
test_syn &= 0x03FFU; /* Keep 10 bits */
}
return -2; /* Not a single-bit error */
}
/*
* Attempt to correct double-bit errors using syndrome decoding.
* For a (31,21) BCH code with d_min=5, we can correct up to 2 errors.
*
* This uses a simplified approach: try all pairs of error positions.
* For performance on Cortex-M0, we use a precomputed approach.
*
* word: pointer to the 32-bit word (will be modified in place if corrected)
* Returns: 0 = no error, 1 = single error corrected,
* 2 = double error corrected, -1 = uncorrectable
*/
int bch31_correct(uint32_t *word)
{
uint32_t data = *word;
/* Step 1: Check parity */
bool parity_ok = bch31_check_parity(data);
/* Extract 31-bit codeword (strip parity bit 31) */
uint32_t codeword = data & 0x7FFFFFFFU;
/* Step 2: Calculate syndrome */
uint16_t syn = bch31_syndrome(codeword);
if (syn == 0 && parity_ok) {
/* No errors detected */
return 0;
}
/* Step 3: Try single-bit error correction */
int err_pos = bch31_find_single_error(syn);
if (err_pos >= 0) {
/* Single-bit error at position err_pos */
codeword ^= ((uint32_t)1 << err_pos);
/* Fix parity bit too */
*word = codeword | ((uint32_t)bch31_check_parity(codeword) << 31);
return 1;
}
/* Step 4: Try double-bit error correction
*
* For double errors at positions i and j:
* syndrome S = x^i + x^j (mod g(x))
*
* We use a brute-force search over all pairs (i, j) where i > j.
* For 31 bits, this is 31*30/2 = 465 pairs — acceptable.
*/
if (err_pos == -2) {
/* Precompute all single-error syndromes */
uint16_t single_syn[31];
uint32_t test = 1;
for (int i = 0; i < 31; i++) {
single_syn[i] = (uint16_t)test;
test <<= 1;
if (test & 0x0400U)
test ^= BCH31_GEN_POLY;
test &= 0x03FFU;
}
/* Search for pair (i, j) where syn_i XOR syn_j == syn */
for (int i = 1; i < 31; i++) {
for (int j = 0; j < i; j++) {
if ((single_syn[i] ^ single_syn[j]) == syn) {
/* Found double error at positions i and j */
codeword ^= ((uint32_t)1 << i);
codeword ^= ((uint32_t)1 << j);
*word = codeword | ((uint32_t)bch31_check_parity(codeword) << 31);
return 2;
}
}
}
}
/* Step 5: If syndrome != 0 but we couldn't find error positions,
* check if it might still be valid (parity might catch it).
* POCSAG spec says words with uncorrectable errors should be discarded.
*/
return -1; /* Uncorrectable */
}
/*
* Extract 21 data bits from a corrected 32-bit POCSAG word.
* Returns the 21-bit data value.
*/
uint32_t bch31_get_data(uint32_t word)
{
/* Data bits are in positions 30:10 of the 31-bit codeword
* (bit 31 is parity, bits 9:0 are check bits)
* So data = bits [30:10] = (word >> 10) & 0x1FFFFF */
return (word >> 10) & 0x001FFFFFU;
}
/*
* Get function bits from a POCSAG address word.
* Address words have function code in bits 11:10 of the data portion.
*/
uint8_t bch31_get_func(uint32_t word)
{
/* Function bits are data bits [11:10] = bits [21:20] of full word */
return (uint8_t)((word >> 20) & 0x03U);
}
/*
* Check if a word is a sync word.
*/
bool bch31_is_sync(uint32_t word)
{
return word == POCSAG_SYNC_WORD;
}
/*
* Check if a word is an idle word.
*/
bool bch31_is_idle(uint32_t word)
{
return word == POCSAG_IDLE_WORD;
}

25
app/pocsag/bch31.h Normal file
View File

@@ -0,0 +1,25 @@
/* UA1ZBE Custom Firmware - BCH(31,21) header */
#ifndef APP_POCSAG_BCH31_H
#define APP_POCSAG_BCH31_H
#include <stdint.h>
#include <stdbool.h>
/* Correct errors in a POCSAG 32-bit word in place.
* Returns: 0 = no error, 1 = single corrected,
* 2 = double corrected, -1 = uncorrectable */
int bch31_correct(uint32_t *word);
/* Extract 21 data bits from corrected word */
uint32_t bch31_get_data(uint32_t word);
/* Get 2-bit function code */
uint8_t bch31_get_func(uint32_t word);
/* Check if word is sync word */
bool bch31_is_sync(uint32_t word);
/* Check if word is idle word */
bool bch31_is_idle(uint32_t word);
#endif

542
app/pocsag/pocsag.c Normal file
View File

@@ -0,0 +1,542 @@
/* UA1ZBE Custom Firmware - POCSAG Decoder Implementation
*
* Implements POCSAG decoding from FM discriminator audio samples.
* Uses zero-crossing detection for bit slicing.
*
* Signal chain:
* BK4819 FM demod -> AF output -> ADC sampling
* -> zero-crossing detection -> bit stream -> POCSAG decode
*
* Cortex-M0 optimized: no hardware division in hot path.
* All memory statically allocated.
*/
#include "pocsag.h"
#include "bch31.h"
#include "driver/bk4819.h"
#include "driver/system.h"
#include "driver/st7565.h"
#include "misc.h"
#include "radio.h"
#include <string.h>
/* === Configuration === */
/* Sampling rate for audio (Hz) — must be much higher than max baud rate */
#define POCSAG_SAMPLE_RATE 8000 /* 8 kHz — sufficient for 1200 baud */
/* Threshold for zero-crossing detection (ADC counts) */
#define POCSAG_ZERO_THRESHOLD 2048 /* Midpoint of 12-bit ADC range (0-4095) */
/* Minimum preamble bits to detect (POCSAG spec: 576 bits of 0x55 + 1) */
#define POCSAG_PREAMBLE_MIN_BITS 576
/* BPSK bit extraction: compare sample against threshold */
#define IS_BIT_ONE(sample) ((sample) > POCSAG_ZERO_THRESHOLD)
/* === Global decoder instance === */
pocsag_decoder_t gPocsag;
/* === Internal state for bit slicing === */
/* Samples since last bit decision */
static uint16_t s_sample_counter;
/* Samples per bit for current baud rate */
static uint16_t s_samples_per_bit;
/* Accumulated samples for current bit decision */
static uint32_t s_bit_accumulator;
static uint8_t s_bit_sample_count;
/* Preamble detection: count alternating bits */
static uint16_t s_preamble_alt_count;
static uint8_t s_last_bit;
/* Sync detection shift register (holds last 32 bits) */
static uint32_t s_sync_reg;
/* Bit buffer for assembling 32-bit words */
static uint32_t s_word_reg;
static uint8_t s_word_bits;
/* Batch tracking */
static uint8_t s_batch_words;
/* Address/message assembly */
static uint32_t s_msg_address;
static uint8_t s_msg_func;
static uint8_t s_msg_buf[POCSAG_MSG_MAX_LEN];
static uint8_t s_msg_len;
static bool s_msg_is_alpha;
/* Alpha decoder state */
static uint32_t s_alpha_bits;
static uint8_t s_alpha_bit_count;
/* State */
static pocsag_state_t s_state;
/* Previous save state for restoration */
static uint16_t s_saved_reg_30;
static uint16_t s_saved_reg_47;
static uint16_t s_saved_reg_33;
/* Timing counter — increments each time FeedSample is called (every ~10ms) */
static uint32_t s_tick_counter;
/* Last sync timestamp */
static uint32_t s_last_sync_tick;
/* === Baud rate lookup === */
/* Samples per bit for supported baud rates at 8kHz sample rate */
static uint16_t get_samples_per_bit(uint32_t baud)
{
/* Avoid division: use precomputed values
* 8000 / 512 = 15.625 -> 16
* 8000 / 1200 = 6.667 -> 7 */
if (baud == POCSAG_BAUD_512)
return 16;
if (baud == POCSAG_BAUD_1200)
return 7;
return 7; /* Default to 1200 */
}
/* === Message ring buffer === */
static void msg_push(const pocsag_msg_t *msg)
{
if (gPocsag.msg_count >= POCSAG_MSG_POOL_SIZE) {
/* Buffer full — drop oldest */
gPocsag.msg_read_idx = (gPocsag.msg_read_idx + 1) % POCSAG_MSG_POOL_SIZE;
gPocsag.msg_count--;
}
gPocsag.messages[gPocsag.msg_write_idx] = *msg;
gPocsag.msg_write_idx = (gPocsag.msg_write_idx + 1) % POCSAG_MSG_POOL_SIZE;
gPocsag.msg_count++;
gPocsag.msg_available = true;
}
/* === POCSAG word processing === */
static void process_pocsag_word(uint32_t word)
{
/* Check parity first — quick reject using bit count */
uint32_t v = word;
v = v - ((v >> 1) & 0x55555555U);
v = (v & 0x33333333U) + ((v >> 2) & 0x33333333U);
v = (v + (v >> 4)) & 0x0F0F0F0FU;
v = (v * 0x01010101U) >> 24;
bool parity_ok = (v & 1U) == 0;
/* Try BCH correction */
int corr = bch31_correct(&word);
if (corr < 0 && !parity_ok) {
/* Uncorrectable — discard */
gPocsag.uncorrectable_errors++;
if (s_state == POCSAG_STATE_DATA) {
s_state = POCSAG_STATE_SYNC;
s_batch_words = 0;
}
return;
}
if (corr > 0)
gPocsag.corrected_errors++;
gPocsag.total_words++;
/* Check for sync word */
if (bch31_is_sync(word)) {
s_batch_words = 0;
s_last_sync_tick = s_tick_counter;
return;
}
/* Check for idle word */
if (bch31_is_idle(word)) {
return; /* Skip idle words */
}
/* In DATA state, process the word */
if (s_state != POCSAG_STATE_DATA) {
s_state = POCSAG_STATE_DATA;
s_batch_words = 0;
}
/* Even/odd position in batch determines address vs data */
if (s_batch_words % 2 == 0) {
/* Address word */
s_msg_address = bch31_get_data(word);
s_msg_func = bch31_get_func(word);
s_msg_len = 0;
s_msg_is_alpha = false;
s_msg_buf[0] = '\0';
/* Reset alpha decoder state */
s_alpha_bits = 0;
s_alpha_bit_count = 0;
} else {
/* Data word */
uint32_t data = bch31_get_data(word);
if (s_msg_func == 0) {
/* Numeric pager — data is BCD digits */
uint32_t num = data & 0x000FFFFFU;
char digits[12];
int idx = 0;
if (num == 0) {
digits[idx++] = '0';
} else {
/* Extract digits using precomputed powers of 10 (no division) */
static const uint32_t powers[] = {
1000000000U, 100000000U, 10000000U, 1000000U,
100000U, 10000U, 1000U, 100U, 10U, 1U
};
bool started = false;
for (int p = 0; p < 10; p++) {
uint32_t pwr = powers[p];
uint8_t digit = 0;
while (num >= pwr) {
num -= pwr;
digit++;
}
if (digit > 0 || started || p == 9) {
digits[idx++] = '0' + digit;
started = true;
}
}
}
digits[idx] = '\0';
/* Push message */
if (s_msg_len == 0) {
pocsag_msg_t msg;
memset(&msg, 0, sizeof(msg));
msg.address = s_msg_address;
msg.func = s_msg_func;
msg.is_alpha = false;
msg.timestamp = s_tick_counter;
int copy_len = idx;
if (copy_len > POCSAG_MSG_MAX_LEN - 1)
copy_len = POCSAG_MSG_MAX_LEN - 1;
memcpy(msg.text, digits, copy_len);
msg.text[copy_len] = '\0';
msg.text_len = copy_len;
msg_push(&msg);
}
} else if (s_msg_func == 2) {
/* Alpha pager — 7-bit ASCII, 20 bits per word */
uint32_t bits20 = data & 0x000FFFFFU;
s_alpha_bits = (s_alpha_bits << 20) | bits20;
s_alpha_bit_count += 20;
while (s_alpha_bit_count >= 7 && s_msg_len < POCSAG_MSG_MAX_LEN - 1) {
s_alpha_bit_count -= 7;
uint8_t ch = (s_alpha_bits >> s_alpha_bit_count) & 0x7F;
if (ch == 0x03) {
/* ETX — end of message */
s_msg_buf[s_msg_len] = '\0';
pocsag_msg_t msg;
memset(&msg, 0, sizeof(msg));
msg.address = s_msg_address;
msg.func = s_msg_func;
msg.is_alpha = true;
msg.timestamp = s_tick_counter;
memcpy(msg.text, s_msg_buf, s_msg_len);
msg.text[s_msg_len] = '\0';
msg.text_len = s_msg_len;
msg_push(&msg);
s_msg_len = 0;
s_alpha_bits = 0;
s_alpha_bit_count = 0;
break;
}
s_msg_buf[s_msg_len++] = ch;
}
s_msg_is_alpha = true;
}
}
s_batch_words++;
/* After 32 words, expect new sync */
if (s_batch_words >= 32) {
s_state = POCSAG_STATE_SYNC;
s_batch_words = 0;
}
}
/* === Bit processing === */
static void process_bit(bool bit)
{
gPocsag.total_bits++;
switch (s_state) {
case POCSAG_STATE_IDLE:
case POCSAG_STATE_PREAMBLE:
s_state = POCSAG_STATE_PREAMBLE;
/* Look for alternating pattern: 01010101... (0x55) ending with 1 (0xAB) */
if (s_preamble_alt_count == 0) {
s_last_bit = bit ? 1 : 0;
s_preamble_alt_count = 1;
} else if ((bit ? 1 : 0) != s_last_bit) {
s_preamble_alt_count++;
s_last_bit = bit ? 1 : 0;
} else {
s_preamble_alt_count = 1;
s_last_bit = bit ? 1 : 0;
}
if (s_preamble_alt_count >= POCSAG_PREAMBLE_MIN_BITS) {
/* Preamble detected — look for sync word */
s_state = POCSAG_STATE_SYNC;
s_sync_reg = 0;
s_word_bits = 0;
s_preamble_alt_count = 0;
s_last_sync_tick = s_tick_counter;
}
break;
case POCSAG_STATE_SYNC:
/* Collect bits into 32-bit sync register */
s_sync_reg = (s_sync_reg << 1) | (bit ? 1 : 0);
if (s_sync_reg == 0x7CD21538U) {
/* Sync word found! */
s_state = POCSAG_STATE_DATA;
s_word_reg = 0;
s_word_bits = 0;
s_batch_words = 0;
gPocsag.signal_detected = true;
s_last_sync_tick = s_tick_counter;
}
/* Timeout: ~1000 bits at 1200 baud ≈ 833ms ≈ 83 calls */
if ((s_tick_counter - s_last_sync_tick) > 100) {
s_state = POCSAG_STATE_IDLE;
s_preamble_alt_count = 0;
gPocsag.signal_detected = false;
}
break;
case POCSAG_STATE_DATA:
/* Collect 32-bit words */
s_word_reg = (s_word_reg << 1) | (bit ? 1 : 0);
s_word_bits++;
if (s_word_bits >= 32) {
process_pocsag_word(s_word_reg);
s_word_reg = 0;
s_word_bits = 0;
}
/* Sync loss check */
if ((s_tick_counter - s_last_sync_tick) > 300) {
s_state = POCSAG_STATE_SYNC;
s_sync_reg = 0;
gPocsag.signal_detected = false;
}
break;
}
}
/* === Sample processing (hot path) === */
bool POCSAG_FeedSample(uint16_t audio_sample)
{
s_tick_counter++;
s_sample_counter++;
/* Accumulate samples for bit decision */
s_bit_accumulator += audio_sample;
s_bit_sample_count++;
if (s_bit_sample_count >= s_samples_per_bit) {
/* Make bit decision from averaged sample.
* Avoid division: compare accumulated value against threshold * count.
*
* For 1200 baud (7 samples): threshold * 7 = 2048 * 7 = 14336
* For 512 baud (16 samples): threshold * 16 = 2048 * 16 = 32768 */
uint32_t thresh;
if (gPocsag.baud_rate == POCSAG_BAUD_512)
thresh = 32768;
else
thresh = 14336;
bool bit = (s_bit_accumulator >= thresh);
s_bit_accumulator = 0;
s_bit_sample_count = 0;
/* Process the bit */
process_bit(bit);
return true;
}
return false;
}
void POCSAG_FeedBit(bool bit)
{
process_bit(bit);
}
/* === Public API === */
void POCSAG_Init(uint32_t baud_rate)
{
memset(&gPocsag, 0, sizeof(gPocsag));
gPocsag.baud_rate = baud_rate;
gPocsag.state = POCSAG_STATE_IDLE;
gPocsag.msg_read_idx = 0;
gPocsag.msg_write_idx = 0;
gPocsag.msg_count = 0;
gPocsag.msg_available = false;
s_sample_counter = 0;
s_samples_per_bit = get_samples_per_bit(baud_rate);
s_bit_accumulator = 0;
s_bit_sample_count = 0;
s_preamble_alt_count = 0;
s_last_bit = 0;
s_sync_reg = 0;
s_word_reg = 0;
s_word_bits = 0;
s_batch_words = 0;
s_msg_address = 0;
s_msg_func = 0;
s_msg_len = 0;
s_msg_is_alpha = false;
s_alpha_bits = 0;
s_alpha_bit_count = 0;
s_state = POCSAG_STATE_IDLE;
s_tick_counter = 0;
s_last_sync_tick = 0;
}
void POCSAG_SwitchBaud(uint32_t baud_rate)
{
gPocsag.baud_rate = baud_rate;
s_samples_per_bit = get_samples_per_bit(baud_rate);
s_state = POCSAG_STATE_IDLE;
s_preamble_alt_count = 0;
s_sync_reg = 0;
s_word_reg = 0;
s_word_bits = 0;
s_batch_words = 0;
gPocsag.signal_detected = false;
}
uint32_t POCSAG_GetBaud(void)
{
return gPocsag.baud_rate;
}
bool POCSAG_MessageAvailable(void)
{
return gPocsag.msg_count > 0;
}
bool POCSAG_GetMessage(pocsag_msg_t *msg)
{
if (gPocsag.msg_count == 0)
return false;
*msg = gPocsag.messages[gPocsag.msg_read_idx];
gPocsag.msg_read_idx = (gPocsag.msg_read_idx + 1) % POCSAG_MSG_POOL_SIZE;
gPocsag.msg_count--;
if (gPocsag.msg_count == 0)
gPocsag.msg_available = false;
return true;
}
pocsag_state_t POCSAG_GetState(void)
{
return s_state;
}
bool POCSAG_SignalDetected(void)
{
return gPocsag.signal_detected;
}
void POCSAG_Reset(void)
{
uint32_t baud = gPocsag.baud_rate;
POCSAG_Init(baud);
}
void POCSAG_Process(void)
{
gPocsag.state = s_state;
}
/* === Radio configuration === */
void POCSAG_ConfigureRadio(uint32_t frequency_hz)
{
/* Save current radio state */
s_saved_reg_30 = BK4819_ReadRegister(BK4819_REG_30);
s_saved_reg_47 = BK4819_ReadRegister(BK4819_REG_47);
s_saved_reg_33 = BK4819_ReadRegister(BK4819_REG_33);
/* Set frequency */
BK4819_SetFrequency(frequency_hz);
BK4819_PickRXFilterPathBasedOnFrequency(frequency_hz);
/* Configure for narrow FM (POCSAG is typically narrow FM) */
BK4819_SetFilterBandwidth(BK4819_FILTER_BW_NARROW, true);
/* Turn on RX */
BK4819_RX_TurnOn();
/* Set AF output to FM (demodulated audio) for sampling */
BK4819_SetAF(BK4819_AF_FM);
/* Disable squelch for continuous audio monitoring */
BK4819_SetupSquelch(0, 0, 0, 0, 255, 0);
/* Enable RX link, AF DAC, disc mode */
BK4819_WriteRegister(BK4819_REG_30,
BK4819_REG_30_ENABLE_VCO_CALIB |
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_ENABLE_RX_DSP);
/* Enable green LED */
BK4819_ToggleGpioOut(BK4819_GPIO6_PIN2_GREEN, true);
}
void POCSAG_Stop(void)
{
BK4819_WriteRegister(BK4819_REG_30, s_saved_reg_30);
BK4819_WriteRegister(BK4819_REG_47, s_saved_reg_47);
BK4819_WriteRegister(BK4819_REG_33, s_saved_reg_33);
gPocsag.signal_detected = false;
s_state = POCSAG_STATE_IDLE;
}
/* === State description strings === */
const char *POCSAG_StateString(pocsag_state_t state)
{
static const char *const strs[] = { "IDLE", "SEARCH", "SYNC", "DATA" };
if ((unsigned int)state > 3u) return "???";
return strs[(unsigned int)state];
}

150
app/pocsag/pocsag.h Normal file
View File

@@ -0,0 +1,150 @@
/* UA1ZBE Custom Firmware - POCSAG Decoder
*
* Decodes POCSAG paging signals from FM discriminator output.
* Supports 512 and 1200 baud rates with dynamic switching.
*
* POCSAG Protocol:
* - Preamble: 0xAAAAAAAB (at least 576 bits of alternating 1010... ending with 1)
* - Sync word: 0x7CD21538
* - Data words: 32-bit (21 data + 10 BCH + 1 parity)
* - BCH(31,21) code, corrects up to 2 errors per word
*
* Architecture:
* - Samples audio from BK4819 discriminator (REG_69 AF output or FSK FIFO)
* - Zero-crossing detection for bit slicing
* - State machine: IDLE -> PREAMBLE -> SYNC -> DATA
* - Ring buffer for decoded messages
* - Zero malloc — all static allocation
*/
#ifndef APP_POCSAG_POCSAG_H
#define APP_POCSAG_POCSAG_H
#include <stdbool.h>
#include <stdint.h>
/* POCSAG baud rates */
#define POCSAG_BAUD_512 512
#define POCSAG_BAUD_1200 1200
/* Maximum message length in bytes (arbitrary, fits in static buffer) */
#define POCSAG_MSG_MAX_LEN 64
/* Maximum messages in ring buffer */
#define POCSAG_MSG_POOL_SIZE 8
/* Decoded message structure */
typedef struct {
uint32_t address; /* Address (21-bit frame address) */
uint8_t func; /* Function code (2 bits) */
char text[POCSAG_MSG_MAX_LEN]; /* Decoded text (alpha pager) */
uint8_t text_len; /* Length of decoded text */
bool is_alpha; /* true = alpha pager, false = numeric */
uint32_t timestamp; /* System tick when received */
} pocsag_msg_t;
/* Decoder state machine states */
typedef enum {
POCSAG_STATE_IDLE = 0,
POCSAG_STATE_PREAMBLE,
POCSAG_STATE_SYNC,
POCSAG_STATE_DATA
} pocsag_state_t;
/* Decoder context — all static, no malloc */
typedef struct {
/* Configuration */
uint32_t baud_rate; /* Current baud rate: 512 or 1200 */
/* State machine */
pocsag_state_t state;
/* Bit accumulation */
uint32_t shift_reg; /* Shift register for incoming bits */
uint8_t bit_count; /* Number of bits collected in shift_reg */
uint8_t preamble_count; /* Consecutive alternating bits in preamble */
/* Sync detection */
uint8_t sync_word_count; /* Number of sync words found in a row */
/* Word collection */
uint8_t batch_count; /* Words in current batch (0-16) */
uint8_t word_in_batch; /* Current word position in batch */
/* Message assembly */
uint32_t current_address;
uint8_t current_func;
uint8_t msg_data[POCSAG_MSG_MAX_LEN];
uint8_t msg_len;
bool msg_is_alpha;
/* Ring buffer of decoded messages */
pocsag_msg_t messages[POCSAG_MSG_POOL_SIZE];
volatile uint8_t msg_read_idx;
volatile uint8_t msg_write_idx;
volatile uint8_t msg_count;
/* Statistics */
uint32_t total_bits;
uint32_t total_words;
uint32_t corrected_errors;
uint32_t uncorrectable_errors;
/* Flag for new message available */
volatile bool msg_available;
/* Signal active flag */
bool signal_detected;
} pocsag_decoder_t;
/* Global decoder instance */
extern pocsag_decoder_t gPocsag;
/* === API === */
/* Initialize decoder, set baud rate */
void POCSAG_Init(uint32_t baud_rate);
/* Switch baud rate dynamically (512 <-> 1200) */
void POCSAG_SwitchBaud(uint32_t baud_rate);
/* Get current baud rate */
uint32_t POCSAG_GetBaud(void);
/* Feed audio sample (12-bit ADC value from discriminator)
* Call this from the 10ms timeslice or a dedicated sampling timer.
* Returns true if a bit was detected. */
bool POCSAG_FeedSample(uint16_t audio_sample);
/* Feed a single bit (after external bit-slicing) */
void POCSAG_FeedBit(bool bit);
/* Check if a decoded message is available (non-blocking) */
bool POCSAG_MessageAvailable(void);
/* Pop the next decoded message from the ring buffer */
bool POCSAG_GetMessage(pocsag_msg_t *msg);
/* Get decoder state (for display) */
pocsag_state_t POCSAG_GetState(void);
/* Get signal detection status */
bool POCSAG_SignalDetected(void);
/* Reset decoder to idle state */
void POCSAG_Reset(void);
/* Process decoder state machine (call from main loop) */
void POCSAG_Process(void);
/* Configure BK4819 for POCSAG reception on given frequency */
void POCSAG_ConfigureRadio(uint32_t frequency_hz);
/* Stop POCSAG reception, restore normal RX */
void POCSAG_Stop(void);
/* Get state description string */
const char *POCSAG_StateString(pocsag_state_t state);
#endif /* APP_POCSAG_POCSAG_H */

528
app/scanner.c Normal file
View File

@@ -0,0 +1,528 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "app/app.h"
#include "app/dtmf.h"
#include "app/generic.h"
#include "app/menu.h"
#include "app/scanner.h"
#include "audio.h"
#include "driver/bk4819.h"
#include "frequencies.h"
#include "misc.h"
#include "radio.h"
#include "settings.h"
#include "ui/inputbox.h"
#include "ui/ui.h"
DCS_CodeType_t gScanCssResultType;
uint8_t gScanCssResultCode;
bool gScanSingleFrequency; // scan CTCSS/DCS codes for current frequency
SCAN_SaveState_t gScannerSaveState;
uint8_t gScanChannel;
uint32_t gScanFrequency;
SCAN_CssState_t gScanCssState;
uint8_t gScanProgressIndicator;
bool gScanUseCssResult;
STEP_Setting_t stepSetting;
uint8_t scanHitCount;
static void SCANNER_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
{
if (!bKeyHeld && bKeyPressed)
{
if (gScannerSaveState == SCAN_SAVE_CHAN_SEL) {
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
INPUTBOX_Append(Key);
gRequestDisplayScreen = DISPLAY_SCANNER;
if (gInputBoxIndex < 3) {
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
return;
}
gInputBoxIndex = 0;
uint16_t chan = ((gInputBox[0] * 100) + (gInputBox[1] * 10) + gInputBox[2]) - 1;
if (IS_MR_CHANNEL(chan)) {
#ifdef ENABLE_VOICE
gAnotherVoiceID = (VOICE_ID_t)Key;
#endif
gShowChPrefix = RADIO_CheckValidChannel(chan, false, 0);
gScanChannel = (uint8_t)chan;
return;
}
}
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
}
}
static void SCANNER_Key_EXIT(bool bKeyPressed, bool bKeyHeld)
{
if (!bKeyHeld && bKeyPressed) { // short pressed
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
switch (gScannerSaveState) {
case SCAN_SAVE_NO_PROMPT:
SCANNER_Stop();
gRequestDisplayScreen = DISPLAY_MAIN;
break;
case SCAN_SAVE_CHAN_SEL:
if (gInputBoxIndex > 0) {
gInputBox[--gInputBoxIndex] = 10;
gRequestDisplayScreen = DISPLAY_SCANNER;
break;
}
// Fallthrough
case SCAN_SAVE_CHANNEL:
gScannerSaveState = SCAN_SAVE_NO_PROMPT;
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_CANCEL;
#endif
gRequestDisplayScreen = DISPLAY_SCANNER;
break;
}
}
}
static void SCANNER_Key_MENU(bool bKeyPressed, bool bKeyHeld)
{
if (bKeyHeld || !bKeyPressed) // ignore long press or release button events
return;
if (gScanCssState == SCAN_CSS_STATE_OFF && !gScanSingleFrequency) {
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
if (gScanCssState == SCAN_CSS_STATE_SCANNING && gScanSingleFrequency) {
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
if (gScanCssState == SCAN_CSS_STATE_FAILED) {
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
return;
}
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
switch (gScannerSaveState) {
case SCAN_SAVE_NO_PROMPT:
if (!gScanSingleFrequency)
{
uint32_t freq250 = FREQUENCY_RoundToStep(gScanFrequency, 250);
uint32_t freq625 = FREQUENCY_RoundToStep(gScanFrequency, 625);
uint32_t diff250 = gScanFrequency > freq250 ? gScanFrequency - freq250 : freq250 - gScanFrequency;
uint32_t diff625 = gScanFrequency > freq625 ? gScanFrequency - freq625 : freq625 - gScanFrequency;
if(diff250 > diff625) {
stepSetting = STEP_6_25kHz;
gScanFrequency = freq625;
}
else {
stepSetting = STEP_2_5kHz;
gScanFrequency = freq250;
}
}
if (IS_MR_CHANNEL(gTxVfo->CHANNEL_SAVE)) {
gScannerSaveState = SCAN_SAVE_CHAN_SEL;
gScanChannel = gTxVfo->CHANNEL_SAVE;
gShowChPrefix = RADIO_CheckValidChannel(gTxVfo->CHANNEL_SAVE, false, 0);
}
else {
gScannerSaveState = SCAN_SAVE_CHANNEL;
}
gScanCssState = SCAN_CSS_STATE_FOUND;
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_MEMORY_CHANNEL;
#endif
gRequestDisplayScreen = DISPLAY_SCANNER;
gUpdateStatus = true;
break;
case SCAN_SAVE_CHAN_SEL:
if (gInputBoxIndex == 0) {
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
gRequestDisplayScreen = DISPLAY_SCANNER;
gScannerSaveState = SCAN_SAVE_CHANNEL;
}
break;
case SCAN_SAVE_CHANNEL:
if (!gScanSingleFrequency) {
RADIO_InitInfo(gTxVfo, gTxVfo->CHANNEL_SAVE, gScanFrequency);
if (gScanUseCssResult) {
gTxVfo->freq_config_RX.CodeType = gScanCssResultType;
gTxVfo->freq_config_RX.Code = gScanCssResultCode;
}
gTxVfo->freq_config_TX = gTxVfo->freq_config_RX;
gTxVfo->STEP_SETTING = stepSetting;
}
else {
RADIO_ConfigureChannel(0, VFO_CONFIGURE_RELOAD);
RADIO_ConfigureChannel(1, VFO_CONFIGURE_RELOAD);
gTxVfo->freq_config_RX.CodeType = gScanCssResultType;
gTxVfo->freq_config_RX.Code = gScanCssResultCode;
gTxVfo->freq_config_TX.CodeType = gScanCssResultType;
gTxVfo->freq_config_TX.Code = gScanCssResultCode;
}
uint8_t chan;
if (IS_MR_CHANNEL(gTxVfo->CHANNEL_SAVE)) {
chan = gScanChannel;
gEeprom.MrChannel[gEeprom.TX_VFO] = chan;
}
else {
chan = gTxVfo->Band + FREQ_CHANNEL_FIRST;
gEeprom.FreqChannel[gEeprom.TX_VFO] = chan;
}
gTxVfo->CHANNEL_SAVE = chan;
gEeprom.ScreenChannel[gEeprom.TX_VFO] = chan;
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_CONFIRM;
#endif
gRequestDisplayScreen = DISPLAY_SCANNER;
gRequestSaveChannel = 2;
gScannerSaveState = SCAN_SAVE_NO_PROMPT;
break;
default:
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
break;
}
}
static void SCANNER_Key_STAR(bool bKeyPressed, bool bKeyHeld)
{
if (!bKeyHeld && bKeyPressed) {
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
SCANNER_Start(gScanSingleFrequency);
}
return;
}
static void SCANNER_Key_UP_DOWN(bool bKeyPressed, bool pKeyHeld, int8_t Direction)
{
if (pKeyHeld) {
if (!bKeyPressed)
return;
}
else {
if (!bKeyPressed)
return;
gInputBoxIndex = 0;
gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL;
}
if (gScannerSaveState == SCAN_SAVE_CHAN_SEL) {
gScanChannel = NUMBER_AddWithWraparound(gScanChannel, Direction, 0, MR_CHANNEL_LAST);
gShowChPrefix = RADIO_CheckValidChannel(gScanChannel, false, 0);
gRequestDisplayScreen = DISPLAY_SCANNER;
}
else
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
}
void SCANNER_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:
SCANNER_Key_DIGITS(Key, bKeyPressed, bKeyHeld);
break;
case KEY_MENU:
SCANNER_Key_MENU(bKeyPressed, bKeyHeld);
break;
case KEY_UP:
SCANNER_Key_UP_DOWN(bKeyPressed, bKeyHeld, 1);
break;
case KEY_DOWN:
SCANNER_Key_UP_DOWN(bKeyPressed, bKeyHeld, -1);
break;
case KEY_EXIT:
SCANNER_Key_EXIT(bKeyPressed, bKeyHeld);
break;
case KEY_STAR:
SCANNER_Key_STAR(bKeyPressed, bKeyHeld);
break;
case KEY_PTT:
GENERIC_Key_PTT(bKeyPressed);
break;
default:
if (!bKeyHeld && bKeyPressed)
gBeepToPlay = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL;
break;
}
}
void SCANNER_Start(bool singleFreq)
{
gScanSingleFrequency = singleFreq;
gMonitor = false;
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_SCANNING_BEGIN;
#endif
BK4819_StopScan();
RADIO_SelectVfos();
#ifdef ENABLE_NOAA
if (IS_NOAA_CHANNEL(gRxVfo->CHANNEL_SAVE))
gRxVfo->CHANNEL_SAVE = FREQ_CHANNEL_FIRST + BAND6_400MHz;
#endif
uint8_t backupStep = gRxVfo->STEP_SETTING;
uint16_t backupFrequency = gRxVfo->StepFrequency;
RADIO_InitInfo(gRxVfo, gRxVfo->CHANNEL_SAVE, gRxVfo->pRX->Frequency);
gRxVfo->STEP_SETTING = backupStep;
gRxVfo->StepFrequency = backupFrequency;
RADIO_SetupRegisters(true);
#ifdef ENABLE_NOAA
gIsNoaaMode = false;
#endif
if (gScanSingleFrequency) {
gScanCssState = SCAN_CSS_STATE_SCANNING;
gScanFrequency = gRxVfo->pRX->Frequency;
stepSetting = gRxVfo->STEP_SETTING;
BK4819_PickRXFilterPathBasedOnFrequency(gScanFrequency);
BK4819_SetScanFrequency(gScanFrequency);
gUpdateStatus = true;
}
else {
gScanCssState = SCAN_CSS_STATE_OFF;
gScanFrequency = 0xFFFFFFFF;
BK4819_PickRXFilterPathBasedOnFrequency(gScanFrequency);
BK4819_EnableFrequencyScan();
gUpdateStatus = true;
}
#ifdef ENABLE_DTMF_CALLING
DTMF_clear_RX();
#endif
gScanDelay_10ms = scan_delay_10ms;
gScanCssResultCode = 0xFF;
gScanCssResultType = 0xFF;
scanHitCount = 0;
gScanUseCssResult = false;
g_CxCSS_TAIL_Found = false;
g_CDCSS_Lost = false;
gCDCSSCodeType = 0;
g_CTCSS_Lost = false;
#ifdef ENABLE_VOX
g_VOX_Lost = false;
#endif
g_SquelchLost = false;
gScannerSaveState = SCAN_SAVE_NO_PROMPT;
gScanProgressIndicator = 0;
}
void SCANNER_Stop(void)
{
if(SCANNER_IsScanning()) {
gEeprom.CROSS_BAND_RX_TX = gBackup_CROSS_BAND_RX_TX;
gVfoConfigureMode = VFO_CONFIGURE_RELOAD;
gFlagResetVfos = true;
gUpdateStatus = true;
gCssBackgroundScan = false;
gScanUseCssResult = false;
#ifdef ENABLE_VOICE
gAnotherVoiceID = VOICE_ID_CANCEL;
#endif
BK4819_StopScan();
}
}
void SCANNER_TimeSlice10ms(void)
{
if (!SCANNER_IsScanning())
return;
if (gScanDelay_10ms > 0) {
gScanDelay_10ms--;
return;
}
if (gScannerSaveState != SCAN_SAVE_NO_PROMPT) {
return;
}
switch (gScanCssState) {
case SCAN_CSS_STATE_OFF: {
// must be RF frequency scanning if we're here ?
uint32_t result;
if (!BK4819_GetFrequencyScanResult(&result))
break;
int32_t delta = result - gScanFrequency;
gScanFrequency = result;
if (delta < 0)
delta = -delta;
if (delta < 100)
scanHitCount++;
else
scanHitCount = 0;
BK4819_DisableFrequencyScan();
if (scanHitCount < 3) {
BK4819_EnableFrequencyScan();
}
else {
BK4819_SetScanFrequency(gScanFrequency);
gScanCssResultCode = 0xFF;
gScanCssResultType = 0xFF;
scanHitCount = 0;
gScanUseCssResult = false;
gScanProgressIndicator = 0;
gScanCssState = SCAN_CSS_STATE_SCANNING;
if(!gCssBackgroundScan)
GUI_SelectNextDisplay(DISPLAY_SCANNER);
gUpdateStatus = true;
}
gScanDelay_10ms = scan_delay_10ms;
//gScanDelay_10ms = 1; // 10ms
break;
}
case SCAN_CSS_STATE_SCANNING: {
uint32_t cdcssFreq;
uint16_t ctcssFreq;
BK4819_CssScanResult_t scanResult = BK4819_GetCxCSSScanResult(&cdcssFreq, &ctcssFreq);
if (scanResult == BK4819_CSS_RESULT_NOT_FOUND)
break;
BK4819_Disable();
if (scanResult == BK4819_CSS_RESULT_CDCSS) {
const uint8_t Code = DCS_GetCdcssCode(cdcssFreq);
if (Code != 0xFF)
{
gScanCssResultCode = Code;
gScanCssResultType = CODE_TYPE_DIGITAL;
gScanCssState = SCAN_CSS_STATE_FOUND;
gScanUseCssResult = true;
gUpdateStatus = true;
}
}
else if (scanResult == BK4819_CSS_RESULT_CTCSS) {
const uint8_t Code = DCS_GetCtcssCode(ctcssFreq);
if (Code != 0xFF) {
if (Code == gScanCssResultCode && gScanCssResultType == CODE_TYPE_CONTINUOUS_TONE) {
if (++scanHitCount >= 2) {
gScanCssState = SCAN_CSS_STATE_FOUND;
gScanUseCssResult = true;
gUpdateStatus = true;
}
}
else
scanHitCount = 0;
gScanCssResultType = CODE_TYPE_CONTINUOUS_TONE;
gScanCssResultCode = Code;
}
}
if (gScanCssState < SCAN_CSS_STATE_FOUND) { // scanning or off
BK4819_SetScanFrequency(gScanFrequency);
gScanDelay_10ms = scan_delay_10ms;
break;
}
if(gCssBackgroundScan) {
gCssBackgroundScan = false;
if(gScanUseCssResult)
MENU_CssScanFound();
}
else
GUI_SelectNextDisplay(DISPLAY_SCANNER);
break;
}
default:
gCssBackgroundScan = false;
break;
}
}
void SCANNER_TimeSlice500ms(void)
{
if (SCANNER_IsScanning() && gScannerSaveState == SCAN_SAVE_NO_PROMPT && gScanCssState < SCAN_CSS_STATE_FOUND) {
gScanProgressIndicator++;
#ifndef ENABLE_NO_CODE_SCAN_TIMEOUT
if (gScanProgressIndicator > 32) {
if (gScanCssState == SCAN_CSS_STATE_SCANNING && !gScanSingleFrequency)
gScanCssState = SCAN_CSS_STATE_FOUND;
else
gScanCssState = SCAN_CSS_STATE_FAILED;
gUpdateStatus = true;
}
#endif
gUpdateDisplay = true;
}
else if(gCssBackgroundScan) {
gUpdateDisplay = true;
}
}
bool SCANNER_IsScanning(void)
{
return gCssBackgroundScan || (gScreenToDisplay == DISPLAY_SCANNER);
}

57
app/scanner.h Normal file
View File

@@ -0,0 +1,57 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef APP_SCANNER_H
#define APP_SCANNER_H
#include "dcs.h"
#include "driver/keyboard.h"
typedef enum
{
SCAN_CSS_STATE_OFF,
SCAN_CSS_STATE_SCANNING,
SCAN_CSS_STATE_FOUND,
SCAN_CSS_STATE_FAILED
} SCAN_CssState_t;
typedef enum
{
SCAN_SAVE_NO_PROMPT, // saving process not initiated
SCAN_SAVE_CHAN_SEL, // "SAVE: ", channel select prompt, actives only in channel mode
SCAN_SAVE_CHANNEL, // "SAVE?" prompt, waits for confirmation to save settings to channel, or current VFO
} SCAN_SaveState_t;
extern DCS_CodeType_t gScanCssResultType;
extern uint8_t gScanCssResultCode;
extern bool gScanSingleFrequency;
extern SCAN_SaveState_t gScannerSaveState;
extern uint8_t gScanChannel;
extern uint32_t gScanFrequency;
extern SCAN_CssState_t gScanCssState;
extern uint8_t gScanProgressIndicator;
extern bool gScanUseCssResult;
void SCANNER_ProcessKeys(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld);
void SCANNER_Start(bool singleFreq);
void SCANNER_Stop(void);
void SCANNER_TimeSlice10ms(void);
void SCANNER_TimeSlice500ms(void);
bool SCANNER_IsScanning(void);
#endif

1310
app/spectrum.c Normal file

File diff suppressed because it is too large Load Diff

158
app/spectrum.h Normal file
View File

@@ -0,0 +1,158 @@
/* Copyright 2023 fagci
* https://github.com/fagci
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SPECTRUM_H
#define SPECTRUM_H
#include "../bitmaps.h"
#include "../board.h"
#include "../bsp/dp32g030/gpio.h"
#include "../driver/bk4819-regs.h"
#include "../driver/bk4819.h"
#include "../driver/gpio.h"
#include "../driver/keyboard.h"
#include "../driver/st7565.h"
#include "../driver/system.h"
#include "../driver/systick.h"
#include "../external/printf/printf.h"
#include "../font.h"
#include "../helper/battery.h"
#include "../misc.h"
#include "../radio.h"
#include "../settings.h"
#include "../ui/helper.h"
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
static const uint8_t DrawingEndY = 40;
static const uint8_t U8RssiMap[] = {
121, 115, 109, 103, 97, 91, 85, 79, 73, 63,
};
static const uint16_t scanStepValues[] = {
1, 10, 50, 100, 250, 500, 625, 833,
1000, 1250, 1500, 2000, 2500, 5000, 10000,
};
static const uint16_t scanStepBWRegValues[] = {
// RX RXw TX BW
// 0b0 000 000 001 01 1000
// 1
0b0000000001011000, // 6.25
// 10
0b0000000001011000, // 6.25
// 50
0b0000000001011000, // 6.25
// 100
0b0000000001011000, // 6.25
// 250
0b0000000001011000, // 6.25
// 500
0b0010010001011000, // 6.25
// 625
0b0100100001011000, // 6.25
// 833
0b0110110001001000, // 6.25
// 1000
0b0110110001001000, // 6.25
// 1250
0b0111111100001000, // 6.25
// 2500
0b0011011000101000, // 25
// 10000
0b0011011000101000, // 25
};
static const uint16_t listenBWRegValues[] = {
0b0011011000101000, // 25
0b0111111100001000, // 12.5
0b0100100001011000, // 6.25
};
typedef enum State {
SPECTRUM,
FREQ_INPUT,
STILL,
} State;
typedef enum StepsCount {
STEPS_128,
STEPS_64,
STEPS_32,
STEPS_16,
} StepsCount;
typedef enum ScanStep {
S_STEP_0_01kHz,
S_STEP_0_1kHz,
S_STEP_0_5kHz,
S_STEP_1_0kHz,
S_STEP_2_5kHz,
S_STEP_5_0kHz,
S_STEP_6_25kHz,
S_STEP_8_33kHz,
S_STEP_10_0kHz,
S_STEP_12_5kHz,
S_STEP_15_0kHz,
S_STEP_20_0kHz,
S_STEP_25_0kHz,
S_STEP_50_0kHz,
S_STEP_100_0kHz,
} ScanStep;
typedef struct SpectrumSettings {
uint32_t frequencyChangeStep;
StepsCount stepsCount;
ScanStep scanStepIndex;
uint16_t scanDelay;
uint16_t rssiTriggerLevel;
BK4819_FilterBandwidth_t bw;
BK4819_FilterBandwidth_t listenBw;
int dbMin;
int dbMax;
ModulationMode_t modulationType;
bool backlightState;
} SpectrumSettings;
typedef struct KeyboardState {
KEY_Code_t current;
KEY_Code_t prev;
uint8_t counter;
} KeyboardState;
typedef struct ScanInfo {
uint16_t rssi, rssiMin, rssiMax;
uint16_t i, iPeak;
uint32_t f, fPeak;
uint16_t scanStep;
uint16_t measurementsCount;
} ScanInfo;
typedef struct PeakInfo {
uint16_t t;
uint16_t rssi;
uint32_t f;
uint16_t i;
} PeakInfo;
void APP_RunSpectrum(void);
#endif /* ifndef SPECTRUM_H */
// vim: ft=c

624
app/uart.c Normal file
View File

@@ -0,0 +1,624 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#if !defined(ENABLE_OVERLAY)
#include "ARMCM0.h"
#endif
#ifdef ENABLE_FMRADIO
#include "app/fm.h"
#endif
#include "app/uart.h"
#include "board.h"
#include "bsp/dp32g030/dma.h"
#include "bsp/dp32g030/gpio.h"
#include "driver/aes.h"
#include "driver/backlight.h"
#include "driver/bk4819.h"
#include "driver/crc.h"
#include "driver/eeprom.h"
#include "driver/gpio.h"
#include "driver/uart.h"
#include "functions.h"
#include "misc.h"
#include "settings.h"
#include "version.h"
#if defined(ENABLE_OVERLAY)
#include "sram-overlay.h"
#endif
#define DMA_INDEX(x, y) (((x) + (y)) % sizeof(UART_DMA_Buffer))
typedef struct {
uint16_t ID;
uint16_t Size;
} Header_t;
typedef struct {
uint8_t Padding[2];
uint16_t ID;
} Footer_t;
typedef struct {
Header_t Header;
uint32_t Timestamp;
} CMD_0514_t;
typedef struct {
Header_t Header;
struct {
char Version[16];
bool bHasCustomAesKey;
bool bIsInLockScreen;
uint8_t Padding[2];
uint32_t Challenge[4];
} Data;
} REPLY_0514_t;
typedef struct {
Header_t Header;
uint16_t Offset;
uint8_t Size;
uint8_t Padding;
uint32_t Timestamp;
} CMD_051B_t;
typedef struct {
Header_t Header;
struct {
uint16_t Offset;
uint8_t Size;
uint8_t Padding;
uint8_t Data[128];
} Data;
} REPLY_051B_t;
typedef struct {
Header_t Header;
uint16_t Offset;
uint8_t Size;
bool bAllowPassword;
uint32_t Timestamp;
uint8_t Data[0];
} CMD_051D_t;
typedef struct {
Header_t Header;
struct {
uint16_t Offset;
} Data;
} REPLY_051D_t;
typedef struct {
Header_t Header;
struct {
uint16_t RSSI;
uint8_t ExNoiseIndicator;
uint8_t GlitchIndicator;
} Data;
} REPLY_0527_t;
typedef struct {
Header_t Header;
struct {
uint16_t Voltage;
uint16_t Current;
} Data;
} REPLY_0529_t;
typedef struct {
Header_t Header;
uint32_t Response[4];
} CMD_052D_t;
typedef struct {
Header_t Header;
struct {
bool bIsLocked;
uint8_t Padding[3];
} Data;
} REPLY_052D_t;
typedef struct {
Header_t Header;
uint32_t Timestamp;
} CMD_052F_t;
static const uint8_t Obfuscation[16] =
{
0x16, 0x6C, 0x14, 0xE6, 0x2E, 0x91, 0x0D, 0x40, 0x21, 0x35, 0xD5, 0x40, 0x13, 0x03, 0xE9, 0x80
};
static union
{
uint8_t Buffer[256];
struct
{
Header_t Header;
uint8_t Data[252];
};
} UART_Command;
static uint32_t Timestamp;
static uint16_t gUART_WriteIndex;
static bool bIsEncrypted = true;
static void SendReply(void *pReply, uint16_t Size)
{
Header_t Header;
Footer_t Footer;
if (bIsEncrypted)
{
uint8_t *pBytes = (uint8_t *)pReply;
unsigned int i;
for (i = 0; i < Size; i++)
pBytes[i] ^= Obfuscation[i % 16];
}
Header.ID = 0xCDAB;
Header.Size = Size;
UART_Send(&Header, sizeof(Header));
UART_Send(pReply, Size);
if (bIsEncrypted)
{
Footer.Padding[0] = Obfuscation[(Size + 0) % 16] ^ 0xFF;
Footer.Padding[1] = Obfuscation[(Size + 1) % 16] ^ 0xFF;
}
else
{
Footer.Padding[0] = 0xFF;
Footer.Padding[1] = 0xFF;
}
Footer.ID = 0xBADC;
UART_Send(&Footer, sizeof(Footer));
}
static void SendVersion(void)
{
REPLY_0514_t Reply;
Reply.Header.ID = 0x0515;
Reply.Header.Size = sizeof(Reply.Data);
strcpy(Reply.Data.Version, Version);
Reply.Data.bHasCustomAesKey = bHasCustomAesKey;
Reply.Data.bIsInLockScreen = bIsInLockScreen;
Reply.Data.Challenge[0] = gChallenge[0];
Reply.Data.Challenge[1] = gChallenge[1];
Reply.Data.Challenge[2] = gChallenge[2];
Reply.Data.Challenge[3] = gChallenge[3];
SendReply(&Reply, sizeof(Reply));
}
static bool IsBadChallenge(const uint32_t *pKey, const uint32_t *pIn, const uint32_t *pResponse)
{
unsigned int i;
uint32_t IV[4];
IV[0] = 0;
IV[1] = 0;
IV[2] = 0;
IV[3] = 0;
AES_Encrypt(pKey, IV, pIn, IV, true);
for (i = 0; i < 4; i++)
if (IV[i] != pResponse[i])
return true;
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;
Timestamp = pCmd->Timestamp;
#ifdef ENABLE_FMRADIO
gFmRadioCountdown_500ms = fm_radio_countdown_500ms;
#endif
gSerialConfigCountDown_500ms = 12; // 6 sec
// turn the LCD backlight off
BACKLIGHT_TurnOff();
SendVersion();
}
// read eeprom
static void CMD_051B(const uint8_t *pBuffer)
{
const CMD_051B_t *pCmd = (const CMD_051B_t *)pBuffer;
REPLY_051B_t Reply;
bool bLocked = false;
if (pCmd->Timestamp != Timestamp)
return;
gSerialConfigCountDown_500ms = 12; // 6 sec
#ifdef ENABLE_FMRADIO
gFmRadioCountdown_500ms = fm_radio_countdown_500ms;
#endif
memset(&Reply, 0, sizeof(Reply));
Reply.Header.ID = 0x051C;
Reply.Header.Size = pCmd->Size + 4;
Reply.Data.Offset = pCmd->Offset;
Reply.Data.Size = pCmd->Size;
if (bHasCustomAesKey)
bLocked = gIsLocked;
if (!bLocked)
EEPROM_ReadBuffer(pCmd->Offset, Reply.Data.Data, pCmd->Size);
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;
REPLY_051D_t Reply;
bool bReloadEeprom;
bool bIsLocked;
if (pCmd->Timestamp != Timestamp)
return;
gSerialConfigCountDown_500ms = 12; // 6 sec
bReloadEeprom = false;
#ifdef ENABLE_FMRADIO
gFmRadioCountdown_500ms = fm_radio_countdown_500ms;
#endif
Reply.Header.ID = 0x051E;
Reply.Header.Size = sizeof(Reply.Data);
Reply.Data.Offset = pCmd->Offset;
bIsLocked = bHasCustomAesKey ? gIsLocked : bHasCustomAesKey;
if (!bIsLocked)
{
unsigned int i;
for (i = 0; i < (pCmd->Size / 8); i++)
{
const uint16_t Offset = pCmd->Offset + (i * 8U);
if (Offset >= 0x0F30 && Offset < 0x0F40)
if (!gIsLocked)
bReloadEeprom = true;
if ((Offset < 0x0E98 || Offset >= 0x0EA0) || !bIsInLockScreen || pCmd->bAllowPassword)
EEPROM_WriteBuffer(Offset, &pCmd->Data[i * 8U]);
}
if (bReloadEeprom)
SETTINGS_InitEEPROM();
}
SendReply(&Reply, sizeof(Reply));
}
// read RSSI
static void CMD_0527(void)
{
REPLY_0527_t Reply;
Reply.Header.ID = 0x0528;
Reply.Header.Size = sizeof(Reply.Data);
Reply.Data.RSSI = BK4819_ReadRegister(BK4819_REG_67) & 0x01FF;
Reply.Data.ExNoiseIndicator = BK4819_ReadRegister(BK4819_REG_65) & 0x007F;
Reply.Data.GlitchIndicator = BK4819_ReadRegister(BK4819_REG_63);
SendReply(&Reply, sizeof(Reply));
}
// read ADC
static void CMD_0529(void)
{
REPLY_0529_t Reply;
Reply.Header.ID = 0x52A;
Reply.Header.Size = sizeof(Reply.Data);
// Original doesn't actually send current!
BOARD_ADC_GetBatteryInfo(&Reply.Data.Voltage, &Reply.Data.Current);
SendReply(&Reply, sizeof(Reply));
}
static void CMD_052D(const uint8_t *pBuffer)
{
const CMD_052D_t *pCmd = (const CMD_052D_t *)pBuffer;
REPLY_052D_t Reply;
bool bIsLocked;
#ifdef ENABLE_FMRADIO
gFmRadioCountdown_500ms = fm_radio_countdown_500ms;
#endif
Reply.Header.ID = 0x052E;
Reply.Header.Size = sizeof(Reply.Data);
bIsLocked = bHasCustomAesKey;
if (!bIsLocked)
bIsLocked = IsBadChallenge(gCustomAesKey, gChallenge, pCmd->Response);
if (!bIsLocked)
{
bIsLocked = IsBadChallenge(gDefaultAesKey, gChallenge, pCmd->Response);
if (bIsLocked)
gTryCount++;
}
if (gTryCount < 3)
{
if (!bIsLocked)
gTryCount = 0;
}
else
{
gTryCount = 3;
bIsLocked = true;
}
gIsLocked = bIsLocked;
Reply.Data.bIsLocked = bIsLocked;
SendReply(&Reply, sizeof(Reply));
}
// session init, sends back version info and state
// timestamp is a session id really
// this command also disables dual watch, crossband,
// DTMF side tones, freq reverse, PTT ID, DTMF decoding, frequency offset
// exits power save, sets main VFO to upper,
static void CMD_052F(const uint8_t *pBuffer)
{
const CMD_052F_t *pCmd = (const CMD_052F_t *)pBuffer;
gEeprom.DUAL_WATCH = DUAL_WATCH_OFF;
gEeprom.CROSS_BAND_RX_TX = CROSS_BAND_OFF;
gEeprom.RX_VFO = 0;
gEeprom.DTMF_SIDE_TONE = false;
gEeprom.VfoInfo[0].FrequencyReverse = false;
gEeprom.VfoInfo[0].pRX = &gEeprom.VfoInfo[0].freq_config_RX;
gEeprom.VfoInfo[0].pTX = &gEeprom.VfoInfo[0].freq_config_TX;
gEeprom.VfoInfo[0].TX_OFFSET_FREQUENCY_DIRECTION = TX_OFFSET_FREQUENCY_DIRECTION_OFF;
gEeprom.VfoInfo[0].DTMF_PTT_ID_TX_MODE = PTT_ID_OFF;
#ifdef ENABLE_DTMF_CALLING
gEeprom.VfoInfo[0].DTMF_DECODING_ENABLE = false;
#endif
#ifdef ENABLE_NOAA
gIsNoaaMode = false;
#endif
if (gCurrentFunction == FUNCTION_POWER_SAVE)
FUNCTION_Select(FUNCTION_FOREGROUND);
gSerialConfigCountDown_500ms = 12; // 6 sec
Timestamp = pCmd->Timestamp;
// turn the LCD backlight off
BACKLIGHT_TurnOff();
SendVersion();
}
#ifdef ENABLE_UART_RW_BK_REGS
static void CMD_0601_ReadBK4819Reg(const uint8_t *pBuffer)
{
typedef struct __attribute__((__packed__)) {
Header_t header;
uint8_t reg;
} CMD_0601_t;
CMD_0601_t *cmd = (CMD_0601_t*) pBuffer;
struct __attribute__((__packed__)) {
Header_t header;
struct __attribute__((__packed__)) {
uint8_t reg;
uint16_t value;
} data;
} reply;
reply.header.ID = 0x0601;
reply.header.Size = sizeof(reply.data);
reply.data.reg = cmd->reg;
reply.data.value = BK4819_ReadRegister(cmd->reg);
SendReply(&reply, sizeof(reply));
}
static void CMD_0602_WriteBK4819Reg(const uint8_t *pBuffer)
{
typedef struct __attribute__((__packed__)) {
Header_t header;
uint8_t reg;
uint16_t value;
} CMD_0602_t;
CMD_0602_t *cmd = (CMD_0602_t*) pBuffer;
BK4819_WriteRegister(cmd->reg, cmd->value);
}
#endif
bool UART_IsCommandAvailable(void)
{
uint16_t Index;
uint16_t TailIndex;
uint16_t Size;
uint16_t CRC;
uint16_t CommandLength;
uint16_t DmaLength = DMA_CH0->ST & 0xFFFU;
while (1)
{
if (gUART_WriteIndex == DmaLength)
return false;
while (gUART_WriteIndex != DmaLength && UART_DMA_Buffer[gUART_WriteIndex] != 0xABU)
gUART_WriteIndex = DMA_INDEX(gUART_WriteIndex, 1);
if (gUART_WriteIndex == DmaLength)
return false;
if (gUART_WriteIndex < DmaLength)
CommandLength = DmaLength - gUART_WriteIndex;
else
CommandLength = (DmaLength + sizeof(UART_DMA_Buffer)) - gUART_WriteIndex;
if (CommandLength < 8)
return 0;
if (UART_DMA_Buffer[DMA_INDEX(gUART_WriteIndex, 1)] == 0xCD)
break;
gUART_WriteIndex = DMA_INDEX(gUART_WriteIndex, 1);
}
Index = DMA_INDEX(gUART_WriteIndex, 2);
Size = (UART_DMA_Buffer[DMA_INDEX(Index, 1)] << 8) | UART_DMA_Buffer[Index];
if ((Size + 8u) > sizeof(UART_DMA_Buffer))
{
gUART_WriteIndex = DmaLength;
return false;
}
if (CommandLength < (Size + 8))
return false;
Index = DMA_INDEX(Index, 2);
TailIndex = DMA_INDEX(Index, Size + 2);
if (UART_DMA_Buffer[TailIndex] != 0xDC || UART_DMA_Buffer[DMA_INDEX(TailIndex, 1)] != 0xBA)
{
gUART_WriteIndex = DmaLength;
return false;
}
if (TailIndex < Index)
{
const uint16_t ChunkSize = sizeof(UART_DMA_Buffer) - Index;
memcpy(UART_Command.Buffer, UART_DMA_Buffer + Index, ChunkSize);
memcpy(UART_Command.Buffer + ChunkSize, UART_DMA_Buffer, TailIndex);
}
else
memcpy(UART_Command.Buffer, UART_DMA_Buffer + Index, TailIndex - Index);
TailIndex = DMA_INDEX(TailIndex, 2);
if (TailIndex < gUART_WriteIndex)
{
memset(UART_DMA_Buffer + gUART_WriteIndex, 0, sizeof(UART_DMA_Buffer) - gUART_WriteIndex);
memset(UART_DMA_Buffer, 0, TailIndex);
}
else
memset(UART_DMA_Buffer + gUART_WriteIndex, 0, TailIndex - gUART_WriteIndex);
gUART_WriteIndex = TailIndex;
if (UART_Command.Header.ID == 0x0514)
bIsEncrypted = false;
if (UART_Command.Header.ID == 0x6902)
bIsEncrypted = true;
if (bIsEncrypted)
{
unsigned int i;
for (i = 0; i < (Size + 2u); i++)
UART_Command.Buffer[i] ^= Obfuscation[i % 16];
}
CRC = UART_Command.Buffer[Size] | (UART_Command.Buffer[Size + 1] << 8);
return (CRC_Calculate(UART_Command.Buffer, Size) != CRC) ? false : true;
}
void UART_HandleCommand(void)
{
switch (UART_Command.Header.ID)
{
case 0x0514:
CMD_0514(UART_Command.Buffer);
break;
case 0x051B:
CMD_051B(UART_Command.Buffer);
break;
case 0x051D:
CMD_051D(UART_Command.Buffer);
break;
case 0x051F: // Not implementing non-authentic command
break;
case 0x0521: // Not implementing non-authentic command
break;
case 0x0527:
CMD_0527();
break;
case 0x0529:
CMD_0529();
break;
case 0x052D:
CMD_052D(UART_Command.Buffer);
break;
case 0x052F:
CMD_052F(UART_Command.Buffer);
break;
case 0x05DD: // reset
#if defined(ENABLE_OVERLAY)
overlay_FLASH_RebootToBootloader();
#else
NVIC_SystemReset();
#endif
break;
#ifdef ENABLE_UART_RW_BK_REGS
case 0x0601:
CMD_0601_ReadBK4819Reg(UART_Command.Buffer);
break;
case 0x0602:
CMD_0602_WriteBK4819Reg(UART_Command.Buffer);
break;
#endif
}
}

26
app/uart.h Normal file
View File

@@ -0,0 +1,26 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef APP_UART_H
#define APP_UART_H
#include <stdbool.h>
bool UART_IsCommandAvailable(void);
void UART_HandleCommand(void);
#endif

442
audio.c Normal file
View File

@@ -0,0 +1,442 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef ENABLE_FMRADIO
#include "app/fm.h"
#endif
#include "audio.h"
#include "bsp/dp32g030/gpio.h"
#ifdef ENABLE_FMRADIO
#include "driver/bk1080.h"
#endif
#include "driver/bk4819.h"
#include "driver/gpio.h"
#include "driver/system.h"
#include "driver/systick.h"
#include "functions.h"
#include "misc.h"
#include "settings.h"
#include "ui/ui.h"
BEEP_Type_t gBeepToPlay = BEEP_NONE;
void AUDIO_PlayBeep(BEEP_Type_t Beep)
{
if (Beep != BEEP_880HZ_60MS_TRIPLE_BEEP &&
Beep != BEEP_500HZ_60MS_DOUBLE_BEEP &&
Beep != BEEP_440HZ_500MS &&
Beep != BEEP_880HZ_200MS &&
Beep != BEEP_880HZ_500MS &&
!gEeprom.BEEP_CONTROL)
return;
#ifdef ENABLE_AIRCOPY
if (gScreenToDisplay == DISPLAY_AIRCOPY)
return;
#endif
if (gCurrentFunction == FUNCTION_RECEIVE)
return;
if (gCurrentFunction == FUNCTION_MONITOR)
return;
#ifdef ENABLE_FMRADIO
if (gFmRadioMode)
BK1080_Mute(true);
#endif
AUDIO_AudioPathOff();
if (gCurrentFunction == FUNCTION_POWER_SAVE && gRxIdleMode)
BK4819_RX_TurnOn();
SYSTEM_DelayMs(20);
uint16_t ToneConfig = BK4819_ReadRegister(BK4819_REG_71);
uint16_t ToneFrequency;
switch (Beep)
{
default:
case BEEP_NONE:
ToneFrequency = 220;
break;
case BEEP_1KHZ_60MS_OPTIONAL:
ToneFrequency = 1000;
break;
case BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL:
case BEEP_500HZ_60MS_DOUBLE_BEEP:
ToneFrequency = 500;
break;
case BEEP_440HZ_40MS_OPTIONAL:
case BEEP_440HZ_500MS:
ToneFrequency = 440;
break;
case BEEP_880HZ_40MS_OPTIONAL:
case BEEP_880HZ_60MS_TRIPLE_BEEP:
case BEEP_880HZ_200MS:
case BEEP_880HZ_500MS:
ToneFrequency = 880;
break;
}
BK4819_PlayTone(ToneFrequency, true);
SYSTEM_DelayMs(2);
AUDIO_AudioPathOn();
SYSTEM_DelayMs(60);
uint16_t Duration;
switch (Beep)
{
case BEEP_880HZ_60MS_TRIPLE_BEEP:
BK4819_ExitTxMute();
SYSTEM_DelayMs(60);
BK4819_EnterTxMute();
SYSTEM_DelayMs(20);
__attribute__((fallthrough));
case BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL:
case BEEP_500HZ_60MS_DOUBLE_BEEP:
BK4819_ExitTxMute();
SYSTEM_DelayMs(60);
BK4819_EnterTxMute();
SYSTEM_DelayMs(20);
__attribute__((fallthrough));
case BEEP_1KHZ_60MS_OPTIONAL:
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:
BK4819_ExitTxMute();
Duration = 500;
break;
}
SYSTEM_DelayMs(Duration);
BK4819_EnterTxMute();
SYSTEM_DelayMs(20);
AUDIO_AudioPathOff();
SYSTEM_DelayMs(5);
BK4819_TurnsOffTones_TurnsOnRX();
SYSTEM_DelayMs(5);
BK4819_WriteRegister(BK4819_REG_71, ToneConfig);
if (gEnableSpeaker)
AUDIO_AudioPathOn();
#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
static const uint8_t VoiceClipLengthChinese[58] =
{
0x32, 0x32, 0x32, 0x37, 0x37, 0x32, 0x32, 0x32,
0x32, 0x37, 0x37, 0x32, 0x64, 0x64, 0x64, 0x64,
0x64, 0x69, 0x64, 0x69, 0x5A, 0x5F, 0x5F, 0x64,
0x64, 0x69, 0x64, 0x64, 0x69, 0x69, 0x69, 0x64,
0x64, 0x6E, 0x69, 0x5F, 0x64, 0x64, 0x64, 0x69,
0x69, 0x69, 0x64, 0x69, 0x64, 0x64, 0x55, 0x5F,
0x5A, 0x4B, 0x4B, 0x46, 0x46, 0x69, 0x64, 0x6E,
0x5A, 0x64,
};
static const uint8_t VoiceClipLengthEnglish[76] =
{
0x50, 0x32, 0x2D, 0x2D, 0x2D, 0x37, 0x37, 0x37,
0x32, 0x32, 0x3C, 0x37, 0x46, 0x46, 0x4B, 0x82,
0x82, 0x6E, 0x82, 0x46, 0x96, 0x64, 0x46, 0x6E,
0x78, 0x6E, 0x87, 0x64, 0x96, 0x96, 0x46, 0x9B,
0x91, 0x82, 0x82, 0x73, 0x78, 0x64, 0x82, 0x6E,
0x78, 0x82, 0x87, 0x6E, 0x55, 0x78, 0x64, 0x69,
0x9B, 0x5A, 0x50, 0x3C, 0x32, 0x55, 0x64, 0x64,
0x50, 0x46, 0x46, 0x46, 0x4B, 0x4B, 0x50, 0x50,
0x55, 0x4B, 0x4B, 0x32, 0x32, 0x32, 0x32, 0x37,
0x41, 0x32, 0x3C, 0x37,
};
VOICE_ID_t gVoiceID[8];
uint8_t gVoiceReadIndex;
uint8_t gVoiceWriteIndex;
volatile uint16_t gCountdownToPlayNextVoice_10ms;
volatile bool gFlagPlayQueuedVoice;
VOICE_ID_t gAnotherVoiceID = VOICE_ID_INVALID;
static void AUDIO_PlayVoice(uint8_t VoiceID)
{
unsigned int i;
GPIO_SetBit(&GPIOA->DATA, GPIOA_PIN_VOICE_0);
SYSTEM_DelayMs(20);
GPIO_ClearBit(&GPIOA->DATA, GPIOA_PIN_VOICE_0);
for (i = 0; i < 8; i++)
{
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);
}
}
void AUDIO_PlaySingleVoice(bool bFlag)
{
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)
{
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
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;
}
}
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

158
audio.h Normal file
View File

@@ -0,0 +1,158 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef AUDIO_H
#define AUDIO_H
#include <stdbool.h>
#include <stdint.h>
#include "bsp/dp32g030/gpio.h"
#include "driver/gpio.h"
enum BEEP_Type_t
{
BEEP_NONE = 0,
BEEP_1KHZ_60MS_OPTIONAL,
BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL,
BEEP_440HZ_500MS,
BEEP_880HZ_200MS,
BEEP_880HZ_500MS,
BEEP_500HZ_60MS_DOUBLE_BEEP,
BEEP_440HZ_40MS_OPTIONAL,
BEEP_880HZ_40MS_OPTIONAL,
BEEP_880HZ_60MS_TRIPLE_BEEP
};
typedef enum BEEP_Type_t BEEP_Type_t;
extern BEEP_Type_t gBeepToPlay;
void AUDIO_PlayBeep(BEEP_Type_t Beep);
enum
{
VOICE_ID_CHI_BASE = 0x10U,
VOICE_ID_ENG_BASE = 0x60U,
};
enum VOICE_ID_t
{
VOICE_ID_0 = 0x00U,
VOICE_ID_1 = 0x01U,
VOICE_ID_2 = 0x02U,
VOICE_ID_3 = 0x03U,
VOICE_ID_4 = 0x04U,
VOICE_ID_5 = 0x05U,
VOICE_ID_6 = 0x06U,
VOICE_ID_7 = 0x07U,
VOICE_ID_8 = 0x08U,
VOICE_ID_9 = 0x09U,
VOICE_ID_10 = 0x0AU,
VOICE_ID_100 = 0x0BU,
VOICE_ID_WELCOME = 0x0CU,
VOICE_ID_LOCK = 0x0DU,
VOICE_ID_UNLOCK = 0x0EU,
VOICE_ID_SCANNING_BEGIN = 0x0FU,
VOICE_ID_SCANNING_STOP = 0x10U,
VOICE_ID_SCRAMBLER_ON = 0x11U,
VOICE_ID_SCRAMBLER_OFF = 0x12U,
VOICE_ID_FUNCTION = 0x13U,
VOICE_ID_CTCSS = 0x14U,
VOICE_ID_DCS = 0x15U,
VOICE_ID_POWER = 0x16U,
VOICE_ID_SAVE_MODE = 0x17U,
VOICE_ID_MEMORY_CHANNEL = 0x18U,
VOICE_ID_DELETE_CHANNEL = 0x19U,
VOICE_ID_FREQUENCY_STEP = 0x1AU,
VOICE_ID_SQUELCH = 0x1BU,
VOICE_ID_TRANSMIT_OVER_TIME = 0x1CU,
VOICE_ID_BACKLIGHT_SELECTION = 0x1DU,
VOICE_ID_VOX = 0x1EU,
VOICE_ID_TX_OFFSET_FREQUENCY_DIRECTION = 0x1FU,
VOICE_ID_TX_OFFSET_FREQUENCY = 0x20U,
VOICE_ID_TRANSMITING_MEMORY = 0x21U,
VOICE_ID_RECEIVING_MEMORY = 0x22U,
VOICE_ID_EMERGENCY_CALL = 0x23U,
VOICE_ID_LOW_VOLTAGE = 0x24U,
VOICE_ID_CHANNEL_MODE = 0x25U,
VOICE_ID_FREQUENCY_MODE = 0x26U,
VOICE_ID_VOICE_PROMPT = 0x27U,
VOICE_ID_BAND_SELECTION = 0x28U,
VOICE_ID_DUAL_STANDBY = 0x29U,
VOICE_ID_CHANNEL_BANDWIDTH = 0x2AU,
VOICE_ID_OPTIONAL_SIGNAL = 0x2BU,
VOICE_ID_MUTE_MODE = 0x2CU,
VOICE_ID_BUSY_LOCKOUT = 0x2DU,
VOICE_ID_BEEP_PROMPT = 0x2EU,
VOICE_ID_ANI_CODE = 0x2FU,
VOICE_ID_INITIALISATION = 0x30U,
VOICE_ID_CONFIRM = 0x31U,
VOICE_ID_CANCEL = 0x32U,
VOICE_ID_ON = 0x33U,
VOICE_ID_OFF = 0x34U,
VOICE_ID_2_TONE = 0x35U,
VOICE_ID_5_TONE = 0x36U,
VOICE_ID_DIGITAL_SIGNAL = 0x37U,
VOICE_ID_REPEATER = 0x38U,
VOICE_ID_MENU = 0x39U,
VOICE_ID_11 = 0x3AU,
VOICE_ID_12 = 0x3BU,
VOICE_ID_13 = 0x3CU,
VOICE_ID_14 = 0x3DU,
VOICE_ID_15 = 0x3EU,
VOICE_ID_16 = 0x3FU,
VOICE_ID_17 = 0x40U,
VOICE_ID_18 = 0x41U,
VOICE_ID_19 = 0x42U,
VOICE_ID_20 = 0x43U,
VOICE_ID_30 = 0x44U,
VOICE_ID_40 = 0x45U,
VOICE_ID_50 = 0x46U,
VOICE_ID_60 = 0x47U,
VOICE_ID_70 = 0x48U,
VOICE_ID_80 = 0x49U,
VOICE_ID_90 = 0x4AU,
VOICE_ID_END = 0x4BU,
VOICE_ID_INVALID = 0xFFU,
};
typedef enum VOICE_ID_t VOICE_ID_t;
static inline void AUDIO_AudioPathOn(void) {
GPIO_SetBit(&GPIOC->DATA, GPIOC_PIN_AUDIO_PATH);
}
static inline void AUDIO_AudioPathOff(void) {
GPIO_ClearBit(&GPIOC->DATA, GPIOC_PIN_AUDIO_PATH);
}
#ifdef ENABLE_VOICE
extern VOICE_ID_t gVoiceID[8];
extern uint8_t gVoiceReadIndex;
extern uint8_t gVoiceWriteIndex;
extern volatile uint16_t gCountdownToPlayNextVoice_10ms;
extern volatile bool gFlagPlayQueuedVoice;
extern VOICE_ID_t gAnotherVoiceID;
void AUDIO_PlaySingleVoice(bool bFlag);
void AUDIO_SetVoiceID(uint8_t Index, VOICE_ID_t VoiceID);
uint8_t AUDIO_SetDigitVoice(uint8_t Index, uint16_t Value);
void AUDIO_PlayQueuedVoice(void);
#endif
#endif

327
bitmaps.c Normal file
View File

@@ -0,0 +1,327 @@
#include "bitmaps.h"
// all these images are on their right sides
// turn your monitor 90-deg anti-clockwise to see the images
const uint8_t BITMAP_POWERSAVE[8] =
{
// "PS"
0b00000000,
0b01111111,
0b00010001,
0b00001110,
0b00000000,
0b01000110,
0b01001001,
0b00110001
};
const uint8_t BITMAP_TX[8] =
{ // "TX"
0b00000000,
0b00000001,
0b00000001,
0b01111111,
0b00000001,
0b00000001,
0b00000000,
0b00000000
};
const uint8_t BITMAP_RX[8] =
{ // "RX"
0b00000000,
0b01111111,
0b00001001,
0b00011001,
0b01100110,
0b00000000,
0b00000000,
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,
0b01011101
};
#ifndef ENABLE_REVERSE_BAT_SYMBOL
// Quansheng way (+ pole to the left)
const uint8_t BITMAP_BatteryLevel1[17] =
{
0b00000000,
0b00111110,
0b00100010,
0b01000001,
0b01000001,
0b01000001,
0b01000001,
0b01000001,
0b01000001,
0b01000001,
0b01000001,
0b01000001,
0b01000001,
0b01000001,
0b01000001,
0b01000001,
0b01111111
};
#else
// reversed (+ pole to the right)
const uint8_t BITMAP_BatteryLevel1[17] =
{
0b00000000,
0b01111111,
0b01000001,
0b01000001,
0b01000001,
0b01000001,
0b01000001,
0b01000001,
0b01000001,
0b01000001,
0b01000001,
0b01000001,
0b01000001,
0b01000001,
0b01000001,
0b00100010,
0b00111110
};
#endif
const uint8_t BITMAP_USB_C[9] =
{ // USB symbol
0b00000000,
0b00011100,
0b00100111,
0b01000100,
0b01000100,
0b01000100,
0b01000100,
0b00100111,
0b00011100
};
const uint8_t BITMAP_KeyLock[6] =
{ // teeny padlock symbol
0b00000000,
0b01111100,
0b01000110,
0b01000101,
0b01000110,
0b01111100
};
const uint8_t BITMAP_F_Key[6] =
{ // F-Key symbol
0b00000000,
0b01011111,
0b01000101,
0b01000101,
0b01000101,
0b01000001
};
#ifdef ENABLE_VOX
const uint8_t BITMAP_VOX[18] =
{ // "VOX"
0b00000000,
0b00011111,
0b00100000,
0b01000000,
0b00100000,
0b00011111,
0b00000000,
0b00111110,
0b01000001,
0b01000001,
0b01000001,
0b00111110,
0b00000000,
0b01100011,
0b00010100,
0b00001000,
0b00010100,
0b01100011
};
#endif
// '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,
0b00111110,
0b00000000,
0b01111111,
0b00100000,
0b00011000,
0b00100000,
0b01111111,
0b00000000,
0b01111111,
0b00011001,
0b00101001,
0b01000110
};
const uint8_t BITMAP_TDR2[10] =
{ // "><" .. DW on hold
0b00000000,
0b00100010,
0b00110110,
0b00011100,
0b00001000,
0b00000000,
0b00001000,
0b00011100,
0b00110110,
0b00100010,
};
#ifdef ENABLE_VOICE
const uint8_t BITMAP_VoicePrompt[9] =
{
0b00000000,
0b00011000,
0b00011000,
0b00100100,
0b00100100,
0b01000010,
0b01000010,
0b11111111,
0b00011000
};
#endif
#ifdef ENABLE_NOAA
const uint8_t BITMAP_NOAA[11] =
{ // "NS"
0b00000000,
0b01111111,
0b00000100,
0b00001000,
0b00010000,
0b01111111,
0b00000000,
0b01000110,
0b01001001,
0b01001001,
0b00110001
};
#endif
const uint8_t BITMAP_Antenna[5] =
{
0b00000011,
0b00000101,
0b01111111,
0b00000101,
0b00000011
};
const uint8_t BITMAP_VFO_Default[8] =
{
0b00000000,
0b01111111,
0b01111111,
0b00111110,
0b00111110,
0b00011100,
0b00011100,
0b00001000
};
const uint8_t BITMAP_VFO_NotDefault[8] =
{
0b00000000,
0b01000001,
0b01000001,
0b00100010,
0b00100010,
0b00010100,
0b00010100,
0b00001000
};
const uint8_t BITMAP_ScanList1[6] =
{ // 'I' symbol
0b00000000,
0b00000000,
0b01000010,
0b01111110,
0b01000010,
0b00000000
};
const uint8_t BITMAP_ScanList2[6] =
{ // 'II' symbol
0b00000000,
0b01000010,
0b01111110,
0b01000010,
0b01111110,
0b01000010
};
const uint8_t BITMAP_compand[6] =
{
0b00000000,
0b00111100,
0b01000010,
0b01000010,
0b01000010,
0b00100100
};
#ifndef ENABLE_CUSTOM_MENU_LAYOUT
const uint8_t BITMAP_CurrentIndicator[8] = {
0xFF,
0xFF,
0x7E,
0x7E,
0x3C,
0x3C,
0x18,
0x18
};
#endif

51
bitmaps.h Normal file
View File

@@ -0,0 +1,51 @@
#ifndef BITMAP_H
#define BITMAP_H
#include <stdint.h>
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];
extern const uint8_t BITMAP_USB_C[9];
extern const uint8_t BITMAP_KeyLock[6];
extern const uint8_t BITMAP_F_Key[6];
#ifdef ENABLE_VOX
extern const uint8_t BITMAP_VOX[18];
#endif
extern const uint8_t BITMAP_XB[12];
extern const uint8_t BITMAP_TDR1[16];
extern const uint8_t BITMAP_TDR2[10];
#ifdef ENABLE_VOICE
extern const uint8_t BITMAP_VoicePrompt[9];
#endif
#ifdef ENABLE_NOAA
extern const uint8_t BITMAP_NOAA[11];
#endif
extern const uint8_t BITMAP_Antenna[5];
extern const uint8_t BITMAP_VFO_Default[8];
extern const uint8_t BITMAP_VFO_NotDefault[8];
extern const uint8_t BITMAP_ScanList1[6];
extern const uint8_t BITMAP_ScanList2[6];
extern const uint8_t BITMAP_compand[6];
#ifndef ENABLE_CUSTOM_MENU_LAYOUT
extern const uint8_t BITMAP_CurrentIndicator[8];
#endif
#endif

505
board.c Normal file
View File

@@ -0,0 +1,505 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#ifdef ENABLE_FMRADIO
#include "app/fm.h"
#endif
#include "board.h"
#include "bsp/dp32g030/gpio.h"
#include "bsp/dp32g030/portcon.h"
#include "bsp/dp32g030/saradc.h"
#include "bsp/dp32g030/syscon.h"
#include "driver/adc.h"
#include "driver/backlight.h"
#ifdef ENABLE_FMRADIO
#include "driver/bk1080.h"
#endif
#include "driver/crc.h"
#include "driver/eeprom.h"
#include "driver/flash.h"
#include "driver/gpio.h"
#include "driver/system.h"
#include "driver/st7565.h"
#include "frequencies.h"
#include "helper/battery.h"
#include "misc.h"
#include "settings.h"
#if defined(ENABLE_OVERLAY)
#include "sram-overlay.h"
#endif
#if defined(ENABLE_OVERLAY)
void BOARD_FLASH_Init(void)
{
FLASH_Init(FLASH_READ_MODE_1_CYCLE);
FLASH_ConfigureTrimValues();
SYSTEM_ConfigureClocks();
overlay_FLASH_MainClock = 48000000;
overlay_FLASH_ClockMultiplier = 48;
FLASH_Init(FLASH_READ_MODE_2_CYCLE);
}
#endif
void BOARD_GPIO_Init(void)
{
GPIOA->DIR |= 0
// A7 = UART1 TX default as OUTPUT from bootloader!
// A8 = UART1 RX default as INPUT from bootloader!
// Key pad + I2C
| GPIO_DIR_10_BITS_OUTPUT
// Key pad + I2C
| GPIO_DIR_11_BITS_OUTPUT
// Key pad + Voice chip
| GPIO_DIR_12_BITS_OUTPUT
// Key pad + Voice chip
| GPIO_DIR_13_BITS_OUTPUT
;
GPIOA->DIR &= ~(0
// Key pad
| GPIO_DIR_3_MASK // INPUT
// Key pad
| GPIO_DIR_4_MASK // INPUT
// Key pad
| GPIO_DIR_5_MASK // INPUT
// Key pad
| GPIO_DIR_6_MASK // INPUT
);
GPIOB->DIR |= 0
// ST7565
| GPIO_DIR_9_BITS_OUTPUT
// ST7565 + SWD IO
| GPIO_DIR_11_BITS_OUTPUT
// B14 = SWD_CLK assumed INPUT by default
// BK1080
| GPIO_DIR_15_BITS_OUTPUT
;
GPIOC->DIR |= 0
// BK4819 SCN
| GPIO_DIR_0_BITS_OUTPUT
// BK4819 SCL
| GPIO_DIR_1_BITS_OUTPUT
// BK4819 SDA
| GPIO_DIR_2_BITS_OUTPUT
// Flash light
| GPIO_DIR_3_BITS_OUTPUT
// Speaker
| GPIO_DIR_4_BITS_OUTPUT
;
GPIOC->DIR &= ~(0
// PTT button
| GPIO_DIR_5_MASK // INPUT
);
#if defined(ENABLE_FMRADIO)
GPIO_SetBit(&GPIOB->DATA, GPIOB_PIN_BK1080);
#endif
}
void BOARD_PORTCON_Init(void)
{
// PORT A pin selection
PORTCON_PORTA_SEL0 &= ~(0
// Key pad
| PORTCON_PORTA_SEL0_A3_MASK
// Key pad
| PORTCON_PORTA_SEL0_A4_MASK
// Key pad
| PORTCON_PORTA_SEL0_A5_MASK
// Key pad
| PORTCON_PORTA_SEL0_A6_MASK
);
PORTCON_PORTA_SEL0 |= 0
// Key pad
| PORTCON_PORTA_SEL0_A3_BITS_GPIOA3
// Key pad
| PORTCON_PORTA_SEL0_A4_BITS_GPIOA4
// Key pad
| PORTCON_PORTA_SEL0_A5_BITS_GPIOA5
// Key pad
| PORTCON_PORTA_SEL0_A6_BITS_GPIOA6
// UART1 TX, wasn't cleared in previous step / relying on default value!
| PORTCON_PORTA_SEL0_A7_BITS_UART1_TX
;
PORTCON_PORTA_SEL1 &= ~(0
// Key pad + I2C
| PORTCON_PORTA_SEL1_A10_MASK
// Key pad + I2C
| PORTCON_PORTA_SEL1_A11_MASK
// Key pad + Voice chip
| PORTCON_PORTA_SEL1_A12_MASK
// Key pad + Voice chip
| PORTCON_PORTA_SEL1_A13_MASK
);
PORTCON_PORTA_SEL1 |= 0
// UART1 RX, wasn't cleared in previous step / relying on default value!
| PORTCON_PORTA_SEL1_A8_BITS_UART1_RX
// Battery voltage, wasn't cleared in previous step / relying on default value!
| PORTCON_PORTA_SEL1_A9_BITS_SARADC_CH4
// Key pad + I2C
| PORTCON_PORTA_SEL1_A10_BITS_GPIOA10
// Key pad + I2C
| PORTCON_PORTA_SEL1_A11_BITS_GPIOA11
// Key pad + Voice chip
| PORTCON_PORTA_SEL1_A12_BITS_GPIOA12
// Key pad + Voice chip
| PORTCON_PORTA_SEL1_A13_BITS_GPIOA13
// Battery Current, wasn't cleared in previous step / relying on default value!
| PORTCON_PORTA_SEL1_A14_BITS_SARADC_CH9
;
// PORT B pin selection
PORTCON_PORTB_SEL0 &= ~(0
// SPI0 SSN
| PORTCON_PORTB_SEL0_B7_MASK
);
PORTCON_PORTB_SEL0 |= 0
// SPI0 SSN
| PORTCON_PORTB_SEL0_B7_BITS_SPI0_SSN
;
PORTCON_PORTB_SEL1 &= ~(0
// ST7565
| PORTCON_PORTB_SEL1_B9_MASK
// ST7565 + SWD IO
| PORTCON_PORTB_SEL1_B11_MASK
// SWD CLK
| PORTCON_PORTB_SEL1_B14_MASK
// BK1080
| PORTCON_PORTB_SEL1_B15_MASK
);
PORTCON_PORTB_SEL1 |= 0
// SPI0 CLK, wasn't cleared in previous step / relying on default value!
| PORTCON_PORTB_SEL1_B8_BITS_SPI0_CLK
// ST7565
| PORTCON_PORTB_SEL1_B9_BITS_GPIOB9
// SPI0 MOSI, wasn't cleared in previous step / relying on default value!
| PORTCON_PORTB_SEL1_B10_BITS_SPI0_MOSI
#if defined(ENABLE_SWD)
// SWD IO
| PORTCON_PORTB_SEL1_B11_BITS_SWDIO
// SWD CLK
| PORTCON_PORTB_SEL1_B14_BITS_SWCLK
#else
// ST7565
| PORTCON_PORTB_SEL1_B11_BITS_GPIOB11
#endif
;
// PORT C pin selection
PORTCON_PORTC_SEL0 &= ~(0
// BK4819 SCN
| PORTCON_PORTC_SEL0_C0_MASK
// BK4819 SCL
| PORTCON_PORTC_SEL0_C1_MASK
// BK4819 SDA
| PORTCON_PORTC_SEL0_C2_MASK
// Flash light
| PORTCON_PORTC_SEL0_C3_MASK
// Speaker
| PORTCON_PORTC_SEL0_C4_MASK
// PTT button
| PORTCON_PORTC_SEL0_C5_MASK
);
// PORT A pin configuration
PORTCON_PORTA_IE |= 0
// Keypad
| PORTCON_PORTA_IE_A3_BITS_ENABLE
// Keypad
| PORTCON_PORTA_IE_A4_BITS_ENABLE
// Keypad
| PORTCON_PORTA_IE_A5_BITS_ENABLE
// Keypad
| PORTCON_PORTA_IE_A6_BITS_ENABLE
// A7 = UART1 TX disabled by default
// UART1 RX
| PORTCON_PORTA_IE_A8_BITS_ENABLE
;
PORTCON_PORTA_IE &= ~(0
// Keypad + I2C
| PORTCON_PORTA_IE_A10_MASK
// Keypad + I2C
| PORTCON_PORTA_IE_A11_MASK
// Keypad + Voice chip
| PORTCON_PORTA_IE_A12_MASK
// Keypad + Voice chip
| PORTCON_PORTA_IE_A13_MASK
);
PORTCON_PORTA_PU |= 0
// Keypad
| PORTCON_PORTA_PU_A3_BITS_ENABLE
// Keypad
| PORTCON_PORTA_PU_A4_BITS_ENABLE
// Keypad
| PORTCON_PORTA_PU_A5_BITS_ENABLE
// Keypad
| PORTCON_PORTA_PU_A6_BITS_ENABLE
;
PORTCON_PORTA_PU &= ~(0
// Keypad + I2C
| PORTCON_PORTA_PU_A10_MASK
// Keypad + I2C
| PORTCON_PORTA_PU_A11_MASK
// Keypad + Voice chip
| PORTCON_PORTA_PU_A12_MASK
// Keypad + Voice chip
| PORTCON_PORTA_PU_A13_MASK
);
PORTCON_PORTA_PD &= ~(0
// Keypad
| PORTCON_PORTA_PD_A3_MASK
// Keypad
| PORTCON_PORTA_PD_A4_MASK
// Keypad
| PORTCON_PORTA_PD_A5_MASK
// Keypad
| PORTCON_PORTA_PD_A6_MASK
// Keypad + I2C
| PORTCON_PORTA_PD_A10_MASK
// Keypad + I2C
| PORTCON_PORTA_PD_A11_MASK
// Keypad + Voice chip
| PORTCON_PORTA_PD_A12_MASK
// Keypad + Voice chip
| PORTCON_PORTA_PD_A13_MASK
);
PORTCON_PORTA_OD |= 0
// Keypad
| PORTCON_PORTA_OD_A3_BITS_ENABLE
// Keypad
| PORTCON_PORTA_OD_A4_BITS_ENABLE
// Keypad
| PORTCON_PORTA_OD_A5_BITS_ENABLE
// Keypad
| PORTCON_PORTA_OD_A6_BITS_ENABLE
;
PORTCON_PORTA_OD &= ~(0
// Keypad + I2C
| PORTCON_PORTA_OD_A10_MASK
// Keypad + I2C
| PORTCON_PORTA_OD_A11_MASK
// Keypad + Voice chip
| PORTCON_PORTA_OD_A12_MASK
// Keypad + Voice chip
| PORTCON_PORTA_OD_A13_MASK
);
// PORT B pin configuration
PORTCON_PORTB_IE |= 0
| PORTCON_PORTB_IE_B14_BITS_ENABLE
;
PORTCON_PORTB_IE &= ~(0
// Back light
| PORTCON_PORTB_IE_B6_MASK
// UART1
| PORTCON_PORTB_IE_B7_MASK
| PORTCON_PORTB_IE_B8_MASK
// ST7565
| PORTCON_PORTB_IE_B9_MASK
// SPI0 MOSI
| PORTCON_PORTB_IE_B10_MASK
#if !defined(ENABLE_SWD)
// ST7565
| PORTCON_PORTB_IE_B11_MASK
#endif
// BK1080
| PORTCON_PORTB_IE_B15_MASK
);
PORTCON_PORTB_PU &= ~(0
// Back light
| PORTCON_PORTB_PU_B6_MASK
// ST7565
| PORTCON_PORTB_PU_B9_MASK
// ST7565 + SWD IO
| PORTCON_PORTB_PU_B11_MASK
// SWD CLK
| PORTCON_PORTB_PU_B14_MASK
// BK1080
| PORTCON_PORTB_PU_B15_MASK
);
PORTCON_PORTB_PD &= ~(0
// Back light
| PORTCON_PORTB_PD_B6_MASK
// ST7565
| PORTCON_PORTB_PD_B9_MASK
// ST7565 + SWD IO
| PORTCON_PORTB_PD_B11_MASK
// SWD CLK
| PORTCON_PORTB_PD_B14_MASK
// BK1080
| PORTCON_PORTB_PD_B15_MASK
);
PORTCON_PORTB_OD &= ~(0
// Back light
| PORTCON_PORTB_OD_B6_MASK
// ST7565
| PORTCON_PORTB_OD_B9_MASK
// ST7565 + SWD IO
| PORTCON_PORTB_OD_B11_MASK
// BK1080
| PORTCON_PORTB_OD_B15_MASK
);
PORTCON_PORTB_OD |= 0
// SWD CLK
| PORTCON_PORTB_OD_B14_BITS_ENABLE
;
// PORT C pin configuration
PORTCON_PORTC_IE |= 0
// PTT button
| PORTCON_PORTC_IE_C5_BITS_ENABLE
;
PORTCON_PORTC_IE &= ~(0
// BK4819 SCN
| PORTCON_PORTC_IE_C0_MASK
// BK4819 SCL
| PORTCON_PORTC_IE_C1_MASK
// BK4819 SDA
| PORTCON_PORTC_IE_C2_MASK
// Flash Light
| PORTCON_PORTC_IE_C3_MASK
// Speaker
| PORTCON_PORTC_IE_C4_MASK
);
PORTCON_PORTC_PU |= 0
// PTT button
| PORTCON_PORTC_PU_C5_BITS_ENABLE
;
PORTCON_PORTC_PU &= ~(0
// BK4819 SCN
| PORTCON_PORTC_PU_C0_MASK
// BK4819 SCL
| PORTCON_PORTC_PU_C1_MASK
// BK4819 SDA
| PORTCON_PORTC_PU_C2_MASK
// Flash Light
| PORTCON_PORTC_PU_C3_MASK
// Speaker
| PORTCON_PORTC_PU_C4_MASK
);
PORTCON_PORTC_PD &= ~(0
// BK4819 SCN
| PORTCON_PORTC_PD_C0_MASK
// BK4819 SCL
| PORTCON_PORTC_PD_C1_MASK
// BK4819 SDA
| PORTCON_PORTC_PD_C2_MASK
// Flash Light
| PORTCON_PORTC_PD_C3_MASK
// Speaker
| PORTCON_PORTC_PD_C4_MASK
// PTT Button
| PORTCON_PORTC_PD_C5_MASK
);
PORTCON_PORTC_OD &= ~(0
// BK4819 SCN
| PORTCON_PORTC_OD_C0_MASK
// BK4819 SCL
| PORTCON_PORTC_OD_C1_MASK
// BK4819 SDA
| PORTCON_PORTC_OD_C2_MASK
// Flash Light
| PORTCON_PORTC_OD_C3_MASK
// Speaker
| PORTCON_PORTC_OD_C4_MASK
);
PORTCON_PORTC_OD |= 0
// BK4819 SCN
| PORTCON_PORTC_OD_C0_BITS_DISABLE
// BK4819 SCL
| PORTCON_PORTC_OD_C1_BITS_DISABLE
// BK4819 SDA
| PORTCON_PORTC_OD_C2_BITS_DISABLE
// Flash Light
| PORTCON_PORTC_OD_C3_BITS_DISABLE
// Speaker
| PORTCON_PORTC_OD_C4_BITS_DISABLE
// PTT button
| PORTCON_PORTC_OD_C5_BITS_ENABLE
;
}
void BOARD_ADC_Init(void)
{
ADC_Config_t Config;
Config.CLK_SEL = SYSCON_CLK_SEL_W_SARADC_SMPL_VALUE_DIV2;
Config.CH_SEL = ADC_CH4 | ADC_CH9;
Config.AVG = SARADC_CFG_AVG_VALUE_8_SAMPLE;
Config.CONT = SARADC_CFG_CONT_VALUE_SINGLE;
Config.MEM_MODE = SARADC_CFG_MEM_MODE_VALUE_CHANNEL;
Config.SMPL_CLK = SARADC_CFG_SMPL_CLK_VALUE_INTERNAL;
Config.SMPL_WIN = SARADC_CFG_SMPL_WIN_VALUE_15_CYCLE;
Config.SMPL_SETUP = SARADC_CFG_SMPL_SETUP_VALUE_1_CYCLE;
Config.ADC_TRIG = SARADC_CFG_ADC_TRIG_VALUE_CPU;
Config.CALIB_KD_VALID = SARADC_CALIB_KD_VALID_VALUE_YES;
Config.CALIB_OFFSET_VALID = SARADC_CALIB_OFFSET_VALID_VALUE_YES;
Config.DMA_EN = SARADC_CFG_DMA_EN_VALUE_DISABLE;
Config.IE_CHx_EOC = SARADC_IE_CHx_EOC_VALUE_NONE;
Config.IE_FIFO_FULL = SARADC_IE_FIFO_FULL_VALUE_DISABLE;
Config.IE_FIFO_HFULL = SARADC_IE_FIFO_HFULL_VALUE_DISABLE;
ADC_Configure(&Config);
ADC_Enable();
ADC_SoftReset();
}
void BOARD_ADC_GetBatteryInfo(uint16_t *pVoltage, uint16_t *pCurrent)
{
ADC_Start();
while (!ADC_CheckEndOfConversion(ADC_CH9)) {}
*pVoltage = ADC_GetValue(ADC_CH4);
*pCurrent = ADC_GetValue(ADC_CH9);
}
void BOARD_Init(void)
{
BOARD_PORTCON_Init();
BOARD_GPIO_Init();
BACKLIGHT_InitHardware();
BOARD_ADC_Init();
ST7565_Init();
#ifdef ENABLE_FMRADIO
BK1080_Init0();
#endif
#if defined(ENABLE_UART) || defined(ENABLED_AIRCOPY)
CRC_Init();
#endif
}

31
board.h Normal file
View File

@@ -0,0 +1,31 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef BOARD_H
#define BOARD_H
#include <stdint.h>
#include <stdbool.h>
void BOARD_FLASH_Init(void);
void BOARD_GPIO_Init(void);
void BOARD_PORTCON_Init(void);
void BOARD_ADC_Init(void);
void BOARD_ADC_GetBatteryInfo(uint16_t *pVoltage, uint16_t *pCurrent);
void BOARD_Init(void);
#endif

87
bsp/dp32g030/aes.h Normal file
View File

@@ -0,0 +1,87 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef HARDWARE_DP32G030_AES_H
#define HARDWARE_DP32G030_AES_H
#if !defined(__ASSEMBLY__)
#include <stdint.h>
#endif
/* -------- AES -------- */
#define AES_BASE_ADDR 0x400BD000U
#define AES_BASE_SIZE 0x00000800U
#define AES_CR_ADDR (AES_BASE_ADDR + 0x0000U)
#define AES_CR (*(volatile uint32_t *)AES_CR_ADDR)
#define AES_CR_EN_SHIFT 0
#define AES_CR_EN_WIDTH 1
#define AES_CR_EN_MASK (((1U << AES_CR_EN_WIDTH) - 1U) << AES_CR_EN_SHIFT)
#define AES_CR_EN_VALUE_DISABLE 0U
#define AES_CR_EN_BITS_DISABLE (AES_CR_EN_VALUE_DISABLE << AES_CR_EN_SHIFT)
#define AES_CR_EN_VALUE_ENABLE 1U
#define AES_CR_EN_BITS_ENABLE (AES_CR_EN_VALUE_ENABLE << AES_CR_EN_SHIFT)
#define AES_CR_CHMOD_SHIFT 5
#define AES_CR_CHMOD_WIDTH 2
#define AES_CR_CHMOD_MASK (((1U << AES_CR_CHMOD_WIDTH) - 1U) << AES_CR_CHMOD_SHIFT)
#define AES_CR_CHMOD_VALUE_ECB 0U
#define AES_CR_CHMOD_BITS_ECB (AES_CR_CHMOD_VALUE_ECB << AES_CR_CHMOD_SHIFT)
#define AES_CR_CHMOD_VALUE_CBC 1U
#define AES_CR_CHMOD_BITS_CBC (AES_CR_CHMOD_VALUE_CBC << AES_CR_CHMOD_SHIFT)
#define AES_CR_CHMOD_VALUE_CTR 2U
#define AES_CR_CHMOD_BITS_CTR (AES_CR_CHMOD_VALUE_CTR << AES_CR_CHMOD_SHIFT)
#define AES_CR_CCFC_SHIFT 7
#define AES_CR_CCFC_WIDTH 1
#define AES_CR_CCFC_MASK (((1U << AES_CR_CCFC_WIDTH) - 1U) << AES_CR_CCFC_SHIFT)
#define AES_CR_CCFC_VALUE_SET 1U
#define AES_CR_CCFC_BITS_SET (AES_CR_CCFC_VALUE_SET << AES_CR_CCFC_SHIFT)
#define AES_SR_ADDR (AES_BASE_ADDR + 0x0004U)
#define AES_SR (*(volatile uint32_t *)AES_SR_ADDR)
#define AES_SR_CCF_SHIFT 0
#define AES_SR_CCF_WIDTH 1
#define AES_SR_CCF_MASK (((1U << AES_SR_CCF_WIDTH) - 1U) << AES_SR_CCF_SHIFT)
#define AES_SR_CCF_VALUE_NOT_COMPLETE 0U
#define AES_SR_CCF_BITS_NOT_COMPLETE (AES_SR_CCF_VALUE_NOT_COMPLETE << AES_SR_CCF_SHIFT)
#define AES_SR_CCF_VALUE_COMPLETE 1U
#define AES_SR_CCF_BITS_COMPLETE (AES_SR_CCF_VALUE_COMPLETE << AES_SR_CCF_SHIFT)
#define AES_DINR_ADDR (AES_BASE_ADDR + 0x0008U)
#define AES_DINR (*(volatile uint32_t *)AES_DINR_ADDR)
#define AES_DOUTR_ADDR (AES_BASE_ADDR + 0x000CU)
#define AES_DOUTR (*(volatile uint32_t *)AES_DOUTR_ADDR)
#define AES_KEYR0_ADDR (AES_BASE_ADDR + 0x0010U)
#define AES_KEYR0 (*(volatile uint32_t *)AES_KEYR0_ADDR)
#define AES_KEYR1_ADDR (AES_BASE_ADDR + 0x0014U)
#define AES_KEYR1 (*(volatile uint32_t *)AES_KEYR1_ADDR)
#define AES_KEYR2_ADDR (AES_BASE_ADDR + 0x0018U)
#define AES_KEYR2 (*(volatile uint32_t *)AES_KEYR2_ADDR)
#define AES_KEYR3_ADDR (AES_BASE_ADDR + 0x001CU)
#define AES_KEYR3 (*(volatile uint32_t *)AES_KEYR3_ADDR)
#define AES_IVR0_ADDR (AES_BASE_ADDR + 0x0020U)
#define AES_IVR0 (*(volatile uint32_t *)AES_IVR0_ADDR)
#define AES_IVR1_ADDR (AES_BASE_ADDR + 0x0024U)
#define AES_IVR1 (*(volatile uint32_t *)AES_IVR1_ADDR)
#define AES_IVR2_ADDR (AES_BASE_ADDR + 0x0028U)
#define AES_IVR2 (*(volatile uint32_t *)AES_IVR2_ADDR)
#define AES_IVR3_ADDR (AES_BASE_ADDR + 0x002CU)
#define AES_IVR3 (*(volatile uint32_t *)AES_IVR3_ADDR)
#endif

109
bsp/dp32g030/crc.h Normal file
View File

@@ -0,0 +1,109 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef HARDWARE_DP32G030_CRC_H
#define HARDWARE_DP32G030_CRC_H
#if !defined(__ASSEMBLY__)
#include <stdint.h>
#endif
/* -------- CRC -------- */
#define CRC_BASE_ADDR 0x40003000U
#define CRC_BASE_SIZE 0x00000800U
#define CRC_CR_ADDR (CRC_BASE_ADDR + 0x0000U)
#define CRC_CR (*(volatile uint32_t *)CRC_CR_ADDR)
#define CRC_CR_CRC_EN_SHIFT 0
#define CRC_CR_CRC_EN_WIDTH 1
#define CRC_CR_CRC_EN_MASK (((1U << CRC_CR_CRC_EN_WIDTH) - 1U) << CRC_CR_CRC_EN_SHIFT)
#define CRC_CR_CRC_EN_VALUE_DISABLE 0U
#define CRC_CR_CRC_EN_BITS_DISABLE (CRC_CR_CRC_EN_VALUE_DISABLE << CRC_CR_CRC_EN_SHIFT)
#define CRC_CR_CRC_EN_VALUE_ENABLE 1U
#define CRC_CR_CRC_EN_BITS_ENABLE (CRC_CR_CRC_EN_VALUE_ENABLE << CRC_CR_CRC_EN_SHIFT)
#define CRC_CR_INPUT_REV_SHIFT 1
#define CRC_CR_INPUT_REV_WIDTH 1
#define CRC_CR_INPUT_REV_MASK (((1U << CRC_CR_INPUT_REV_WIDTH) - 1U) << CRC_CR_INPUT_REV_SHIFT)
#define CRC_CR_INPUT_REV_VALUE_NORMAL 0U
#define CRC_CR_INPUT_REV_BITS_NORMAL (CRC_CR_INPUT_REV_VALUE_NORMAL << CRC_CR_INPUT_REV_SHIFT)
#define CRC_CR_INPUT_REV_VALUE_REVERSED 1U
#define CRC_CR_INPUT_REV_BITS_REVERSED (CRC_CR_INPUT_REV_VALUE_REVERSED << CRC_CR_INPUT_REV_SHIFT)
#define CRC_CR_INPUT_INV_SHIFT 2
#define CRC_CR_INPUT_INV_WIDTH 2
#define CRC_CR_INPUT_INV_MASK (((1U << CRC_CR_INPUT_INV_WIDTH) - 1U) << CRC_CR_INPUT_INV_SHIFT)
#define CRC_CR_INPUT_INV_VALUE_NORMAL 0U
#define CRC_CR_INPUT_INV_BITS_NORMAL (CRC_CR_INPUT_INV_VALUE_NORMAL << CRC_CR_INPUT_INV_SHIFT)
#define CRC_CR_INPUT_INV_VALUE_BIT_INVERTED 1U
#define CRC_CR_INPUT_INV_BITS_BIT_INVERTED (CRC_CR_INPUT_INV_VALUE_BIT_INVERTED << CRC_CR_INPUT_INV_SHIFT)
#define CRC_CR_INPUT_INV_VALUE_BYTE_INVERTED 2U
#define CRC_CR_INPUT_INV_BITS_BYTE_INVERTED (CRC_CR_INPUT_INV_VALUE_BYTE_INVERTED << CRC_CR_INPUT_INV_SHIFT)
#define CRC_CR_INPUT_INV_VALUE_BIT_BYTE_INVERTED 3U
#define CRC_CR_INPUT_INV_BITS_BIT_BYTE_INVERTED (CRC_CR_INPUT_INV_VALUE_BIT_BYTE_INVERTED << CRC_CR_INPUT_INV_SHIFT)
#define CRC_CR_OUTPUT_REV_SHIFT 4
#define CRC_CR_OUTPUT_REV_WIDTH 1
#define CRC_CR_OUTPUT_REV_MASK (((1U << CRC_CR_OUTPUT_REV_WIDTH) - 1U) << CRC_CR_OUTPUT_REV_SHIFT)
#define CRC_CR_OUTPUT_REV_VALUE_NORMAL 0U
#define CRC_CR_OUTPUT_REV_BITS_NORMAL (CRC_CR_OUTPUT_REV_VALUE_NORMAL << CRC_CR_OUTPUT_REV_SHIFT)
#define CRC_CR_OUTPUT_REV_VALUE_REVERSED 1U
#define CRC_CR_OUTPUT_REV_BITS_REVERSED (CRC_CR_OUTPUT_REV_VALUE_REVERSED << CRC_CR_OUTPUT_REV_SHIFT)
#define CRC_CR_OUTPUT_INV_SHIFT 5
#define CRC_CR_OUTPUT_INV_WIDTH 2
#define CRC_CR_OUTPUT_INV_MASK (((1U << CRC_CR_OUTPUT_INV_WIDTH) - 1U) << CRC_CR_OUTPUT_INV_SHIFT)
#define CRC_CR_OUTPUT_INV_VALUE_NORMAL 0U
#define CRC_CR_OUTPUT_INV_BITS_NORMAL (CRC_CR_OUTPUT_INV_VALUE_NORMAL << CRC_CR_OUTPUT_INV_SHIFT)
#define CRC_CR_OUTPUT_INV_VALUE_BIT_INVERTED 1U
#define CRC_CR_OUTPUT_INV_BITS_BIT_INVERTED (CRC_CR_OUTPUT_INV_VALUE_BIT_INVERTED << CRC_CR_OUTPUT_INV_SHIFT)
#define CRC_CR_OUTPUT_INV_VALUE_BYTE_INVERTED 2U
#define CRC_CR_OUTPUT_INV_BITS_BYTE_INVERTED (CRC_CR_OUTPUT_INV_VALUE_BYTE_INVERTED << CRC_CR_OUTPUT_INV_SHIFT)
#define CRC_CR_OUTPUT_INV_VALUE_BIT_BYTE_INVERTED 3U
#define CRC_CR_OUTPUT_INV_BITS_BIT_BYTE_INVERTED (CRC_CR_OUTPUT_INV_VALUE_BIT_BYTE_INVERTED << CRC_CR_OUTPUT_INV_SHIFT)
#define CRC_CR_DATA_WIDTH_SHIFT 7
#define CRC_CR_DATA_WIDTH_WIDTH 2
#define CRC_CR_DATA_WIDTH_MASK (((1U << CRC_CR_DATA_WIDTH_WIDTH) - 1U) << CRC_CR_DATA_WIDTH_SHIFT)
#define CRC_CR_DATA_WIDTH_VALUE_32 0U
#define CRC_CR_DATA_WIDTH_BITS_32 (CRC_CR_DATA_WIDTH_VALUE_32 << CRC_CR_DATA_WIDTH_SHIFT)
#define CRC_CR_DATA_WIDTH_VALUE_16 1U
#define CRC_CR_DATA_WIDTH_BITS_16 (CRC_CR_DATA_WIDTH_VALUE_16 << CRC_CR_DATA_WIDTH_SHIFT)
#define CRC_CR_DATA_WIDTH_VALUE_8 2U
#define CRC_CR_DATA_WIDTH_BITS_8 (CRC_CR_DATA_WIDTH_VALUE_8 << CRC_CR_DATA_WIDTH_SHIFT)
#define CRC_CR_CRC_SEL_SHIFT 9
#define CRC_CR_CRC_SEL_WIDTH 2
#define CRC_CR_CRC_SEL_MASK (((1U << CRC_CR_CRC_SEL_WIDTH) - 1U) << CRC_CR_CRC_SEL_SHIFT)
#define CRC_CR_CRC_SEL_VALUE_CRC_16_CCITT 0U
#define CRC_CR_CRC_SEL_BITS_CRC_16_CCITT (CRC_CR_CRC_SEL_VALUE_CRC_16_CCITT << CRC_CR_CRC_SEL_SHIFT)
#define CRC_CR_CRC_SEL_VALUE_CRC_8_ATM 1U
#define CRC_CR_CRC_SEL_BITS_CRC_8_ATM (CRC_CR_CRC_SEL_VALUE_CRC_8_ATM << CRC_CR_CRC_SEL_SHIFT)
#define CRC_CR_CRC_SEL_VALUE_CRC_16 2U
#define CRC_CR_CRC_SEL_BITS_CRC_16 (CRC_CR_CRC_SEL_VALUE_CRC_16 << CRC_CR_CRC_SEL_SHIFT)
#define CRC_CR_CRC_SEL_VALUE_CRC_32_IEEE802_3 3U
#define CRC_CR_CRC_SEL_BITS_CRC_32_IEEE802_3 (CRC_CR_CRC_SEL_VALUE_CRC_32_IEEE802_3 << CRC_CR_CRC_SEL_SHIFT)
#define CRC_IV_ADDR (CRC_BASE_ADDR + 0x0004U)
#define CRC_IV (*(volatile uint32_t *)CRC_IV_ADDR)
#define CRC_DATAIN_ADDR (CRC_BASE_ADDR + 0x0008U)
#define CRC_DATAIN (*(volatile uint32_t *)CRC_DATAIN_ADDR)
#define CRC_DATAOUT_ADDR (CRC_BASE_ADDR + 0x000CU)
#define CRC_DATAOUT (*(volatile uint32_t *)CRC_DATAOUT_ADDR)
#endif

319
bsp/dp32g030/dma.h Normal file
View File

@@ -0,0 +1,319 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef HARDWARE_DP32G030_DMA_H
#define HARDWARE_DP32G030_DMA_H
#if !defined(__ASSEMBLY__)
#include <stdint.h>
#endif
/* -------- DMA -------- */
#define DMA_BASE_ADDR 0x40001000U
#define DMA_BASE_SIZE 0x00000100U
#define DMA_CTR_ADDR (DMA_BASE_ADDR + 0x0000U)
#define DMA_CTR (*(volatile uint32_t *)DMA_CTR_ADDR)
#define DMA_CTR_DMAEN_SHIFT 0
#define DMA_CTR_DMAEN_WIDTH 1
#define DMA_CTR_DMAEN_MASK (((1U << DMA_CTR_DMAEN_WIDTH) - 1U) << DMA_CTR_DMAEN_SHIFT)
#define DMA_CTR_DMAEN_VALUE_DISABLE 0U
#define DMA_CTR_DMAEN_BITS_DISABLE (DMA_CTR_DMAEN_VALUE_DISABLE << DMA_CTR_DMAEN_SHIFT)
#define DMA_CTR_DMAEN_VALUE_ENABLE 1U
#define DMA_CTR_DMAEN_BITS_ENABLE (DMA_CTR_DMAEN_VALUE_ENABLE << DMA_CTR_DMAEN_SHIFT)
#define DMA_INTEN_ADDR (DMA_BASE_ADDR + 0x0004U)
#define DMA_INTEN (*(volatile uint32_t *)DMA_INTEN_ADDR)
#define DMA_INTEN_CH0_TC_INTEN_SHIFT 0
#define DMA_INTEN_CH0_TC_INTEN_WIDTH 1
#define DMA_INTEN_CH0_TC_INTEN_MASK (((1U << DMA_INTEN_CH0_TC_INTEN_WIDTH) - 1U) << DMA_INTEN_CH0_TC_INTEN_SHIFT)
#define DMA_INTEN_CH0_TC_INTEN_VALUE_DISABLE 0U
#define DMA_INTEN_CH0_TC_INTEN_BITS_DISABLE (DMA_INTEN_CH0_TC_INTEN_VALUE_DISABLE << DMA_INTEN_CH0_TC_INTEN_SHIFT)
#define DMA_INTEN_CH0_TC_INTEN_VALUE_ENABLE 1U
#define DMA_INTEN_CH0_TC_INTEN_BITS_ENABLE (DMA_INTEN_CH0_TC_INTEN_VALUE_ENABLE << DMA_INTEN_CH0_TC_INTEN_SHIFT)
#define DMA_INTEN_CH1_TC_INTEN_SHIFT 1
#define DMA_INTEN_CH1_TC_INTEN_WIDTH 1
#define DMA_INTEN_CH1_TC_INTEN_MASK (((1U << DMA_INTEN_CH1_TC_INTEN_WIDTH) - 1U) << DMA_INTEN_CH1_TC_INTEN_SHIFT)
#define DMA_INTEN_CH1_TC_INTEN_VALUE_DISABLE 0U
#define DMA_INTEN_CH1_TC_INTEN_BITS_DISABLE (DMA_INTEN_CH1_TC_INTEN_VALUE_DISABLE << DMA_INTEN_CH1_TC_INTEN_SHIFT)
#define DMA_INTEN_CH1_TC_INTEN_VALUE_ENABLE 1U
#define DMA_INTEN_CH1_TC_INTEN_BITS_ENABLE (DMA_INTEN_CH1_TC_INTEN_VALUE_ENABLE << DMA_INTEN_CH1_TC_INTEN_SHIFT)
#define DMA_INTEN_CH2_TC_INTEN_SHIFT 2
#define DMA_INTEN_CH2_TC_INTEN_WIDTH 1
#define DMA_INTEN_CH2_TC_INTEN_MASK (((1U << DMA_INTEN_CH2_TC_INTEN_WIDTH) - 1U) << DMA_INTEN_CH2_TC_INTEN_SHIFT)
#define DMA_INTEN_CH2_TC_INTEN_VALUE_DISABLE 0U
#define DMA_INTEN_CH2_TC_INTEN_BITS_DISABLE (DMA_INTEN_CH2_TC_INTEN_VALUE_DISABLE << DMA_INTEN_CH2_TC_INTEN_SHIFT)
#define DMA_INTEN_CH2_TC_INTEN_VALUE_ENABLE 1U
#define DMA_INTEN_CH2_TC_INTEN_BITS_ENABLE (DMA_INTEN_CH2_TC_INTEN_VALUE_ENABLE << DMA_INTEN_CH2_TC_INTEN_SHIFT)
#define DMA_INTEN_CH3_TC_INTEN_SHIFT 3
#define DMA_INTEN_CH3_TC_INTEN_WIDTH 1
#define DMA_INTEN_CH3_TC_INTEN_MASK (((1U << DMA_INTEN_CH3_TC_INTEN_WIDTH) - 1U) << DMA_INTEN_CH3_TC_INTEN_SHIFT)
#define DMA_INTEN_CH3_TC_INTEN_VALUE_DISABLE 0U
#define DMA_INTEN_CH3_TC_INTEN_BITS_DISABLE (DMA_INTEN_CH3_TC_INTEN_VALUE_DISABLE << DMA_INTEN_CH3_TC_INTEN_SHIFT)
#define DMA_INTEN_CH3_TC_INTEN_VALUE_ENABLE 1U
#define DMA_INTEN_CH3_TC_INTEN_BITS_ENABLE (DMA_INTEN_CH3_TC_INTEN_VALUE_ENABLE << DMA_INTEN_CH3_TC_INTEN_SHIFT)
#define DMA_INTEN_CH0_THC_INTEN_SHIFT 8
#define DMA_INTEN_CH0_THC_INTEN_WIDTH 1
#define DMA_INTEN_CH0_THC_INTEN_MASK (((1U << DMA_INTEN_CH0_THC_INTEN_WIDTH) - 1U) << DMA_INTEN_CH0_THC_INTEN_SHIFT)
#define DMA_INTEN_CH0_THC_INTEN_VALUE_DISABLE 0U
#define DMA_INTEN_CH0_THC_INTEN_BITS_DISABLE (DMA_INTEN_CH0_THC_INTEN_VALUE_DISABLE << DMA_INTEN_CH0_THC_INTEN_SHIFT)
#define DMA_INTEN_CH0_THC_INTEN_VALUE_ENABLE 1U
#define DMA_INTEN_CH0_THC_INTEN_BITS_ENABLE (DMA_INTEN_CH0_THC_INTEN_VALUE_ENABLE << DMA_INTEN_CH0_THC_INTEN_SHIFT)
#define DMA_INTEN_CH1_THC_INTEN_SHIFT 9
#define DMA_INTEN_CH1_THC_INTEN_WIDTH 1
#define DMA_INTEN_CH1_THC_INTEN_MASK (((1U << DMA_INTEN_CH1_THC_INTEN_WIDTH) - 1U) << DMA_INTEN_CH1_THC_INTEN_SHIFT)
#define DMA_INTEN_CH1_THC_INTEN_VALUE_DISABLE 0U
#define DMA_INTEN_CH1_THC_INTEN_BITS_DISABLE (DMA_INTEN_CH1_THC_INTEN_VALUE_DISABLE << DMA_INTEN_CH1_THC_INTEN_SHIFT)
#define DMA_INTEN_CH1_THC_INTEN_VALUE_ENABLE 1U
#define DMA_INTEN_CH1_THC_INTEN_BITS_ENABLE (DMA_INTEN_CH1_THC_INTEN_VALUE_ENABLE << DMA_INTEN_CH1_THC_INTEN_SHIFT)
#define DMA_INTEN_CH2_THC_INTEN_SHIFT 10
#define DMA_INTEN_CH2_THC_INTEN_WIDTH 1
#define DMA_INTEN_CH2_THC_INTEN_MASK (((1U << DMA_INTEN_CH2_THC_INTEN_WIDTH) - 1U) << DMA_INTEN_CH2_THC_INTEN_SHIFT)
#define DMA_INTEN_CH2_THC_INTEN_VALUE_DISABLE 0U
#define DMA_INTEN_CH2_THC_INTEN_BITS_DISABLE (DMA_INTEN_CH2_THC_INTEN_VALUE_DISABLE << DMA_INTEN_CH2_THC_INTEN_SHIFT)
#define DMA_INTEN_CH2_THC_INTEN_VALUE_ENABLE 1U
#define DMA_INTEN_CH2_THC_INTEN_BITS_ENABLE (DMA_INTEN_CH2_THC_INTEN_VALUE_ENABLE << DMA_INTEN_CH2_THC_INTEN_SHIFT)
#define DMA_INTEN_CH3_THC_INTEN_SHIFT 11
#define DMA_INTEN_CH3_THC_INTEN_WIDTH 1
#define DMA_INTEN_CH3_THC_INTEN_MASK (((1U << DMA_INTEN_CH3_THC_INTEN_WIDTH) - 1U) << DMA_INTEN_CH3_THC_INTEN_SHIFT)
#define DMA_INTEN_CH3_THC_INTEN_VALUE_DISABLE 0U
#define DMA_INTEN_CH3_THC_INTEN_BITS_DISABLE (DMA_INTEN_CH3_THC_INTEN_VALUE_DISABLE << DMA_INTEN_CH3_THC_INTEN_SHIFT)
#define DMA_INTEN_CH3_THC_INTEN_VALUE_ENABLE 1U
#define DMA_INTEN_CH3_THC_INTEN_BITS_ENABLE (DMA_INTEN_CH3_THC_INTEN_VALUE_ENABLE << DMA_INTEN_CH3_THC_INTEN_SHIFT)
#define DMA_INTST_ADDR (DMA_BASE_ADDR + 0x0008U)
#define DMA_INTST (*(volatile uint32_t *)DMA_INTST_ADDR)
#define DMA_INTST_CH0_TC_INTST_SHIFT 0
#define DMA_INTST_CH0_TC_INTST_WIDTH 1
#define DMA_INTST_CH0_TC_INTST_MASK (((1U << DMA_INTST_CH0_TC_INTST_WIDTH) - 1U) << DMA_INTST_CH0_TC_INTST_SHIFT)
#define DMA_INTST_CH0_TC_INTST_VALUE_NOT_SET 0U
#define DMA_INTST_CH0_TC_INTST_BITS_NOT_SET (DMA_INTST_CH0_TC_INTST_VALUE_NOT_SET << DMA_INTST_CH0_TC_INTST_SHIFT)
#define DMA_INTST_CH0_TC_INTST_VALUE_SET 1U
#define DMA_INTST_CH0_TC_INTST_BITS_SET (DMA_INTST_CH0_TC_INTST_VALUE_SET << DMA_INTST_CH0_TC_INTST_SHIFT)
#define DMA_INTST_CH1_TC_INTST_SHIFT 1
#define DMA_INTST_CH1_TC_INTST_WIDTH 1
#define DMA_INTST_CH1_TC_INTST_MASK (((1U << DMA_INTST_CH1_TC_INTST_WIDTH) - 1U) << DMA_INTST_CH1_TC_INTST_SHIFT)
#define DMA_INTST_CH1_TC_INTST_VALUE_NOT_SET 0U
#define DMA_INTST_CH1_TC_INTST_BITS_NOT_SET (DMA_INTST_CH1_TC_INTST_VALUE_NOT_SET << DMA_INTST_CH1_TC_INTST_SHIFT)
#define DMA_INTST_CH1_TC_INTST_VALUE_SET 1U
#define DMA_INTST_CH1_TC_INTST_BITS_SET (DMA_INTST_CH1_TC_INTST_VALUE_SET << DMA_INTST_CH1_TC_INTST_SHIFT)
#define DMA_INTST_CH2_TC_INTST_SHIFT 2
#define DMA_INTST_CH2_TC_INTST_WIDTH 1
#define DMA_INTST_CH2_TC_INTST_MASK (((1U << DMA_INTST_CH2_TC_INTST_WIDTH) - 1U) << DMA_INTST_CH2_TC_INTST_SHIFT)
#define DMA_INTST_CH2_TC_INTST_VALUE_NOT_SET 0U
#define DMA_INTST_CH2_TC_INTST_BITS_NOT_SET (DMA_INTST_CH2_TC_INTST_VALUE_NOT_SET << DMA_INTST_CH2_TC_INTST_SHIFT)
#define DMA_INTST_CH2_TC_INTST_VALUE_SET 1U
#define DMA_INTST_CH2_TC_INTST_BITS_SET (DMA_INTST_CH2_TC_INTST_VALUE_SET << DMA_INTST_CH2_TC_INTST_SHIFT)
#define DMA_INTST_CH3_TC_INTST_SHIFT 3
#define DMA_INTST_CH3_TC_INTST_WIDTH 1
#define DMA_INTST_CH3_TC_INTST_MASK (((1U << DMA_INTST_CH3_TC_INTST_WIDTH) - 1U) << DMA_INTST_CH3_TC_INTST_SHIFT)
#define DMA_INTST_CH3_TC_INTST_VALUE_NOT_SET 0U
#define DMA_INTST_CH3_TC_INTST_BITS_NOT_SET (DMA_INTST_CH3_TC_INTST_VALUE_NOT_SET << DMA_INTST_CH3_TC_INTST_SHIFT)
#define DMA_INTST_CH3_TC_INTST_VALUE_SET 1U
#define DMA_INTST_CH3_TC_INTST_BITS_SET (DMA_INTST_CH3_TC_INTST_VALUE_SET << DMA_INTST_CH3_TC_INTST_SHIFT)
#define DMA_INTST_CH0_THC_INTST_SHIFT 8
#define DMA_INTST_CH0_THC_INTST_WIDTH 1
#define DMA_INTST_CH0_THC_INTST_MASK (((1U << DMA_INTST_CH0_THC_INTST_WIDTH) - 1U) << DMA_INTST_CH0_THC_INTST_SHIFT)
#define DMA_INTST_CH0_THC_INTST_VALUE_NOT_SET 0U
#define DMA_INTST_CH0_THC_INTST_BITS_NOT_SET (DMA_INTST_CH0_THC_INTST_VALUE_NOT_SET << DMA_INTST_CH0_THC_INTST_SHIFT)
#define DMA_INTST_CH0_THC_INTST_VALUE_SET 1U
#define DMA_INTST_CH0_THC_INTST_BITS_SET (DMA_INTST_CH0_THC_INTST_VALUE_SET << DMA_INTST_CH0_THC_INTST_SHIFT)
#define DMA_INTST_CH1_THC_INTST_SHIFT 9
#define DMA_INTST_CH1_THC_INTST_WIDTH 1
#define DMA_INTST_CH1_THC_INTST_MASK (((1U << DMA_INTST_CH1_THC_INTST_WIDTH) - 1U) << DMA_INTST_CH1_THC_INTST_SHIFT)
#define DMA_INTST_CH1_THC_INTST_VALUE_NOT_SET 0U
#define DMA_INTST_CH1_THC_INTST_BITS_NOT_SET (DMA_INTST_CH1_THC_INTST_VALUE_NOT_SET << DMA_INTST_CH1_THC_INTST_SHIFT)
#define DMA_INTST_CH1_THC_INTST_VALUE_SET 1U
#define DMA_INTST_CH1_THC_INTST_BITS_SET (DMA_INTST_CH1_THC_INTST_VALUE_SET << DMA_INTST_CH1_THC_INTST_SHIFT)
#define DMA_INTST_CH2_THC_INTST_SHIFT 10
#define DMA_INTST_CH2_THC_INTST_WIDTH 1
#define DMA_INTST_CH2_THC_INTST_MASK (((1U << DMA_INTST_CH2_THC_INTST_WIDTH) - 1U) << DMA_INTST_CH2_THC_INTST_SHIFT)
#define DMA_INTST_CH2_THC_INTST_VALUE_NOT_SET 0U
#define DMA_INTST_CH2_THC_INTST_BITS_NOT_SET (DMA_INTST_CH2_THC_INTST_VALUE_NOT_SET << DMA_INTST_CH2_THC_INTST_SHIFT)
#define DMA_INTST_CH2_THC_INTST_VALUE_SET 1U
#define DMA_INTST_CH2_THC_INTST_BITS_SET (DMA_INTST_CH2_THC_INTST_VALUE_SET << DMA_INTST_CH2_THC_INTST_SHIFT)
#define DMA_INTST_CH3_THC_INTST_SHIFT 11
#define DMA_INTST_CH3_THC_INTST_WIDTH 1
#define DMA_INTST_CH3_THC_INTST_MASK (((1U << DMA_INTST_CH3_THC_INTST_WIDTH) - 1U) << DMA_INTST_CH3_THC_INTST_SHIFT)
#define DMA_INTST_CH3_THC_INTST_VALUE_NOT_SET 0U
#define DMA_INTST_CH3_THC_INTST_BITS_NOT_SET (DMA_INTST_CH3_THC_INTST_VALUE_NOT_SET << DMA_INTST_CH3_THC_INTST_SHIFT)
#define DMA_INTST_CH3_THC_INTST_VALUE_SET 1U
#define DMA_INTST_CH3_THC_INTST_BITS_SET (DMA_INTST_CH3_THC_INTST_VALUE_SET << DMA_INTST_CH3_THC_INTST_SHIFT)
/* -------- DMA_CH0 -------- */
#define DMA_CH0_BASE_ADDR 0x40001100U
#define DMA_CH0_BASE_SIZE 0x00000020U
#define DMA_CH0 ((volatile DMA_Channel_t *)DMA_CH0_BASE_ADDR)
/* -------- DMA_CH1 -------- */
#define DMA_CH1_BASE_ADDR 0x40001120U
#define DMA_CH1_BASE_SIZE 0x00000020U
#define DMA_CH1 ((volatile DMA_Channel_t *)DMA_CH1_BASE_ADDR)
/* -------- DMA_CH2 -------- */
#define DMA_CH2_BASE_ADDR 0x40001140U
#define DMA_CH2_BASE_SIZE 0x00000020U
#define DMA_CH2 ((volatile DMA_Channel_t *)DMA_CH2_BASE_ADDR)
/* -------- DMA_CH3 -------- */
#define DMA_CH3_BASE_ADDR 0x40001160U
#define DMA_CH3_BASE_SIZE 0x00000020U
#define DMA_CH3 ((volatile DMA_Channel_t *)DMA_CH3_BASE_ADDR)
/* -------- DMA_CH -------- */
typedef struct {
uint32_t CTR;
uint32_t MOD;
uint32_t MSADDR;
uint32_t MDADDR;
uint32_t ST;
} DMA_Channel_t;
#define DMA_CH_CTR_CH_EN_SHIFT 0
#define DMA_CH_CTR_CH_EN_WIDTH 1
#define DMA_CH_CTR_CH_EN_MASK (((1U << DMA_CH_CTR_CH_EN_WIDTH) - 1U) << DMA_CH_CTR_CH_EN_SHIFT)
#define DMA_CH_CTR_CH_EN_VALUE_DISABLE 0U
#define DMA_CH_CTR_CH_EN_BITS_DISABLE (DMA_CH_CTR_CH_EN_VALUE_DISABLE << DMA_CH_CTR_CH_EN_SHIFT)
#define DMA_CH_CTR_CH_EN_VALUE_ENABLE 1U
#define DMA_CH_CTR_CH_EN_BITS_ENABLE (DMA_CH_CTR_CH_EN_VALUE_ENABLE << DMA_CH_CTR_CH_EN_SHIFT)
#define DMA_CH_CTR_LENGTH_SHIFT 1
#define DMA_CH_CTR_LENGTH_WIDTH 12
#define DMA_CH_CTR_LENGTH_MASK (((1U << DMA_CH_CTR_LENGTH_WIDTH) - 1U) << DMA_CH_CTR_LENGTH_SHIFT)
#define DMA_CH_CTR_LOOP_SHIFT 13
#define DMA_CH_CTR_LOOP_WIDTH 1
#define DMA_CH_CTR_LOOP_MASK (((1U << DMA_CH_CTR_LOOP_WIDTH) - 1U) << DMA_CH_CTR_LOOP_SHIFT)
#define DMA_CH_CTR_LOOP_VALUE_DISABLE 0U
#define DMA_CH_CTR_LOOP_BITS_DISABLE (DMA_CH_CTR_LOOP_VALUE_DISABLE << DMA_CH_CTR_LOOP_SHIFT)
#define DMA_CH_CTR_LOOP_VALUE_ENABLE 1U
#define DMA_CH_CTR_LOOP_BITS_ENABLE (DMA_CH_CTR_LOOP_VALUE_ENABLE << DMA_CH_CTR_LOOP_SHIFT)
#define DMA_CH_CTR_PRI_SHIFT 14
#define DMA_CH_CTR_PRI_WIDTH 2
#define DMA_CH_CTR_PRI_MASK (((1U << DMA_CH_CTR_PRI_WIDTH) - 1U) << DMA_CH_CTR_PRI_SHIFT)
#define DMA_CH_CTR_PRI_VALUE_LOW 0U
#define DMA_CH_CTR_PRI_BITS_LOW (DMA_CH_CTR_PRI_VALUE_LOW << DMA_CH_CTR_PRI_SHIFT)
#define DMA_CH_CTR_PRI_VALUE_MEDIUM 1U
#define DMA_CH_CTR_PRI_BITS_MEDIUM (DMA_CH_CTR_PRI_VALUE_MEDIUM << DMA_CH_CTR_PRI_SHIFT)
#define DMA_CH_CTR_PRI_VALUE_HIGH 2U
#define DMA_CH_CTR_PRI_BITS_HIGH (DMA_CH_CTR_PRI_VALUE_HIGH << DMA_CH_CTR_PRI_SHIFT)
#define DMA_CH_CTR_PRI_VALUE_HIGHEST 3U
#define DMA_CH_CTR_PRI_BITS_HIGHEST (DMA_CH_CTR_PRI_VALUE_HIGHEST << DMA_CH_CTR_PRI_SHIFT)
#define DMA_CH_CTR_SWREQ_SHIFT 16
#define DMA_CH_CTR_SWREQ_WIDTH 1
#define DMA_CH_CTR_SWREQ_MASK (((1U << DMA_CH_CTR_SWREQ_WIDTH) - 1U) << DMA_CH_CTR_SWREQ_SHIFT)
#define DMA_CH_CTR_SWREQ_VALUE_SET 1U
#define DMA_CH_CTR_SWREQ_BITS_SET (DMA_CH_CTR_SWREQ_VALUE_SET << DMA_CH_CTR_SWREQ_SHIFT)
#define DMA_CH_MOD_MS_ADDMOD_SHIFT 0
#define DMA_CH_MOD_MS_ADDMOD_WIDTH 1
#define DMA_CH_MOD_MS_ADDMOD_MASK (((1U << DMA_CH_MOD_MS_ADDMOD_WIDTH) - 1U) << DMA_CH_MOD_MS_ADDMOD_SHIFT)
#define DMA_CH_MOD_MS_ADDMOD_VALUE_NONE 0U
#define DMA_CH_MOD_MS_ADDMOD_BITS_NONE (DMA_CH_MOD_MS_ADDMOD_VALUE_NONE << DMA_CH_MOD_MS_ADDMOD_SHIFT)
#define DMA_CH_MOD_MS_ADDMOD_VALUE_INCREMENT 1U
#define DMA_CH_MOD_MS_ADDMOD_BITS_INCREMENT (DMA_CH_MOD_MS_ADDMOD_VALUE_INCREMENT << DMA_CH_MOD_MS_ADDMOD_SHIFT)
#define DMA_CH_MOD_MS_SIZE_SHIFT 1
#define DMA_CH_MOD_MS_SIZE_WIDTH 2
#define DMA_CH_MOD_MS_SIZE_MASK (((1U << DMA_CH_MOD_MS_SIZE_WIDTH) - 1U) << DMA_CH_MOD_MS_SIZE_SHIFT)
#define DMA_CH_MOD_MS_SIZE_VALUE_8BIT 0U
#define DMA_CH_MOD_MS_SIZE_BITS_8BIT (DMA_CH_MOD_MS_SIZE_VALUE_8BIT << DMA_CH_MOD_MS_SIZE_SHIFT)
#define DMA_CH_MOD_MS_SIZE_VALUE_16BIT 1U
#define DMA_CH_MOD_MS_SIZE_BITS_16BIT (DMA_CH_MOD_MS_SIZE_VALUE_16BIT << DMA_CH_MOD_MS_SIZE_SHIFT)
#define DMA_CH_MOD_MS_SIZE_VALUE_32BIT 2U
#define DMA_CH_MOD_MS_SIZE_BITS_32BIT (DMA_CH_MOD_MS_SIZE_VALUE_32BIT << DMA_CH_MOD_MS_SIZE_SHIFT)
#define DMA_CH_MOD_MS_SIZE_VALUE_KEEP 3U
#define DMA_CH_MOD_MS_SIZE_BITS_KEEP (DMA_CH_MOD_MS_SIZE_VALUE_KEEP << DMA_CH_MOD_MS_SIZE_SHIFT)
#define DMA_CH_MOD_MS_SEL_SHIFT 3
#define DMA_CH_MOD_MS_SEL_WIDTH 3
#define DMA_CH_MOD_MS_SEL_MASK (((1U << DMA_CH_MOD_MS_SEL_WIDTH) - 1U) << DMA_CH_MOD_MS_SEL_SHIFT)
#define DMA_CH_MOD_MS_SEL_VALUE_SRAM 0U
#define DMA_CH_MOD_MS_SEL_BITS_SRAM (DMA_CH_MOD_MS_SEL_VALUE_SRAM << DMA_CH_MOD_MS_SEL_SHIFT)
#define DMA_CH_MOD_MS_SEL_VALUE_HSREQ_MS0 1U
#define DMA_CH_MOD_MS_SEL_BITS_HSREQ_MS0 (DMA_CH_MOD_MS_SEL_VALUE_HSREQ_MS0 << DMA_CH_MOD_MS_SEL_SHIFT)
#define DMA_CH_MOD_MS_SEL_VALUE_HSREQ_MS1 2U
#define DMA_CH_MOD_MS_SEL_BITS_HSREQ_MS1 (DMA_CH_MOD_MS_SEL_VALUE_HSREQ_MS1 << DMA_CH_MOD_MS_SEL_SHIFT)
#define DMA_CH_MOD_MS_SEL_VALUE_HSREQ_MS2 3U
#define DMA_CH_MOD_MS_SEL_BITS_HSREQ_MS2 (DMA_CH_MOD_MS_SEL_VALUE_HSREQ_MS2 << DMA_CH_MOD_MS_SEL_SHIFT)
#define DMA_CH_MOD_MS_SEL_VALUE_HSREQ_MS3 4U
#define DMA_CH_MOD_MS_SEL_BITS_HSREQ_MS3 (DMA_CH_MOD_MS_SEL_VALUE_HSREQ_MS3 << DMA_CH_MOD_MS_SEL_SHIFT)
#define DMA_CH_MOD_MS_SEL_VALUE_HSREQ_MS4 5U
#define DMA_CH_MOD_MS_SEL_BITS_HSREQ_MS4 (DMA_CH_MOD_MS_SEL_VALUE_HSREQ_MS4 << DMA_CH_MOD_MS_SEL_SHIFT)
#define DMA_CH_MOD_MS_SEL_VALUE_HSREQ_MS5 6U
#define DMA_CH_MOD_MS_SEL_BITS_HSREQ_MS5 (DMA_CH_MOD_MS_SEL_VALUE_HSREQ_MS5 << DMA_CH_MOD_MS_SEL_SHIFT)
#define DMA_CH_MOD_MS_SEL_VALUE_HSREQ_MS6 7U
#define DMA_CH_MOD_MS_SEL_BITS_HSREQ_MS6 (DMA_CH_MOD_MS_SEL_VALUE_HSREQ_MS6 << DMA_CH_MOD_MS_SEL_SHIFT)
#define DMA_CH_MOD_MD_ADDMOD_SHIFT 8
#define DMA_CH_MOD_MD_ADDMOD_WIDTH 1
#define DMA_CH_MOD_MD_ADDMOD_MASK (((1U << DMA_CH_MOD_MD_ADDMOD_WIDTH) - 1U) << DMA_CH_MOD_MD_ADDMOD_SHIFT)
#define DMA_CH_MOD_MD_ADDMOD_VALUE_NONE 0U
#define DMA_CH_MOD_MD_ADDMOD_BITS_NONE (DMA_CH_MOD_MD_ADDMOD_VALUE_NONE << DMA_CH_MOD_MD_ADDMOD_SHIFT)
#define DMA_CH_MOD_MD_ADDMOD_VALUE_INCREMENT 1U
#define DMA_CH_MOD_MD_ADDMOD_BITS_INCREMENT (DMA_CH_MOD_MD_ADDMOD_VALUE_INCREMENT << DMA_CH_MOD_MD_ADDMOD_SHIFT)
#define DMA_CH_MOD_MD_SIZE_SHIFT 9
#define DMA_CH_MOD_MD_SIZE_WIDTH 2
#define DMA_CH_MOD_MD_SIZE_MASK (((1U << DMA_CH_MOD_MD_SIZE_WIDTH) - 1U) << DMA_CH_MOD_MD_SIZE_SHIFT)
#define DMA_CH_MOD_MD_SIZE_VALUE_8BIT 0U
#define DMA_CH_MOD_MD_SIZE_BITS_8BIT (DMA_CH_MOD_MD_SIZE_VALUE_8BIT << DMA_CH_MOD_MD_SIZE_SHIFT)
#define DMA_CH_MOD_MD_SIZE_VALUE_16BIT 1U
#define DMA_CH_MOD_MD_SIZE_BITS_16BIT (DMA_CH_MOD_MD_SIZE_VALUE_16BIT << DMA_CH_MOD_MD_SIZE_SHIFT)
#define DMA_CH_MOD_MD_SIZE_VALUE_32BIT 2U
#define DMA_CH_MOD_MD_SIZE_BITS_32BIT (DMA_CH_MOD_MD_SIZE_VALUE_32BIT << DMA_CH_MOD_MD_SIZE_SHIFT)
#define DMA_CH_MOD_MD_SIZE_VALUE_KEEP 3U
#define DMA_CH_MOD_MD_SIZE_BITS_KEEP (DMA_CH_MOD_MD_SIZE_VALUE_KEEP << DMA_CH_MOD_MD_SIZE_SHIFT)
#define DMA_CH_MOD_MD_SEL_SHIFT 11
#define DMA_CH_MOD_MD_SEL_WIDTH 3
#define DMA_CH_MOD_MD_SEL_MASK (((1U << DMA_CH_MOD_MD_SEL_WIDTH) - 1U) << DMA_CH_MOD_MD_SEL_SHIFT)
#define DMA_CH_MOD_MD_SEL_VALUE_SRAM 0U
#define DMA_CH_MOD_MD_SEL_BITS_SRAM (DMA_CH_MOD_MD_SEL_VALUE_SRAM << DMA_CH_MOD_MD_SEL_SHIFT)
#define DMA_CH_MOD_MD_SEL_VALUE_HSREQ_MS0 1U
#define DMA_CH_MOD_MD_SEL_BITS_HSREQ_MS0 (DMA_CH_MOD_MD_SEL_VALUE_HSREQ_MS0 << DMA_CH_MOD_MD_SEL_SHIFT)
#define DMA_CH_MOD_MD_SEL_VALUE_HSREQ_MS1 2U
#define DMA_CH_MOD_MD_SEL_BITS_HSREQ_MS1 (DMA_CH_MOD_MD_SEL_VALUE_HSREQ_MS1 << DMA_CH_MOD_MD_SEL_SHIFT)
#define DMA_CH_MOD_MD_SEL_VALUE_HSREQ_MS2 3U
#define DMA_CH_MOD_MD_SEL_BITS_HSREQ_MS2 (DMA_CH_MOD_MD_SEL_VALUE_HSREQ_MS2 << DMA_CH_MOD_MD_SEL_SHIFT)
#define DMA_CH_MOD_MD_SEL_VALUE_HSREQ_MS3 4U
#define DMA_CH_MOD_MD_SEL_BITS_HSREQ_MS3 (DMA_CH_MOD_MD_SEL_VALUE_HSREQ_MS3 << DMA_CH_MOD_MD_SEL_SHIFT)
#define DMA_CH_MOD_MD_SEL_VALUE_HSREQ_MS4 5U
#define DMA_CH_MOD_MD_SEL_BITS_HSREQ_MS4 (DMA_CH_MOD_MD_SEL_VALUE_HSREQ_MS4 << DMA_CH_MOD_MD_SEL_SHIFT)
#define DMA_CH_MOD_MD_SEL_VALUE_HSREQ_MS5 6U
#define DMA_CH_MOD_MD_SEL_BITS_HSREQ_MS5 (DMA_CH_MOD_MD_SEL_VALUE_HSREQ_MS5 << DMA_CH_MOD_MD_SEL_SHIFT)
#define DMA_CH_MOD_MD_SEL_VALUE_HSREQ_MS6 7U
#define DMA_CH_MOD_MD_SEL_BITS_HSREQ_MS6 (DMA_CH_MOD_MD_SEL_VALUE_HSREQ_MS6 << DMA_CH_MOD_MD_SEL_SHIFT)
#endif

165
bsp/dp32g030/flash.h Normal file
View File

@@ -0,0 +1,165 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef HARDWARE_DP32G030_FLASH_H
#define HARDWARE_DP32G030_FLASH_H
#if !defined(__ASSEMBLY__)
#include <stdint.h>
#endif
/* -------- FLASH -------- */
#define FLASH_BASE_ADDR 0x4006F000U
#define FLASH_BASE_SIZE 0x00000800U
#define FLASH_CFG_ADDR (FLASH_BASE_ADDR + 0x0000U)
#define FLASH_CFG (*(volatile uint32_t *)FLASH_CFG_ADDR)
#define FLASH_CFG_READ_MD_SHIFT 0
#define FLASH_CFG_READ_MD_WIDTH 1
#define FLASH_CFG_READ_MD_MASK (((1U << FLASH_CFG_READ_MD_WIDTH) - 1U) << FLASH_CFG_READ_MD_SHIFT)
#define FLASH_CFG_READ_MD_VALUE_1_CYCLE 0U
#define FLASH_CFG_READ_MD_BITS_1_CYCLE (FLASH_CFG_READ_MD_VALUE_1_CYCLE << FLASH_CFG_READ_MD_SHIFT)
#define FLASH_CFG_READ_MD_VALUE_2_CYCLE 1U
#define FLASH_CFG_READ_MD_BITS_2_CYCLE (FLASH_CFG_READ_MD_VALUE_2_CYCLE << FLASH_CFG_READ_MD_SHIFT)
#define FLASH_CFG_NVR_SEL_SHIFT 1
#define FLASH_CFG_NVR_SEL_WIDTH 1
#define FLASH_CFG_NVR_SEL_MASK (((1U << FLASH_CFG_NVR_SEL_WIDTH) - 1U) << FLASH_CFG_NVR_SEL_SHIFT)
#define FLASH_CFG_NVR_SEL_VALUE_MAIN 0U
#define FLASH_CFG_NVR_SEL_BITS_MAIN (FLASH_CFG_NVR_SEL_VALUE_MAIN << FLASH_CFG_NVR_SEL_SHIFT)
#define FLASH_CFG_NVR_SEL_VALUE_NVR 1U
#define FLASH_CFG_NVR_SEL_BITS_NVR (FLASH_CFG_NVR_SEL_VALUE_NVR << FLASH_CFG_NVR_SEL_SHIFT)
#define FLASH_CFG_MODE_SHIFT 2
#define FLASH_CFG_MODE_WIDTH 3
#define FLASH_CFG_MODE_MASK (((1U << FLASH_CFG_MODE_WIDTH) - 1U) << FLASH_CFG_MODE_SHIFT)
#define FLASH_CFG_MODE_VALUE_READ_AHB 0U
#define FLASH_CFG_MODE_BITS_READ_AHB (FLASH_CFG_MODE_VALUE_READ_AHB << FLASH_CFG_MODE_SHIFT)
#define FLASH_CFG_MODE_VALUE_PROGRAM 1U
#define FLASH_CFG_MODE_BITS_PROGRAM (FLASH_CFG_MODE_VALUE_PROGRAM << FLASH_CFG_MODE_SHIFT)
#define FLASH_CFG_MODE_VALUE_ERASE 2U
#define FLASH_CFG_MODE_BITS_ERASE (FLASH_CFG_MODE_VALUE_ERASE << FLASH_CFG_MODE_SHIFT)
#define FLASH_CFG_MODE_VALUE_READ_APB 5U
#define FLASH_CFG_MODE_BITS_READ_APB (FLASH_CFG_MODE_VALUE_READ_APB << FLASH_CFG_MODE_SHIFT)
#define FLASH_CFG_DEEP_PD_SHIFT 31
#define FLASH_CFG_DEEP_PD_WIDTH 1
#define FLASH_CFG_DEEP_PD_MASK (((1U << FLASH_CFG_DEEP_PD_WIDTH) - 1U) << FLASH_CFG_DEEP_PD_SHIFT)
#define FLASH_CFG_DEEP_PD_VALUE_NORMAL 0U
#define FLASH_CFG_DEEP_PD_BITS_NORMAL (FLASH_CFG_DEEP_PD_VALUE_NORMAL << FLASH_CFG_DEEP_PD_SHIFT)
#define FLASH_CFG_DEEP_PD_VALUE_LOW_POWER 1U
#define FLASH_CFG_DEEP_PD_BITS_LOW_POWER (FLASH_CFG_DEEP_PD_VALUE_LOW_POWER << FLASH_CFG_DEEP_PD_SHIFT)
#define FLASH_ADDR_ADDR (FLASH_BASE_ADDR + 0x0004U)
#define FLASH_ADDR (*(volatile uint32_t *)FLASH_ADDR_ADDR)
#define FLASH_WDATA_ADDR (FLASH_BASE_ADDR + 0x0008U)
#define FLASH_WDATA (*(volatile uint32_t *)FLASH_WDATA_ADDR)
#define FLASH_RDATA_ADDR (FLASH_BASE_ADDR + 0x000CU)
#define FLASH_RDATA (*(volatile uint32_t *)FLASH_RDATA_ADDR)
#define FLASH_START_ADDR (FLASH_BASE_ADDR + 0x0010U)
#define FLASH_START (*(volatile uint32_t *)FLASH_START_ADDR)
#define FLASH_START_START_SHIFT 0
#define FLASH_START_START_WIDTH 1
#define FLASH_START_START_MASK (((1U << FLASH_START_START_WIDTH) - 1U) << FLASH_START_START_SHIFT)
#define FLASH_START_START_VALUE_START 1U
#define FLASH_START_START_BITS_START (FLASH_START_START_VALUE_START << FLASH_START_START_SHIFT)
#define FLASH_ST_ADDR (FLASH_BASE_ADDR + 0x0014U)
#define FLASH_ST (*(volatile uint32_t *)FLASH_ST_ADDR)
#define FLASH_ST_INIT_BUSY_SHIFT 0
#define FLASH_ST_INIT_BUSY_WIDTH 1
#define FLASH_ST_INIT_BUSY_MASK (((1U << FLASH_ST_INIT_BUSY_WIDTH) - 1U) << FLASH_ST_INIT_BUSY_SHIFT)
#define FLASH_ST_INIT_BUSY_VALUE_COMPLETE 0U
#define FLASH_ST_INIT_BUSY_BITS_COMPLETE (FLASH_ST_INIT_BUSY_VALUE_COMPLETE << FLASH_ST_INIT_BUSY_SHIFT)
#define FLASH_ST_INIT_BUSY_VALUE_BUSY 1U
#define FLASH_ST_INIT_BUSY_BITS_BUSY (FLASH_ST_INIT_BUSY_VALUE_BUSY << FLASH_ST_INIT_BUSY_SHIFT)
#define FLASH_ST_BUSY_SHIFT 1
#define FLASH_ST_BUSY_WIDTH 1
#define FLASH_ST_BUSY_MASK (((1U << FLASH_ST_BUSY_WIDTH) - 1U) << FLASH_ST_BUSY_SHIFT)
#define FLASH_ST_BUSY_VALUE_READY 0U
#define FLASH_ST_BUSY_BITS_READY (FLASH_ST_BUSY_VALUE_READY << FLASH_ST_BUSY_SHIFT)
#define FLASH_ST_BUSY_VALUE_BUSY 1U
#define FLASH_ST_BUSY_BITS_BUSY (FLASH_ST_BUSY_VALUE_BUSY << FLASH_ST_BUSY_SHIFT)
#define FLASH_ST_PROG_BUF_EMPTY_SHIFT 2
#define FLASH_ST_PROG_BUF_EMPTY_WIDTH 1
#define FLASH_ST_PROG_BUF_EMPTY_MASK (((1U << FLASH_ST_PROG_BUF_EMPTY_WIDTH) - 1U) << FLASH_ST_PROG_BUF_EMPTY_SHIFT)
#define FLASH_ST_PROG_BUF_EMPTY_VALUE_NOT_EMPTY 0U
#define FLASH_ST_PROG_BUF_EMPTY_BITS_NOT_EMPTY (FLASH_ST_PROG_BUF_EMPTY_VALUE_NOT_EMPTY << FLASH_ST_PROG_BUF_EMPTY_SHIFT)
#define FLASH_ST_PROG_BUF_EMPTY_VALUE_EMPTY 1U
#define FLASH_ST_PROG_BUF_EMPTY_BITS_EMPTY (FLASH_ST_PROG_BUF_EMPTY_VALUE_EMPTY << FLASH_ST_PROG_BUF_EMPTY_SHIFT)
#define FLASH_LOCK_ADDR (FLASH_BASE_ADDR + 0x0018U)
#define FLASH_LOCK (*(volatile uint32_t *)FLASH_LOCK_ADDR)
#define FLASH_LOCK_LOCK_SHIFT 0
#define FLASH_LOCK_LOCK_WIDTH 8
#define FLASH_LOCK_LOCK_MASK (((1U << FLASH_LOCK_LOCK_WIDTH) - 1U) << FLASH_LOCK_LOCK_SHIFT)
#define FLASH_LOCK_LOCK_VALUE_LOCK 85U
#define FLASH_LOCK_LOCK_BITS_LOCK (FLASH_LOCK_LOCK_VALUE_LOCK << FLASH_LOCK_LOCK_SHIFT)
#define FLASH_UNLOCK_ADDR (FLASH_BASE_ADDR + 0x001CU)
#define FLASH_UNLOCK (*(volatile uint32_t *)FLASH_UNLOCK_ADDR)
#define FLASH_UNLOCK_UNLOCK_SHIFT 0
#define FLASH_UNLOCK_UNLOCK_WIDTH 8
#define FLASH_UNLOCK_UNLOCK_MASK (((1U << FLASH_UNLOCK_UNLOCK_WIDTH) - 1U) << FLASH_UNLOCK_UNLOCK_SHIFT)
#define FLASH_UNLOCK_UNLOCK_VALUE_UNLOCK 170U
#define FLASH_UNLOCK_UNLOCK_BITS_UNLOCK (FLASH_UNLOCK_UNLOCK_VALUE_UNLOCK << FLASH_UNLOCK_UNLOCK_SHIFT)
#define FLASH_MASK_ADDR (FLASH_BASE_ADDR + 0x0020U)
#define FLASH_MASK (*(volatile uint32_t *)FLASH_MASK_ADDR)
#define FLASH_MASK_SEL_SHIFT 0
#define FLASH_MASK_SEL_WIDTH 2
#define FLASH_MASK_SEL_MASK (((1U << FLASH_MASK_SEL_WIDTH) - 1U) << FLASH_MASK_SEL_SHIFT)
#define FLASH_MASK_SEL_VALUE_NONE 0U
#define FLASH_MASK_SEL_BITS_NONE (FLASH_MASK_SEL_VALUE_NONE << FLASH_MASK_SEL_SHIFT)
#define FLASH_MASK_SEL_VALUE_2KB 1U
#define FLASH_MASK_SEL_BITS_2KB (FLASH_MASK_SEL_VALUE_2KB << FLASH_MASK_SEL_SHIFT)
#define FLASH_MASK_SEL_VALUE_4KB 2U
#define FLASH_MASK_SEL_BITS_4KB (FLASH_MASK_SEL_VALUE_4KB << FLASH_MASK_SEL_SHIFT)
#define FLASH_MASK_SEL_VALUE_8KB 3U
#define FLASH_MASK_SEL_BITS_8KB (FLASH_MASK_SEL_VALUE_8KB << FLASH_MASK_SEL_SHIFT)
#define FLASH_MASK_LOCK_SHIFT 2
#define FLASH_MASK_LOCK_WIDTH 1
#define FLASH_MASK_LOCK_MASK (((1U << FLASH_MASK_LOCK_WIDTH) - 1U) << FLASH_MASK_LOCK_SHIFT)
#define FLASH_MASK_LOCK_VALUE_NOT_SET 0U
#define FLASH_MASK_LOCK_BITS_NOT_SET (FLASH_MASK_LOCK_VALUE_NOT_SET << FLASH_MASK_LOCK_SHIFT)
#define FLASH_MASK_LOCK_VALUE_SET 1U
#define FLASH_MASK_LOCK_BITS_SET (FLASH_MASK_LOCK_VALUE_SET << FLASH_MASK_LOCK_SHIFT)
#define FLASH_ERASETIME_ADDR (FLASH_BASE_ADDR + 0x0024U)
#define FLASH_ERASETIME (*(volatile uint32_t *)FLASH_ERASETIME_ADDR)
#define FLASH_ERASETIME_TERASE_SHIFT 0
#define FLASH_ERASETIME_TERASE_WIDTH 19
#define FLASH_ERASETIME_TERASE_MASK (((1U << FLASH_ERASETIME_TERASE_WIDTH) - 1U) << FLASH_ERASETIME_TERASE_SHIFT)
#define FLASH_ERASETIME_TRCV_SHIFT 19
#define FLASH_ERASETIME_TRCV_WIDTH 12
#define FLASH_ERASETIME_TRCV_MASK (((1U << FLASH_ERASETIME_TRCV_WIDTH) - 1U) << FLASH_ERASETIME_TRCV_SHIFT)
#define FLASH_PROGTIME_ADDR (FLASH_BASE_ADDR + 0x0028U)
#define FLASH_PROGTIME (*(volatile uint32_t *)FLASH_PROGTIME_ADDR)
#define FLASH_PROGTIME_TPROG_SHIFT 0
#define FLASH_PROGTIME_TPROG_WIDTH 11
#define FLASH_PROGTIME_TPROG_MASK (((1U << FLASH_PROGTIME_TPROG_WIDTH) - 1U) << FLASH_PROGTIME_TPROG_SHIFT)
#define FLASH_PROGTIME_TPGS_SHIFT 11
#define FLASH_PROGTIME_TPGS_WIDTH 11
#define FLASH_PROGTIME_TPGS_MASK (((1U << FLASH_PROGTIME_TPGS_WIDTH) - 1U) << FLASH_PROGTIME_TPGS_SHIFT)
#endif

176
bsp/dp32g030/gpio.h Normal file
View File

@@ -0,0 +1,176 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef HARDWARE_DP32G030_GPIO_H
#define HARDWARE_DP32G030_GPIO_H
#if !defined(__ASSEMBLY__)
#include <stdint.h>
#endif
/* -------- GPIOA -------- */
#define GPIOA_BASE_ADDR 0x40060000U
#define GPIOA_BASE_SIZE 0x00000800U
#define GPIOA ((volatile GPIO_Bank_t *)GPIOA_BASE_ADDR)
/* -------- GPIOB -------- */
#define GPIOB_BASE_ADDR 0x40060800U
#define GPIOB_BASE_SIZE 0x00000800U
#define GPIOB ((volatile GPIO_Bank_t *)GPIOB_BASE_ADDR)
/* -------- GPIOC -------- */
#define GPIOC_BASE_ADDR 0x40061000U
#define GPIOC_BASE_SIZE 0x00000800U
#define GPIOC ((volatile GPIO_Bank_t *)GPIOC_BASE_ADDR)
/* -------- GPIO -------- */
typedef struct {
uint32_t DATA;
uint32_t DIR;
} GPIO_Bank_t;
#define GPIO_DIR_0_SHIFT 0
#define GPIO_DIR_0_WIDTH 1
#define GPIO_DIR_0_MASK (((1U << GPIO_DIR_0_WIDTH) - 1U) << GPIO_DIR_0_SHIFT)
#define GPIO_DIR_0_VALUE_INPUT 0U
#define GPIO_DIR_0_BITS_INPUT (GPIO_DIR_0_VALUE_INPUT << GPIO_DIR_0_SHIFT)
#define GPIO_DIR_0_VALUE_OUTPUT 1U
#define GPIO_DIR_0_BITS_OUTPUT (GPIO_DIR_0_VALUE_OUTPUT << GPIO_DIR_0_SHIFT)
#define GPIO_DIR_1_SHIFT 1
#define GPIO_DIR_1_WIDTH 1
#define GPIO_DIR_1_MASK (((1U << GPIO_DIR_1_WIDTH) - 1U) << GPIO_DIR_1_SHIFT)
#define GPIO_DIR_1_VALUE_INPUT 0U
#define GPIO_DIR_1_BITS_INPUT (GPIO_DIR_1_VALUE_INPUT << GPIO_DIR_1_SHIFT)
#define GPIO_DIR_1_VALUE_OUTPUT 1U
#define GPIO_DIR_1_BITS_OUTPUT (GPIO_DIR_1_VALUE_OUTPUT << GPIO_DIR_1_SHIFT)
#define GPIO_DIR_2_SHIFT 2
#define GPIO_DIR_2_WIDTH 1
#define GPIO_DIR_2_MASK (((1U << GPIO_DIR_2_WIDTH) - 1U) << GPIO_DIR_2_SHIFT)
#define GPIO_DIR_2_VALUE_INPUT 0U
#define GPIO_DIR_2_BITS_INPUT (GPIO_DIR_2_VALUE_INPUT << GPIO_DIR_2_SHIFT)
#define GPIO_DIR_2_VALUE_OUTPUT 1U
#define GPIO_DIR_2_BITS_OUTPUT (GPIO_DIR_2_VALUE_OUTPUT << GPIO_DIR_2_SHIFT)
#define GPIO_DIR_3_SHIFT 3
#define GPIO_DIR_3_WIDTH 1
#define GPIO_DIR_3_MASK (((1U << GPIO_DIR_3_WIDTH) - 1U) << GPIO_DIR_3_SHIFT)
#define GPIO_DIR_3_VALUE_INPUT 0U
#define GPIO_DIR_3_BITS_INPUT (GPIO_DIR_3_VALUE_INPUT << GPIO_DIR_3_SHIFT)
#define GPIO_DIR_3_VALUE_OUTPUT 1U
#define GPIO_DIR_3_BITS_OUTPUT (GPIO_DIR_3_VALUE_OUTPUT << GPIO_DIR_3_SHIFT)
#define GPIO_DIR_4_SHIFT 4
#define GPIO_DIR_4_WIDTH 1
#define GPIO_DIR_4_MASK (((1U << GPIO_DIR_4_WIDTH) - 1U) << GPIO_DIR_4_SHIFT)
#define GPIO_DIR_4_VALUE_INPUT 0U
#define GPIO_DIR_4_BITS_INPUT (GPIO_DIR_4_VALUE_INPUT << GPIO_DIR_4_SHIFT)
#define GPIO_DIR_4_VALUE_OUTPUT 1U
#define GPIO_DIR_4_BITS_OUTPUT (GPIO_DIR_4_VALUE_OUTPUT << GPIO_DIR_4_SHIFT)
#define GPIO_DIR_5_SHIFT 5
#define GPIO_DIR_5_WIDTH 1
#define GPIO_DIR_5_MASK (((1U << GPIO_DIR_5_WIDTH) - 1U) << GPIO_DIR_5_SHIFT)
#define GPIO_DIR_5_VALUE_INPUT 0U
#define GPIO_DIR_5_BITS_INPUT (GPIO_DIR_5_VALUE_INPUT << GPIO_DIR_5_SHIFT)
#define GPIO_DIR_5_VALUE_OUTPUT 1U
#define GPIO_DIR_5_BITS_OUTPUT (GPIO_DIR_5_VALUE_OUTPUT << GPIO_DIR_5_SHIFT)
#define GPIO_DIR_6_SHIFT 6
#define GPIO_DIR_6_WIDTH 1
#define GPIO_DIR_6_MASK (((1U << GPIO_DIR_6_WIDTH) - 1U) << GPIO_DIR_6_SHIFT)
#define GPIO_DIR_6_VALUE_INPUT 0U
#define GPIO_DIR_6_BITS_INPUT (GPIO_DIR_6_VALUE_INPUT << GPIO_DIR_6_SHIFT)
#define GPIO_DIR_6_VALUE_OUTPUT 1U
#define GPIO_DIR_6_BITS_OUTPUT (GPIO_DIR_6_VALUE_OUTPUT << GPIO_DIR_6_SHIFT)
#define GPIO_DIR_7_SHIFT 7
#define GPIO_DIR_7_WIDTH 1
#define GPIO_DIR_7_MASK (((1U << GPIO_DIR_7_WIDTH) - 1U) << GPIO_DIR_7_SHIFT)
#define GPIO_DIR_7_VALUE_INPUT 0U
#define GPIO_DIR_7_BITS_INPUT (GPIO_DIR_7_VALUE_INPUT << GPIO_DIR_7_SHIFT)
#define GPIO_DIR_7_VALUE_OUTPUT 1U
#define GPIO_DIR_7_BITS_OUTPUT (GPIO_DIR_7_VALUE_OUTPUT << GPIO_DIR_7_SHIFT)
#define GPIO_DIR_8_SHIFT 8
#define GPIO_DIR_8_WIDTH 1
#define GPIO_DIR_8_MASK (((1U << GPIO_DIR_8_WIDTH) - 1U) << GPIO_DIR_8_SHIFT)
#define GPIO_DIR_8_VALUE_INPUT 0U
#define GPIO_DIR_8_BITS_INPUT (GPIO_DIR_8_VALUE_INPUT << GPIO_DIR_8_SHIFT)
#define GPIO_DIR_8_VALUE_OUTPUT 1U
#define GPIO_DIR_8_BITS_OUTPUT (GPIO_DIR_8_VALUE_OUTPUT << GPIO_DIR_8_SHIFT)
#define GPIO_DIR_9_SHIFT 9
#define GPIO_DIR_9_WIDTH 1
#define GPIO_DIR_9_MASK (((1U << GPIO_DIR_9_WIDTH) - 1U) << GPIO_DIR_9_SHIFT)
#define GPIO_DIR_9_VALUE_INPUT 0U
#define GPIO_DIR_9_BITS_INPUT (GPIO_DIR_9_VALUE_INPUT << GPIO_DIR_9_SHIFT)
#define GPIO_DIR_9_VALUE_OUTPUT 1U
#define GPIO_DIR_9_BITS_OUTPUT (GPIO_DIR_9_VALUE_OUTPUT << GPIO_DIR_9_SHIFT)
#define GPIO_DIR_10_SHIFT 10
#define GPIO_DIR_10_WIDTH 1
#define GPIO_DIR_10_MASK (((1U << GPIO_DIR_10_WIDTH) - 1U) << GPIO_DIR_10_SHIFT)
#define GPIO_DIR_10_VALUE_INPUT 0U
#define GPIO_DIR_10_BITS_INPUT (GPIO_DIR_10_VALUE_INPUT << GPIO_DIR_10_SHIFT)
#define GPIO_DIR_10_VALUE_OUTPUT 1U
#define GPIO_DIR_10_BITS_OUTPUT (GPIO_DIR_10_VALUE_OUTPUT << GPIO_DIR_10_SHIFT)
#define GPIO_DIR_11_SHIFT 11
#define GPIO_DIR_11_WIDTH 1
#define GPIO_DIR_11_MASK (((1U << GPIO_DIR_11_WIDTH) - 1U) << GPIO_DIR_11_SHIFT)
#define GPIO_DIR_11_VALUE_INPUT 0U
#define GPIO_DIR_11_BITS_INPUT (GPIO_DIR_11_VALUE_INPUT << GPIO_DIR_11_SHIFT)
#define GPIO_DIR_11_VALUE_OUTPUT 1U
#define GPIO_DIR_11_BITS_OUTPUT (GPIO_DIR_11_VALUE_OUTPUT << GPIO_DIR_11_SHIFT)
#define GPIO_DIR_12_SHIFT 12
#define GPIO_DIR_12_WIDTH 1
#define GPIO_DIR_12_MASK (((1U << GPIO_DIR_12_WIDTH) - 1U) << GPIO_DIR_12_SHIFT)
#define GPIO_DIR_12_VALUE_INPUT 0U
#define GPIO_DIR_12_BITS_INPUT (GPIO_DIR_12_VALUE_INPUT << GPIO_DIR_12_SHIFT)
#define GPIO_DIR_12_VALUE_OUTPUT 1U
#define GPIO_DIR_12_BITS_OUTPUT (GPIO_DIR_12_VALUE_OUTPUT << GPIO_DIR_12_SHIFT)
#define GPIO_DIR_13_SHIFT 13
#define GPIO_DIR_13_WIDTH 1
#define GPIO_DIR_13_MASK (((1U << GPIO_DIR_13_WIDTH) - 1U) << GPIO_DIR_13_SHIFT)
#define GPIO_DIR_13_VALUE_INPUT 0U
#define GPIO_DIR_13_BITS_INPUT (GPIO_DIR_13_VALUE_INPUT << GPIO_DIR_13_SHIFT)
#define GPIO_DIR_13_VALUE_OUTPUT 1U
#define GPIO_DIR_13_BITS_OUTPUT (GPIO_DIR_13_VALUE_OUTPUT << GPIO_DIR_13_SHIFT)
#define GPIO_DIR_14_SHIFT 14
#define GPIO_DIR_14_WIDTH 1
#define GPIO_DIR_14_MASK (((1U << GPIO_DIR_14_WIDTH) - 1U) << GPIO_DIR_14_SHIFT)
#define GPIO_DIR_14_VALUE_INPUT 0U
#define GPIO_DIR_14_BITS_INPUT (GPIO_DIR_14_VALUE_INPUT << GPIO_DIR_14_SHIFT)
#define GPIO_DIR_14_VALUE_OUTPUT 1U
#define GPIO_DIR_14_BITS_OUTPUT (GPIO_DIR_14_VALUE_OUTPUT << GPIO_DIR_14_SHIFT)
#define GPIO_DIR_15_SHIFT 15
#define GPIO_DIR_15_WIDTH 1
#define GPIO_DIR_15_MASK (((1U << GPIO_DIR_15_WIDTH) - 1U) << GPIO_DIR_15_SHIFT)
#define GPIO_DIR_15_VALUE_INPUT 0U
#define GPIO_DIR_15_BITS_INPUT (GPIO_DIR_15_VALUE_INPUT << GPIO_DIR_15_SHIFT)
#define GPIO_DIR_15_VALUE_OUTPUT 1U
#define GPIO_DIR_15_BITS_OUTPUT (GPIO_DIR_15_VALUE_OUTPUT << GPIO_DIR_15_SHIFT)
#endif

40
bsp/dp32g030/irq.h Normal file
View File

@@ -0,0 +1,40 @@
#ifndef DP32G030_IRQ_H
#define DP32G030_IRQ_H
enum {
DP32_WWDT_IRQn = 0,
DP32_IWDT_IRQn,
DP32_RTC_IRQn,
DP32_DMA_IRQn,
DP32_SARADC_IRQn,
DP32_TIMER_BASE0_IRQn,
DP32_TIMER_BASE1_IRQn,
DP32_TIMER_PLUS0_IRQn,
DP32_TIMER_PLUS1_IRQn,
DP32_PWM_BASE0_IRQn,
DP32_PWM_BASE1_IRQn,
DP32_PWM_PLUS0_IRQn,
DP32_PWM_PLUS1_IRQn,
DP32_UART0_IRQn,
DP32_UART1_IRQn,
DP32_UART2_IRQn,
DP32_SPI0_IRQn,
DP32_SPI1_IRQn,
DP32_IIC0_IRQn,
DP32_IIC1_IRQn,
DP32_CMP_IRQn,
DP32_TIMER_BASE2_IRQn,
DP32_GPIOA5_IRQn,
DP32_GPIOA6_IRQn,
DP32_GPIOA7_IRQn,
DP32_GPIOB0_IRQn,
DP32_GPIOB1_IRQn,
DP32_GPIOC0_IRQn,
DP32_GPIOC1_IRQn,
DP32_GPIOA_IRQn,
DP32_GPIOB_IRQn,
DP32_GPIOC_IRQn,
};
#endif

65
bsp/dp32g030/pmu.h Normal file
View File

@@ -0,0 +1,65 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef HARDWARE_DP32G030_PMU_H
#define HARDWARE_DP32G030_PMU_H
#if !defined(__ASSEMBLY__)
#include <stdint.h>
#endif
/* -------- PMU -------- */
#define PMU_BASE_ADDR 0x40000800U
#define PMU_BASE_SIZE 0x00000800U
#define PMU_SRC_CFG_ADDR (PMU_BASE_ADDR + 0x0010U)
#define PMU_SRC_CFG (*(volatile uint32_t *)PMU_SRC_CFG_ADDR)
#define PMU_SRC_CFG_RCHF_EN_SHIFT 0
#define PMU_SRC_CFG_RCHF_EN_WIDTH 1
#define PMU_SRC_CFG_RCHF_EN_MASK (((1U << PMU_SRC_CFG_RCHF_EN_WIDTH) - 1U) << PMU_SRC_CFG_RCHF_EN_SHIFT)
#define PMU_SRC_CFG_RCHF_EN_VALUE_DISABLE 0U
#define PMU_SRC_CFG_RCHF_EN_BITS_DISABLE (PMU_SRC_CFG_RCHF_EN_VALUE_DISABLE << PMU_SRC_CFG_RCHF_EN_SHIFT)
#define PMU_SRC_CFG_RCHF_EN_VALUE_ENABLE 1U
#define PMU_SRC_CFG_RCHF_EN_BITS_ENABLE (PMU_SRC_CFG_RCHF_EN_VALUE_ENABLE << PMU_SRC_CFG_RCHF_EN_SHIFT)
#define PMU_SRC_CFG_RCHF_SEL_SHIFT 1
#define PMU_SRC_CFG_RCHF_SEL_WIDTH 1
#define PMU_SRC_CFG_RCHF_SEL_MASK (((1U << PMU_SRC_CFG_RCHF_SEL_WIDTH) - 1U) << PMU_SRC_CFG_RCHF_SEL_SHIFT)
#define PMU_SRC_CFG_RCHF_SEL_VALUE_48MHZ 0U
#define PMU_SRC_CFG_RCHF_SEL_BITS_48MHZ (PMU_SRC_CFG_RCHF_SEL_VALUE_48MHZ << PMU_SRC_CFG_RCHF_SEL_SHIFT)
#define PMU_SRC_CFG_RCHF_SEL_VALUE_24MHZ 1U
#define PMU_SRC_CFG_RCHF_SEL_BITS_24MHZ (PMU_SRC_CFG_RCHF_SEL_VALUE_24MHZ << PMU_SRC_CFG_RCHF_SEL_SHIFT)
#define PMU_TRIM_POW0_ADDR (PMU_BASE_ADDR + 0x0020U)
#define PMU_TRIM_POW0 (*(volatile uint32_t *)PMU_TRIM_POW0_ADDR)
#define PMU_TRIM_POW1_ADDR (PMU_BASE_ADDR + 0x0024U)
#define PMU_TRIM_POW1 (*(volatile uint32_t *)PMU_TRIM_POW1_ADDR)
#define PMU_TRIM_POW2_ADDR (PMU_BASE_ADDR + 0x0028U)
#define PMU_TRIM_POW2 (*(volatile uint32_t *)PMU_TRIM_POW2_ADDR)
#define PMU_TRIM_POW3_ADDR (PMU_BASE_ADDR + 0x002CU)
#define PMU_TRIM_POW3 (*(volatile uint32_t *)PMU_TRIM_POW3_ADDR)
#define PMU_TRIM_RCHF_ADDR (PMU_BASE_ADDR + 0x0030U)
#define PMU_TRIM_RCHF (*(volatile uint32_t *)PMU_TRIM_RCHF_ADDR)
#define PMU_TRIM_RCLF_ADDR (PMU_BASE_ADDR + 0x0034U)
#define PMU_TRIM_RCLF (*(volatile uint32_t *)PMU_TRIM_RCLF_ADDR)
#define PMU_TRIM_OPA_ADDR (PMU_BASE_ADDR + 0x0038U)
#define PMU_TRIM_OPA (*(volatile uint32_t *)PMU_TRIM_OPA_ADDR)
#define PMU_TRIM_PLL_ADDR (PMU_BASE_ADDR + 0x003CU)
#define PMU_TRIM_PLL (*(volatile uint32_t *)PMU_TRIM_PLL_ADDR)
#endif

2174
bsp/dp32g030/portcon.h Normal file

File diff suppressed because it is too large Load Diff

146
bsp/dp32g030/pwmplus.h Normal file
View File

@@ -0,0 +1,146 @@
#ifndef HARDWARE_DP32G030_PWMPLUS_H
#define HARDWARE_DP32G030_PWMPLUS_H
#define PWM_PLUS0_BASE_ADDR 0x400B4000U
//---------------
#define PWMPLUS_CFG 0x00U
#define PWMPLUS_CFG_COUNTER_EN_SHIFT 0U
#define PWMPLUS_CFG_COUNTER_EN_WIDTH 1U
#define PWMPLUS_CFG_COUNTER_EN_MASK (((1U << PWMPLUS_CFG_COUNTER_EN_WIDTH) - 1U) << PWMPLUS_CFG_COUNTER_EN_SHIFT)
#define PWMPLUS_CFG_COUNTER_EN_VALUE_ENABLE 1U
#define PWMPLUS_CFG_COUNTER_EN_BITS_ENABLE (PWMPLUS_CFG_COUNTER_EN_VALUE_ENABLE << PWMPLUS_CFG_COUNTER_EN_SHIFT)
#define PWMPLUS_CFG_CNT_TYPE_SHIFT 1U
#define PWMPLUS_CFG_CNT_REP_SHIFT 2U
#define PWMPLUS_CFG_CNT_REP_WIDTH 1U
#define PWMPLUS_CFG_CNT_REP_VALUE_ENABLE 1U
#define PWMPLUS_CFG_CNT_REP_BITS_ENABLE (PWMPLUS_CFG_CNT_REP_VALUE_ENABLE << PWMPLUS_CFG_CNT_REP_SHIFT)
#define PWMPLUS_CFG_OUT_MODE_SHIFT 3U
#define PWMPLUS_CFG_OUT_MODE_VALUE_ENABLE 1U
#define PWMPLUS_CFG_OUT_MODE_BITS_ENABLE (PWMPLUS_CFG_OUT_MODE_VALUE_ENABLE << PWMPLUS_CFG_OUT_MODE_SHIFT)
#define PWMPLUS_CFG_AUTO_RELOAD_SHIFT 8U
//---------------
#define PWMPLUS_GEN 0x04U
#define PWMPLUS_GEN_CH0_OE_SHIFT 24U
#define PWMPLUS_GEN_CH0_OE_WIDTH 1U
#define PWMPLUS_GEN_CH0_OE_VALUE_ENABLE 1U
#define PWMPLUS_GEN_CH0_OE_BITS_ENABLE (PWMPLUS_GEN_CH0_OE_VALUE_ENABLE << PWMPLUS_GEN_CH0_OE_SHIFT)
#define PWMPLUS_GEN_CH0_OUTINV_SHIFT 16U
#define PWMPLUS_GEN_CH0_OUTINV_WIDTH 1U
#define PWMPLUS_GEN_CH0_OUTINV_VALUE_ENABLE 1U
#define PWMPLUS_GEN_CH0_OUTINV_BITS_ENABLE (PWMPLUS_GEN_CH0_OUTINV_VALUE_ENABLE << PWMPLUS_GEN_CH0_OUTINV_SHIFT)
#define PWMPLUS_GEN_CH0_START_SHIFT 8U
#define PWMPLUS_GEN_CH0_START_WIDTH 1U
#define PWMPLUS_GEN_CH0_START_VALUE_ENABLE 1U
#define PWMPLUS_GEN_CH0_START_BITS_ENABLE (PWMPLUS_GEN_CH0_START_VALUE_ENABLE << PWMPLUS_GEN_CH0_START_SHIFT)
#define PWMPLUS_GEN_CH0_IDLE_SHIFT 0U
#define PWMPLUS_GEN_CH0_IDLE_WIDTH 1U
#define PWMPLUS_GEN_CH0_IDLE_VALUE_ENABLE 1U
#define PWMPLUS_GEN_CH0_IDLE_BITS_ENABLE (PWMPLUS_GEN_CH0_IDLE_VALUE_ENABLE << PWMPLUS_GEN_CH0_IDLE_SHIFT)
//---------------
#define PWMPLUS_CLKSRC 0x08U
#define PWMPLUS_BRAKE_CFG 0x0CU
#define PWMPLUS_MASK_LEV 0x10U
#define PWMPLUS_PERIOD 0x1CU
#define PWMPLUS_CH0_COMP 0x20U
#define PWMPLUS_CH1_COMP 0x24U
#define PWMPLUS_CH2_COMP 0x28U
#define PWMPLUS_CH0_DT 0x30U
#define PWMPLUS_CH1_DT 0x34U
#define PWMPLUS_CH2_DT 0x38U
#define PWMPLUS_TRIG_COMP 0x40U
#define PWMPLUS_TRIG_CFG 0x44U
#define PWMPLUS_IE 0x60U
#define PWMPLUS_IF 0x64U
#define PWMPLUS_SWLOAD 0x84U
#define PWMPLUS_MASK_EN 0x88
#define PWMPLUS_CNT_ST 0xE0
#define PWMPLUS_BRAKE_ST 0xE4
#define PWM_PLUS0_CFG_ADDR (PWM_PLUS0_BASE_ADDR + PWMPLUS_CFG)
#define PWM_PLUS0_CFG (*(volatile uint32_t *)PWM_PLUS0_CFG_ADDR)
#define PWM_PLUS0_GEN_ADDR (PWM_PLUS0_BASE_ADDR + PWMPLUS_GEN)
#define PWM_PLUS0_GEN (*(volatile uint32_t *)PWM_PLUS0_GEN_ADDR)
#define PWM_PLUS0_CLKSRC_ADDR (PWM_PLUS0_BASE_ADDR + PWMPLUS_CLKSRC)
#define PWM_PLUS0_CLKSRC (*(volatile uint32_t *)PWM_PLUS0_CLKSRC_ADDR)
#define PWM_PLUS0_BRAKE_CFG_ADDR (PWM_PLUS0_BASE_ADDR + PWMPLUS_BRAKE_CFG)
#define PWM_PLUS0_BRAKE_CFG (*(volatile uint32_t *)PWM_PLUS0_BRAKE_CFG_ADDR)
#define PWM_PLUS0_MASK_LEV_ADDR (PWM_PLUS0_BASE_ADDR + PWMPLUS_MASK_LEV)
#define PWM_PLUS0_MASK_LEV (*(volatile uint32_t *)PWM_PLUS0_MASK_LEV_ADDR)
#define PWM_PLUS0_PERIOD_ADDR (PWM_PLUS0_BASE_ADDR + PWMPLUS_PERIOD)
#define PWM_PLUS0_PERIOD (*(volatile uint32_t *)PWM_PLUS0_PERIOD_ADDR)
#define PWM_PLUS0_CH0_COMP_ADDR (PWM_PLUS0_BASE_ADDR + PWMPLUS_CH0_COMP)
#define PWM_PLUS0_CH0_COMP (*(volatile uint32_t *)PWM_PLUS0_CH0_COMP_ADDR)
#define PWM_PLUS0_CH1_COMP_ADDR (PWM_PLUS0_BASE_ADDR + PWMPLUS_CH1_COMP)
#define PWM_PLUS0_CH1_COMP (*(volatile uint32_t *)PWM_PLUS0_CH1_COMP_ADDR)
#define PWM_PLUS0_CH2_COMP_ADDR (PWM_PLUS0_BASE_ADDR + PWMPLUS_CH2_COMP)
#define PWM_PLUS0_CH2_COMP (*(volatile uint32_t *)PWM_PLUS0_CH2_COMP_ADDR)
#define PWM_PLUS0_CH0_DT_ADDR (PWM_PLUS0_BASE_ADDR + PWMPLUS_CH0_DT)
#define PWM_PLUS0_CH0_DT (*(volatile uint32_t *)PWM_PLUS0_CH0_DT_ADDR)
#define PWM_PLUS0_CH1_DT_ADDR (PWM_PLUS0_BASE_ADDR + PWMPLUS_CH1_DT)
#define PWM_PLUS0_CH1_DT (*(volatile uint32_t *)PWM_PLUS0_CH1_DT_ADDR)
#define PWM_PLUS0_CH2_DT_ADDR (PWM_PLUS0_BASE_ADDR + PWMPLUS_CH2_DT)
#define PWM_PLUS0_CH2_DT (*(volatile uint32_t *)PWM_PLUS0_CH2_DT_ADDR)
#define PWM_PLUS0_TRIG_COMP_ADDR (PWM_PLUS0_BASE_ADDR + PWMPLUS_TRIG_COMP)
#define PWM_PLUS0_TRIG_COMP (*(volatile uint32_t *)PWM_PLUS0_TRIG_COMP_ADDR)
#define PWM_PLUS0_TRIG_CFG_ADDR (PWM_PLUS0_BASE_ADDR + PWMPLUS_TRIG_CFG)
#define PWM_PLUS0_TRIG_CFG (*(volatile uint32_t *)PWM_PLUS0_TRIG_CFG_ADDR)
#define PWM_PLUS0_IE_ADDR (PWM_PLUS0_BASE_ADDR + PWMPLUS_IE)
#define PWM_PLUS0_IE (*(volatile uint32_t *)PWM_PLUS0_IE_ADDR)
#define PWM_PLUS0_IF_ADDR (PWM_PLUS0_BASE_ADDR + PWMPLUS_IF)
#define PWM_PLUS0_IF (*(volatile uint32_t *)PWM_PLUS0_IF_ADDR)
#define PWM_PLUS0_SWLOAD_ADDR (PWM_PLUS0_BASE_ADDR + PWMPLUS_SWLOAD)
#define PWM_PLUS0_SWLOAD (*(volatile uint32_t *)PWM_PLUS0_SWLOAD_ADDR)
#define PWM_PLUS0_MASK_EN_ADDR (PWM_PLUS0_BASE_ADDR + PWMPLUS_MASK_EN)
#define PWM_PLUS0_MASK_EN (*(volatile uint32_t *)PWM_PLUS0_MASK_EN_ADDR)
#define PWM_PLUS0_CNT_ST_ADDR (PWM_PLUS0_BASE_ADDR + PWMPLUS_CNT_ST)
#define PWM_PLUS0_CNT_ST (*(volatile uint32_t *)PWM_PLUS0_CNT_ST_ADDR)
#define PWM_PLUS0_BRAKE_ST_ADDR (PWM_PLUS0_BASE_ADDR + PWMPLUS_BRAKE_ST)
#define PWM_PLUS0_BRAKE_ST (*(volatile uint32_t *)PWM_PLUS0_BRAKE_ST_ADDR)
#endif

253
bsp/dp32g030/saradc.h Normal file
View File

@@ -0,0 +1,253 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef HARDWARE_DP32G030_SARADC_H
#define HARDWARE_DP32G030_SARADC_H
#if !defined(__ASSEMBLY__)
#include <stdint.h>
#endif
/* -------- SARADC -------- */
#define SARADC_BASE_ADDR 0x400BA000U
#define SARADC_BASE_SIZE 0x00000800U
#define SARADC_CFG_ADDR (SARADC_BASE_ADDR + 0x0000U)
#define SARADC_CFG (*(volatile uint32_t *)SARADC_CFG_ADDR)
#define SARADC_CFG_CH_SEL_SHIFT 0
#define SARADC_CFG_CH_SEL_WIDTH 15
#define SARADC_CFG_CH_SEL_MASK (((1U << SARADC_CFG_CH_SEL_WIDTH) - 1U) << SARADC_CFG_CH_SEL_SHIFT)
#define SARADC_CFG_AVG_SHIFT 16
#define SARADC_CFG_AVG_WIDTH 2
#define SARADC_CFG_AVG_MASK (((1U << SARADC_CFG_AVG_WIDTH) - 1U) << SARADC_CFG_AVG_SHIFT)
#define SARADC_CFG_AVG_VALUE_1_SAMPLE 0U
#define SARADC_CFG_AVG_BITS_1_SAMPLE (SARADC_CFG_AVG_VALUE_1_SAMPLE << SARADC_CFG_AVG_SHIFT)
#define SARADC_CFG_AVG_VALUE_2_SAMPLE 1U
#define SARADC_CFG_AVG_BITS_2_SAMPLE (SARADC_CFG_AVG_VALUE_2_SAMPLE << SARADC_CFG_AVG_SHIFT)
#define SARADC_CFG_AVG_VALUE_4_SAMPLE 2U
#define SARADC_CFG_AVG_BITS_4_SAMPLE (SARADC_CFG_AVG_VALUE_4_SAMPLE << SARADC_CFG_AVG_SHIFT)
#define SARADC_CFG_AVG_VALUE_8_SAMPLE 3U
#define SARADC_CFG_AVG_BITS_8_SAMPLE (SARADC_CFG_AVG_VALUE_8_SAMPLE << SARADC_CFG_AVG_SHIFT)
#define SARADC_CFG_CONT_SHIFT 18
#define SARADC_CFG_CONT_WIDTH 1
#define SARADC_CFG_CONT_MASK (((1U << SARADC_CFG_CONT_WIDTH) - 1U) << SARADC_CFG_CONT_SHIFT)
#define SARADC_CFG_CONT_VALUE_SINGLE 0U
#define SARADC_CFG_CONT_BITS_SINGLE (SARADC_CFG_CONT_VALUE_SINGLE << SARADC_CFG_CONT_SHIFT)
#define SARADC_CFG_CONT_VALUE_CONTINUOUS 1U
#define SARADC_CFG_CONT_BITS_CONTINUOUS (SARADC_CFG_CONT_VALUE_CONTINUOUS << SARADC_CFG_CONT_SHIFT)
#define SARADC_CFG_SMPL_SETUP_SHIFT 19
#define SARADC_CFG_SMPL_SETUP_WIDTH 3
#define SARADC_CFG_SMPL_SETUP_MASK (((1U << SARADC_CFG_SMPL_SETUP_WIDTH) - 1U) << SARADC_CFG_SMPL_SETUP_SHIFT)
#define SARADC_CFG_SMPL_SETUP_VALUE_1_CYCLE 0U
#define SARADC_CFG_SMPL_SETUP_BITS_1_CYCLE (SARADC_CFG_SMPL_SETUP_VALUE_1_CYCLE << SARADC_CFG_SMPL_SETUP_SHIFT)
#define SARADC_CFG_SMPL_SETUP_VALUE_2_CYCLE 1U
#define SARADC_CFG_SMPL_SETUP_BITS_2_CYCLE (SARADC_CFG_SMPL_SETUP_VALUE_2_CYCLE << SARADC_CFG_SMPL_SETUP_SHIFT)
#define SARADC_CFG_SMPL_SETUP_VALUE_4_CYCLE 2U
#define SARADC_CFG_SMPL_SETUP_BITS_4_CYCLE (SARADC_CFG_SMPL_SETUP_VALUE_4_CYCLE << SARADC_CFG_SMPL_SETUP_SHIFT)
#define SARADC_CFG_SMPL_SETUP_VALUE_8_CYCLE 3U
#define SARADC_CFG_SMPL_SETUP_BITS_8_CYCLE (SARADC_CFG_SMPL_SETUP_VALUE_8_CYCLE << SARADC_CFG_SMPL_SETUP_SHIFT)
#define SARADC_CFG_SMPL_SETUP_VALUE_16_CYCLE 4U
#define SARADC_CFG_SMPL_SETUP_BITS_16_CYCLE (SARADC_CFG_SMPL_SETUP_VALUE_16_CYCLE << SARADC_CFG_SMPL_SETUP_SHIFT)
#define SARADC_CFG_SMPL_SETUP_VALUE_32_CYCLE 5U
#define SARADC_CFG_SMPL_SETUP_BITS_32_CYCLE (SARADC_CFG_SMPL_SETUP_VALUE_32_CYCLE << SARADC_CFG_SMPL_SETUP_SHIFT)
#define SARADC_CFG_SMPL_SETUP_VALUE_64_CYCLE 6U
#define SARADC_CFG_SMPL_SETUP_BITS_64_CYCLE (SARADC_CFG_SMPL_SETUP_VALUE_64_CYCLE << SARADC_CFG_SMPL_SETUP_SHIFT)
#define SARADC_CFG_SMPL_SETUP_VALUE_128_CYCLE 7U
#define SARADC_CFG_SMPL_SETUP_BITS_128_CYCLE (SARADC_CFG_SMPL_SETUP_VALUE_128_CYCLE << SARADC_CFG_SMPL_SETUP_SHIFT)
#define SARADC_CFG_MEM_MODE_SHIFT 22
#define SARADC_CFG_MEM_MODE_WIDTH 1
#define SARADC_CFG_MEM_MODE_MASK (((1U << SARADC_CFG_MEM_MODE_WIDTH) - 1U) << SARADC_CFG_MEM_MODE_SHIFT)
#define SARADC_CFG_MEM_MODE_VALUE_FIFO 0U
#define SARADC_CFG_MEM_MODE_BITS_FIFO (SARADC_CFG_MEM_MODE_VALUE_FIFO << SARADC_CFG_MEM_MODE_SHIFT)
#define SARADC_CFG_MEM_MODE_VALUE_CHANNEL 1U
#define SARADC_CFG_MEM_MODE_BITS_CHANNEL (SARADC_CFG_MEM_MODE_VALUE_CHANNEL << SARADC_CFG_MEM_MODE_SHIFT)
#define SARADC_CFG_SMPL_CLK_SHIFT 23
#define SARADC_CFG_SMPL_CLK_WIDTH 1
#define SARADC_CFG_SMPL_CLK_MASK (((1U << SARADC_CFG_SMPL_CLK_WIDTH) - 1U) << SARADC_CFG_SMPL_CLK_SHIFT)
#define SARADC_CFG_SMPL_CLK_VALUE_EXTERNAL 0U
#define SARADC_CFG_SMPL_CLK_BITS_EXTERNAL (SARADC_CFG_SMPL_CLK_VALUE_EXTERNAL << SARADC_CFG_SMPL_CLK_SHIFT)
#define SARADC_CFG_SMPL_CLK_VALUE_INTERNAL 1U
#define SARADC_CFG_SMPL_CLK_BITS_INTERNAL (SARADC_CFG_SMPL_CLK_VALUE_INTERNAL << SARADC_CFG_SMPL_CLK_SHIFT)
#define SARADC_CFG_SMPL_WIN_SHIFT 24
#define SARADC_CFG_SMPL_WIN_WIDTH 3
#define SARADC_CFG_SMPL_WIN_MASK (((1U << SARADC_CFG_SMPL_WIN_WIDTH) - 1U) << SARADC_CFG_SMPL_WIN_SHIFT)
#define SARADC_CFG_SMPL_WIN_VALUE_1_CYCLE 0U
#define SARADC_CFG_SMPL_WIN_BITS_1_CYCLE (SARADC_CFG_SMPL_WIN_VALUE_1_CYCLE << SARADC_CFG_SMPL_WIN_SHIFT)
#define SARADC_CFG_SMPL_WIN_VALUE_3_CYCLE 1U
#define SARADC_CFG_SMPL_WIN_BITS_3_CYCLE (SARADC_CFG_SMPL_WIN_VALUE_3_CYCLE << SARADC_CFG_SMPL_WIN_SHIFT)
#define SARADC_CFG_SMPL_WIN_VALUE_5_CYCLE 2U
#define SARADC_CFG_SMPL_WIN_BITS_5_CYCLE (SARADC_CFG_SMPL_WIN_VALUE_5_CYCLE << SARADC_CFG_SMPL_WIN_SHIFT)
#define SARADC_CFG_SMPL_WIN_VALUE_7_CYCLE 3U
#define SARADC_CFG_SMPL_WIN_BITS_7_CYCLE (SARADC_CFG_SMPL_WIN_VALUE_7_CYCLE << SARADC_CFG_SMPL_WIN_SHIFT)
#define SARADC_CFG_SMPL_WIN_VALUE_9_CYCLE 4U
#define SARADC_CFG_SMPL_WIN_BITS_9_CYCLE (SARADC_CFG_SMPL_WIN_VALUE_9_CYCLE << SARADC_CFG_SMPL_WIN_SHIFT)
#define SARADC_CFG_SMPL_WIN_VALUE_11_CYCLE 5U
#define SARADC_CFG_SMPL_WIN_BITS_11_CYCLE (SARADC_CFG_SMPL_WIN_VALUE_11_CYCLE << SARADC_CFG_SMPL_WIN_SHIFT)
#define SARADC_CFG_SMPL_WIN_VALUE_13_CYCLE 6U
#define SARADC_CFG_SMPL_WIN_BITS_13_CYCLE (SARADC_CFG_SMPL_WIN_VALUE_13_CYCLE << SARADC_CFG_SMPL_WIN_SHIFT)
#define SARADC_CFG_SMPL_WIN_VALUE_15_CYCLE 7U
#define SARADC_CFG_SMPL_WIN_BITS_15_CYCLE (SARADC_CFG_SMPL_WIN_VALUE_15_CYCLE << SARADC_CFG_SMPL_WIN_SHIFT)
#define SARADC_CFG_ADC_EN_SHIFT 27
#define SARADC_CFG_ADC_EN_WIDTH 1
#define SARADC_CFG_ADC_EN_MASK (((1U << SARADC_CFG_ADC_EN_WIDTH) - 1U) << SARADC_CFG_ADC_EN_SHIFT)
#define SARADC_CFG_ADC_EN_VALUE_DISABLE 0U
#define SARADC_CFG_ADC_EN_BITS_DISABLE (SARADC_CFG_ADC_EN_VALUE_DISABLE << SARADC_CFG_ADC_EN_SHIFT)
#define SARADC_CFG_ADC_EN_VALUE_ENABLE 1U
#define SARADC_CFG_ADC_EN_BITS_ENABLE (SARADC_CFG_ADC_EN_VALUE_ENABLE << SARADC_CFG_ADC_EN_SHIFT)
#define SARADC_CFG_ADC_TRIG_SHIFT 28
#define SARADC_CFG_ADC_TRIG_WIDTH 1
#define SARADC_CFG_ADC_TRIG_MASK (((1U << SARADC_CFG_ADC_TRIG_WIDTH) - 1U) << SARADC_CFG_ADC_TRIG_SHIFT)
#define SARADC_CFG_ADC_TRIG_VALUE_CPU 0U
#define SARADC_CFG_ADC_TRIG_BITS_CPU (SARADC_CFG_ADC_TRIG_VALUE_CPU << SARADC_CFG_ADC_TRIG_SHIFT)
#define SARADC_CFG_ADC_TRIG_VALUE_EXTERNAL 1U
#define SARADC_CFG_ADC_TRIG_BITS_EXTERNAL (SARADC_CFG_ADC_TRIG_VALUE_EXTERNAL << SARADC_CFG_ADC_TRIG_SHIFT)
#define SARADC_CFG_DMA_EN_SHIFT 29
#define SARADC_CFG_DMA_EN_WIDTH 1
#define SARADC_CFG_DMA_EN_MASK (((1U << SARADC_CFG_DMA_EN_WIDTH) - 1U) << SARADC_CFG_DMA_EN_SHIFT)
#define SARADC_CFG_DMA_EN_VALUE_DISABLE 0U
#define SARADC_CFG_DMA_EN_BITS_DISABLE (SARADC_CFG_DMA_EN_VALUE_DISABLE << SARADC_CFG_DMA_EN_SHIFT)
#define SARADC_CFG_DMA_EN_VALUE_ENABLE 1U
#define SARADC_CFG_DMA_EN_BITS_ENABLE (SARADC_CFG_DMA_EN_VALUE_ENABLE << SARADC_CFG_DMA_EN_SHIFT)
#define SARADC_START_ADDR (SARADC_BASE_ADDR + 0x0004U)
#define SARADC_START (*(volatile uint32_t *)SARADC_START_ADDR)
#define SARADC_START_START_SHIFT 0
#define SARADC_START_START_WIDTH 1
#define SARADC_START_START_MASK (((1U << SARADC_START_START_WIDTH) - 1U) << SARADC_START_START_SHIFT)
#define SARADC_START_START_VALUE_DISABLE 0U
#define SARADC_START_START_BITS_DISABLE (SARADC_START_START_VALUE_DISABLE << SARADC_START_START_SHIFT)
#define SARADC_START_START_VALUE_ENABLE 1U
#define SARADC_START_START_BITS_ENABLE (SARADC_START_START_VALUE_ENABLE << SARADC_START_START_SHIFT)
#define SARADC_START_SOFT_RESET_SHIFT 2
#define SARADC_START_SOFT_RESET_WIDTH 1
#define SARADC_START_SOFT_RESET_MASK (((1U << SARADC_START_SOFT_RESET_WIDTH) - 1U) << SARADC_START_SOFT_RESET_SHIFT)
#define SARADC_START_SOFT_RESET_VALUE_ASSERT 0U
#define SARADC_START_SOFT_RESET_BITS_ASSERT (SARADC_START_SOFT_RESET_VALUE_ASSERT << SARADC_START_SOFT_RESET_SHIFT)
#define SARADC_START_SOFT_RESET_VALUE_DEASSERT 1U
#define SARADC_START_SOFT_RESET_BITS_DEASSERT (SARADC_START_SOFT_RESET_VALUE_DEASSERT << SARADC_START_SOFT_RESET_SHIFT)
#define SARADC_IE_ADDR (SARADC_BASE_ADDR + 0x0008U)
#define SARADC_IE (*(volatile uint32_t *)SARADC_IE_ADDR)
#define SARADC_IE_CHx_EOC_SHIFT 0
#define SARADC_IE_CHx_EOC_WIDTH 16
#define SARADC_IE_CHx_EOC_MASK (((1U << SARADC_IE_CHx_EOC_WIDTH) - 1U) << SARADC_IE_CHx_EOC_SHIFT)
#define SARADC_IE_CHx_EOC_VALUE_NONE 0U
#define SARADC_IE_CHx_EOC_BITS_NONE (SARADC_IE_CHx_EOC_VALUE_NONE << SARADC_IE_CHx_EOC_SHIFT)
#define SARADC_IE_CHx_EOC_VALUE_ALL 65535U
#define SARADC_IE_CHx_EOC_BITS_ALL (SARADC_IE_CHx_EOC_VALUE_ALL << SARADC_IE_CHx_EOC_SHIFT)
#define SARADC_IE_FIFO_FULL_SHIFT 16
#define SARADC_IE_FIFO_FULL_WIDTH 1
#define SARADC_IE_FIFO_FULL_MASK (((1U << SARADC_IE_FIFO_FULL_WIDTH) - 1U) << SARADC_IE_FIFO_FULL_SHIFT)
#define SARADC_IE_FIFO_FULL_VALUE_DISABLE 0U
#define SARADC_IE_FIFO_FULL_BITS_DISABLE (SARADC_IE_FIFO_FULL_VALUE_DISABLE << SARADC_IE_FIFO_FULL_SHIFT)
#define SARADC_IE_FIFO_FULL_VALUE_ENABLE 1U
#define SARADC_IE_FIFO_FULL_BITS_ENABLE (SARADC_IE_FIFO_FULL_VALUE_ENABLE << SARADC_IE_FIFO_FULL_SHIFT)
#define SARADC_IE_FIFO_HFULL_SHIFT 17
#define SARADC_IE_FIFO_HFULL_WIDTH 1
#define SARADC_IE_FIFO_HFULL_MASK (((1U << SARADC_IE_FIFO_HFULL_WIDTH) - 1U) << SARADC_IE_FIFO_HFULL_SHIFT)
#define SARADC_IE_FIFO_HFULL_VALUE_DISABLE 0U
#define SARADC_IE_FIFO_HFULL_BITS_DISABLE (SARADC_IE_FIFO_HFULL_VALUE_DISABLE << SARADC_IE_FIFO_HFULL_SHIFT)
#define SARADC_IE_FIFO_HFULL_VALUE_ENABLE 1U
#define SARADC_IE_FIFO_HFULL_BITS_ENABLE (SARADC_IE_FIFO_HFULL_VALUE_ENABLE << SARADC_IE_FIFO_HFULL_SHIFT)
#define SARADC_IF_ADDR (SARADC_BASE_ADDR + 0x000CU)
#define SARADC_IF (*(volatile uint32_t *)SARADC_IF_ADDR)
#define SARADC_IF_CHx_EOC_SHIFT 0
#define SARADC_IF_CHx_EOC_WIDTH 16
#define SARADC_IF_CHx_EOC_MASK (((1U << SARADC_IF_CHx_EOC_WIDTH) - 1U) << SARADC_IF_CHx_EOC_SHIFT)
#define SARADC_IF_FIFO_FULL_SHIFT 16
#define SARADC_IF_FIFO_FULL_WIDTH 1
#define SARADC_IF_FIFO_FULL_MASK (((1U << SARADC_IF_FIFO_FULL_WIDTH) - 1U) << SARADC_IF_FIFO_FULL_SHIFT)
#define SARADC_IF_FIFO_FULL_VALUE_NOT_SET 0U
#define SARADC_IF_FIFO_FULL_BITS_NOT_SET (SARADC_IF_FIFO_FULL_VALUE_NOT_SET << SARADC_IF_FIFO_FULL_SHIFT)
#define SARADC_IF_FIFO_FULL_VALUE_SET 1U
#define SARADC_IF_FIFO_FULL_BITS_SET (SARADC_IF_FIFO_FULL_VALUE_SET << SARADC_IF_FIFO_FULL_SHIFT)
#define SARADC_IF_FIFO_HFULL_SHIFT 17
#define SARADC_IF_FIFO_HFULL_WIDTH 1
#define SARADC_IF_FIFO_HFULL_MASK (((1U << SARADC_IF_FIFO_HFULL_WIDTH) - 1U) << SARADC_IF_FIFO_HFULL_SHIFT)
#define SARADC_IF_FIFO_HFULL_VALUE_NOT_SET 0U
#define SARADC_IF_FIFO_HFULL_BITS_NOT_SET (SARADC_IF_FIFO_HFULL_VALUE_NOT_SET << SARADC_IF_FIFO_HFULL_SHIFT)
#define SARADC_IF_FIFO_HFULL_VALUE_SET 1U
#define SARADC_IF_FIFO_HFULL_BITS_SET (SARADC_IF_FIFO_HFULL_VALUE_SET << SARADC_IF_FIFO_HFULL_SHIFT)
#define SARADC_CH0_ADDR (SARADC_BASE_ADDR + 0x0010U)
#define SARADC_CH0 (*(volatile uint32_t *)SARADC_CH0_ADDR)
#define SARADC_EXTTRIG_SEL_ADDR (SARADC_BASE_ADDR + 0x00B0U)
#define SARADC_EXTTRIG_SEL (*(volatile uint32_t *)SARADC_EXTTRIG_SEL_ADDR)
#define SARADC_CALIB_OFFSET_ADDR (SARADC_BASE_ADDR + 0x00F0U)
#define SARADC_CALIB_OFFSET (*(volatile uint32_t *)SARADC_CALIB_OFFSET_ADDR)
#define SARADC_CALIB_OFFSET_OFFSET_SHIFT 0
#define SARADC_CALIB_OFFSET_OFFSET_WIDTH 8
#define SARADC_CALIB_OFFSET_OFFSET_MASK (((1U << SARADC_CALIB_OFFSET_OFFSET_WIDTH) - 1U) << SARADC_CALIB_OFFSET_OFFSET_SHIFT)
#define SARADC_CALIB_OFFSET_VALID_SHIFT 16
#define SARADC_CALIB_OFFSET_VALID_WIDTH 1
#define SARADC_CALIB_OFFSET_VALID_MASK (((1U << SARADC_CALIB_OFFSET_VALID_WIDTH) - 1U) << SARADC_CALIB_OFFSET_VALID_SHIFT)
#define SARADC_CALIB_OFFSET_VALID_VALUE_NO 0U
#define SARADC_CALIB_OFFSET_VALID_BITS_NO (SARADC_CALIB_OFFSET_VALID_VALUE_NO << SARADC_CALIB_OFFSET_VALID_SHIFT)
#define SARADC_CALIB_OFFSET_VALID_VALUE_YES 1U
#define SARADC_CALIB_OFFSET_VALID_BITS_YES (SARADC_CALIB_OFFSET_VALID_VALUE_YES << SARADC_CALIB_OFFSET_VALID_SHIFT)
#define SARADC_CALIB_KD_ADDR (SARADC_BASE_ADDR + 0x00F4U)
#define SARADC_CALIB_KD (*(volatile uint32_t *)SARADC_CALIB_KD_ADDR)
#define SARADC_CALIB_KD_KD_SHIFT 0
#define SARADC_CALIB_KD_KD_WIDTH 8
#define SARADC_CALIB_KD_KD_MASK (((1U << SARADC_CALIB_KD_KD_WIDTH) - 1U) << SARADC_CALIB_KD_KD_SHIFT)
#define SARADC_CALIB_KD_VALID_SHIFT 16
#define SARADC_CALIB_KD_VALID_WIDTH 1
#define SARADC_CALIB_KD_VALID_MASK (((1U << SARADC_CALIB_KD_VALID_WIDTH) - 1U) << SARADC_CALIB_KD_VALID_SHIFT)
#define SARADC_CALIB_KD_VALID_VALUE_NO 0U
#define SARADC_CALIB_KD_VALID_BITS_NO (SARADC_CALIB_KD_VALID_VALUE_NO << SARADC_CALIB_KD_VALID_SHIFT)
#define SARADC_CALIB_KD_VALID_VALUE_YES 1U
#define SARADC_CALIB_KD_VALID_BITS_YES (SARADC_CALIB_KD_VALID_VALUE_YES << SARADC_CALIB_KD_VALID_SHIFT)
/* -------- ADC_CHx -------- */
typedef struct {
uint32_t STAT;
uint32_t DATA;
} ADC_Channel_t;
#define ADC_CHx_STAT_EOC_SHIFT 0
#define ADC_CHx_STAT_EOC_WIDTH 1
#define ADC_CHx_STAT_EOC_MASK (((1U << ADC_CHx_STAT_EOC_WIDTH) - 1U) << ADC_CHx_STAT_EOC_SHIFT)
#define ADC_CHx_STAT_EOC_VALUE_NOT_COMPLETE 0U
#define ADC_CHx_STAT_EOC_BITS_NOT_COMPLETE (ADC_CHx_STAT_EOC_VALUE_NOT_COMPLETE << ADC_CHx_STAT_EOC_SHIFT)
#define ADC_CHx_STAT_EOC_VALUE_COMPLETE 1U
#define ADC_CHx_STAT_EOC_BITS_COMPLETE (ADC_CHx_STAT_EOC_VALUE_COMPLETE << ADC_CHx_STAT_EOC_SHIFT)
#define ADC_CHx_DATA_DATA_SHIFT 0
#define ADC_CHx_DATA_DATA_WIDTH 12
#define ADC_CHx_DATA_DATA_MASK (((1U << ADC_CHx_DATA_DATA_WIDTH) - 1U) << ADC_CHx_DATA_DATA_SHIFT)
#define ADC_CHx_DATA_NUM_SHIFT 12
#define ADC_CHx_DATA_NUM_WIDTH 4
#define ADC_CHx_DATA_NUM_MASK (((1U << ADC_CHx_DATA_NUM_WIDTH) - 1U) << ADC_CHx_DATA_NUM_SHIFT)
#endif

240
bsp/dp32g030/spi.h Normal file
View File

@@ -0,0 +1,240 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef HARDWARE_DP32G030_SPI_H
#define HARDWARE_DP32G030_SPI_H
#if !defined(__ASSEMBLY__)
#include <stdint.h>
#endif
/* -------- SPI0 -------- */
#define SPI0_BASE_ADDR 0x400B8000U
#define SPI0_BASE_SIZE 0x00000800U
#define SPI0 ((volatile SPI_Port_t *)SPI0_BASE_ADDR)
/* -------- SPI1 -------- */
#define SPI1_BASE_ADDR 0x400B8800U
#define SPI1_BASE_SIZE 0x00000800U
#define SPI1 ((volatile SPI_Port_t *)SPI1_BASE_ADDR)
/* -------- SPI -------- */
typedef struct {
uint32_t CR;
uint32_t WDR;
uint32_t RDR;
uint32_t Reserved_000C[1];
uint32_t IE;
uint32_t IF;
uint32_t FIFOST;
} SPI_Port_t;
#define SPI_CR_SPR_SHIFT 0
#define SPI_CR_SPR_WIDTH 3
#define SPI_CR_SPR_MASK (((1U << SPI_CR_SPR_WIDTH) - 1U) << SPI_CR_SPR_SHIFT)
#define SPI_CR_SPR_VALUE_FPCLK_DIV_4 0U
#define SPI_CR_SPR_BITS_FPCLK_DIV_4 (SPI_CR_SPR_VALUE_FPCLK_DIV_4 << SPI_CR_SPR_SHIFT)
#define SPI_CR_SPR_VALUE_FPCLK_DIV_8 1U
#define SPI_CR_SPR_BITS_FPCLK_DIV_8 (SPI_CR_SPR_VALUE_FPCLK_DIV_8 << SPI_CR_SPR_SHIFT)
#define SPI_CR_SPR_VALUE_FPCLK_DIV_16 2U
#define SPI_CR_SPR_BITS_FPCLK_DIV_16 (SPI_CR_SPR_VALUE_FPCLK_DIV_16 << SPI_CR_SPR_SHIFT)
#define SPI_CR_SPR_VALUE_FPCLK_DIV_32 3U
#define SPI_CR_SPR_BITS_FPCLK_DIV_32 (SPI_CR_SPR_VALUE_FPCLK_DIV_32 << SPI_CR_SPR_SHIFT)
#define SPI_CR_SPR_VALUE_FPCLK_DIV_64 4U
#define SPI_CR_SPR_BITS_FPCLK_DIV_64 (SPI_CR_SPR_VALUE_FPCLK_DIV_64 << SPI_CR_SPR_SHIFT)
#define SPI_CR_SPR_VALUE_FPCLK_DIV_128 5U
#define SPI_CR_SPR_BITS_FPCLK_DIV_128 (SPI_CR_SPR_VALUE_FPCLK_DIV_128 << SPI_CR_SPR_SHIFT)
#define SPI_CR_SPR_VALUE_FPCLK_DIV_256 6U
#define SPI_CR_SPR_BITS_FPCLK_DIV_256 (SPI_CR_SPR_VALUE_FPCLK_DIV_256 << SPI_CR_SPR_SHIFT)
#define SPI_CR_SPR_VALUE_FPCLK_DIV_512 7U
#define SPI_CR_SPR_BITS_FPCLK_DIV_512 (SPI_CR_SPR_VALUE_FPCLK_DIV_512 << SPI_CR_SPR_SHIFT)
#define SPI_CR_SPE_SHIFT 3
#define SPI_CR_SPE_WIDTH 1
#define SPI_CR_SPE_MASK (((1U << SPI_CR_SPE_WIDTH) - 1U) << SPI_CR_SPE_SHIFT)
#define SPI_CR_SPE_VALUE_DISABLE 0U
#define SPI_CR_SPE_BITS_DISABLE (SPI_CR_SPE_VALUE_DISABLE << SPI_CR_SPE_SHIFT)
#define SPI_CR_SPE_VALUE_ENABLE 1U
#define SPI_CR_SPE_BITS_ENABLE (SPI_CR_SPE_VALUE_ENABLE << SPI_CR_SPE_SHIFT)
#define SPI_CR_CPHA_SHIFT 4
#define SPI_CR_CPHA_WIDTH 1
#define SPI_CR_CPHA_MASK (((1U << SPI_CR_CPHA_WIDTH) - 1U) << SPI_CR_CPHA_SHIFT)
#define SPI_CR_CPOL_SHIFT 5
#define SPI_CR_CPOL_WIDTH 1
#define SPI_CR_CPOL_MASK (((1U << SPI_CR_CPOL_WIDTH) - 1U) << SPI_CR_CPOL_SHIFT)
#define SPI_CR_MSTR_SHIFT 6
#define SPI_CR_MSTR_WIDTH 1
#define SPI_CR_MSTR_MASK (((1U << SPI_CR_MSTR_WIDTH) - 1U) << SPI_CR_MSTR_SHIFT)
#define SPI_CR_LSB_SHIFT 7
#define SPI_CR_LSB_WIDTH 1
#define SPI_CR_LSB_MASK (((1U << SPI_CR_LSB_WIDTH) - 1U) << SPI_CR_LSB_SHIFT)
#define SPI_CR_CPHA_DATA_HOLD_S_SHIFT 8
#define SPI_CR_CPHA_DATA_HOLD_S_WIDTH 4
#define SPI_CR_CPHA_DATA_HOLD_S_MASK (((1U << SPI_CR_CPHA_DATA_HOLD_S_WIDTH) - 1U) << SPI_CR_CPHA_DATA_HOLD_S_SHIFT)
#define SPI_CR_MSR_SSN_SHIFT 12
#define SPI_CR_MSR_SSN_WIDTH 1
#define SPI_CR_MSR_SSN_MASK (((1U << SPI_CR_MSR_SSN_WIDTH) - 1U) << SPI_CR_MSR_SSN_SHIFT)
#define SPI_CR_MSR_SSN_VALUE_DISABLE 0U
#define SPI_CR_MSR_SSN_BITS_DISABLE (SPI_CR_MSR_SSN_VALUE_DISABLE << SPI_CR_MSR_SSN_SHIFT)
#define SPI_CR_MSR_SSN_VALUE_ENABLE 1U
#define SPI_CR_MSR_SSN_BITS_ENABLE (SPI_CR_MSR_SSN_VALUE_ENABLE << SPI_CR_MSR_SSN_SHIFT)
#define SPI_CR_RXDMAEN_SHIFT 13
#define SPI_CR_RXDMAEN_WIDTH 1
#define SPI_CR_RXDMAEN_MASK (((1U << SPI_CR_RXDMAEN_WIDTH) - 1U) << SPI_CR_RXDMAEN_SHIFT)
#define SPI_CR_TXDMAEN_SHIFT 14
#define SPI_CR_TXDMAEN_WIDTH 1
#define SPI_CR_TXDMAEN_MASK (((1U << SPI_CR_TXDMAEN_WIDTH) - 1U) << SPI_CR_TXDMAEN_SHIFT)
#define SPI_CR_RF_CLR_SHIFT 15
#define SPI_CR_RF_CLR_WIDTH 1
#define SPI_CR_RF_CLR_MASK (((1U << SPI_CR_RF_CLR_WIDTH) - 1U) << SPI_CR_RF_CLR_SHIFT)
#define SPI_CR_TF_CLR_SHIFT 16
#define SPI_CR_TF_CLR_WIDTH 1
#define SPI_CR_TF_CLR_MASK (((1U << SPI_CR_TF_CLR_WIDTH) - 1U) << SPI_CR_TF_CLR_SHIFT)
#define SPI_IE_RXFIFO_OVF_SHIFT 0
#define SPI_IE_RXFIFO_OVF_WIDTH 1
#define SPI_IE_RXFIFO_OVF_MASK (((1U << SPI_IE_RXFIFO_OVF_WIDTH) - 1U) << SPI_IE_RXFIFO_OVF_SHIFT)
#define SPI_IE_RXFIFO_OVF_VALUE_DISABLE 0U
#define SPI_IE_RXFIFO_OVF_BITS_DISABLE (SPI_IE_RXFIFO_OVF_VALUE_DISABLE << SPI_IE_RXFIFO_OVF_SHIFT)
#define SPI_IE_RXFIFO_OVF_VALUE_ENABLE 1U
#define SPI_IE_RXFIFO_OVF_BITS_ENABLE (SPI_IE_RXFIFO_OVF_VALUE_ENABLE << SPI_IE_RXFIFO_OVF_SHIFT)
#define SPI_IE_RXFIFO_FULL_SHIFT 1
#define SPI_IE_RXFIFO_FULL_WIDTH 1
#define SPI_IE_RXFIFO_FULL_MASK (((1U << SPI_IE_RXFIFO_FULL_WIDTH) - 1U) << SPI_IE_RXFIFO_FULL_SHIFT)
#define SPI_IE_RXFIFO_FULL_VALUE_DISABLE 0U
#define SPI_IE_RXFIFO_FULL_BITS_DISABLE (SPI_IE_RXFIFO_FULL_VALUE_DISABLE << SPI_IE_RXFIFO_FULL_SHIFT)
#define SPI_IE_RXFIFO_FULL_VALUE_ENABLE 1U
#define SPI_IE_RXFIFO_FULL_BITS_ENABLE (SPI_IE_RXFIFO_FULL_VALUE_ENABLE << SPI_IE_RXFIFO_FULL_SHIFT)
#define SPI_IE_RXFIFO_HFULL_SHIFT 2
#define SPI_IE_RXFIFO_HFULL_WIDTH 1
#define SPI_IE_RXFIFO_HFULL_MASK (((1U << SPI_IE_RXFIFO_HFULL_WIDTH) - 1U) << SPI_IE_RXFIFO_HFULL_SHIFT)
#define SPI_IE_RXFIFO_HFULL_VALUE_DISABLE 0U
#define SPI_IE_RXFIFO_HFULL_BITS_DISABLE (SPI_IE_RXFIFO_HFULL_VALUE_DISABLE << SPI_IE_RXFIFO_HFULL_SHIFT)
#define SPI_IE_RXFIFO_HFULL_VALUE_ENABLE 1U
#define SPI_IE_RXFIFO_HFULL_BITS_ENABLE (SPI_IE_RXFIFO_HFULL_VALUE_ENABLE << SPI_IE_RXFIFO_HFULL_SHIFT)
#define SPI_IE_TXFIFO_EMPTY_SHIFT 3
#define SPI_IE_TXFIFO_EMPTY_WIDTH 1
#define SPI_IE_TXFIFO_EMPTY_MASK (((1U << SPI_IE_TXFIFO_EMPTY_WIDTH) - 1U) << SPI_IE_TXFIFO_EMPTY_SHIFT)
#define SPI_IE_TXFIFO_EMPTY_VALUE_DISABLE 0U
#define SPI_IE_TXFIFO_EMPTY_BITS_DISABLE (SPI_IE_TXFIFO_EMPTY_VALUE_DISABLE << SPI_IE_TXFIFO_EMPTY_SHIFT)
#define SPI_IE_TXFIFO_EMPTY_VALUE_ENABLE 1U
#define SPI_IE_TXFIFO_EMPTY_BITS_ENABLE (SPI_IE_TXFIFO_EMPTY_VALUE_ENABLE << SPI_IE_TXFIFO_EMPTY_SHIFT)
#define SPI_IE_TXFIFO_HFULL_SHIFT 4
#define SPI_IE_TXFIFO_HFULL_WIDTH 1
#define SPI_IE_TXFIFO_HFULL_MASK (((1U << SPI_IE_TXFIFO_HFULL_WIDTH) - 1U) << SPI_IE_TXFIFO_HFULL_SHIFT)
#define SPI_IE_TXFIFO_HFULL_VALUE_DISABLE 0U
#define SPI_IE_TXFIFO_HFULL_BITS_DISABLE (SPI_IE_TXFIFO_HFULL_VALUE_DISABLE << SPI_IE_TXFIFO_HFULL_SHIFT)
#define SPI_IE_TXFIFO_HFULL_VALUE_ENABLE 1U
#define SPI_IE_TXFIFO_HFULL_BITS_ENABLE (SPI_IE_TXFIFO_HFULL_VALUE_ENABLE << SPI_IE_TXFIFO_HFULL_SHIFT)
#define SPI_FIFOST_RFE_SHIFT 0
#define SPI_FIFOST_RFE_WIDTH 1
#define SPI_FIFOST_RFE_MASK (((1U << SPI_FIFOST_RFE_WIDTH) - 1U) << SPI_FIFOST_RFE_SHIFT)
#define SPI_FIFOST_RFE_VALUE_NOT_EMPTY 0U
#define SPI_FIFOST_RFE_BITS_NOT_EMPTY (SPI_FIFOST_RFE_VALUE_NOT_EMPTY << SPI_FIFOST_RFE_SHIFT)
#define SPI_FIFOST_RFE_VALUE_EMPTY 1U
#define SPI_FIFOST_RFE_BITS_EMPTY (SPI_FIFOST_RFE_VALUE_EMPTY << SPI_FIFOST_RFE_SHIFT)
#define SPI_FIFOST_RFF_SHIFT 1
#define SPI_FIFOST_RFF_WIDTH 1
#define SPI_FIFOST_RFF_MASK (((1U << SPI_FIFOST_RFF_WIDTH) - 1U) << SPI_FIFOST_RFF_SHIFT)
#define SPI_FIFOST_RFF_VALUE_NOT_FULL 0U
#define SPI_FIFOST_RFF_BITS_NOT_FULL (SPI_FIFOST_RFF_VALUE_NOT_FULL << SPI_FIFOST_RFF_SHIFT)
#define SPI_FIFOST_RFF_VALUE_FULL 1U
#define SPI_FIFOST_RFF_BITS_FULL (SPI_FIFOST_RFF_VALUE_FULL << SPI_FIFOST_RFF_SHIFT)
#define SPI_FIFOST_RFHF_SHIFT 2
#define SPI_FIFOST_RFHF_WIDTH 1
#define SPI_FIFOST_RFHF_MASK (((1U << SPI_FIFOST_RFHF_WIDTH) - 1U) << SPI_FIFOST_RFHF_SHIFT)
#define SPI_FIFOST_RFHF_VALUE_NOT_HALF_FULL 0U
#define SPI_FIFOST_RFHF_BITS_NOT_HALF_FULL (SPI_FIFOST_RFHF_VALUE_NOT_HALF_FULL << SPI_FIFOST_RFHF_SHIFT)
#define SPI_FIFOST_RFHF_VALUE_HALF_FULL 1U
#define SPI_FIFOST_RFHF_BITS_HALF_FULL (SPI_FIFOST_RFHF_VALUE_HALF_FULL << SPI_FIFOST_RFHF_SHIFT)
#define SPI_FIFOST_TFE_SHIFT 3
#define SPI_FIFOST_TFE_WIDTH 1
#define SPI_FIFOST_TFE_MASK (((1U << SPI_FIFOST_TFE_WIDTH) - 1U) << SPI_FIFOST_TFE_SHIFT)
#define SPI_FIFOST_TFE_VALUE_NOT_EMPTY 0U
#define SPI_FIFOST_TFE_BITS_NOT_EMPTY (SPI_FIFOST_TFE_VALUE_NOT_EMPTY << SPI_FIFOST_TFE_SHIFT)
#define SPI_FIFOST_TFE_VALUE_EMPTY 1U
#define SPI_FIFOST_TFE_BITS_EMPTY (SPI_FIFOST_TFE_VALUE_EMPTY << SPI_FIFOST_TFE_SHIFT)
#define SPI_FIFOST_TFF_SHIFT 4
#define SPI_FIFOST_TFF_WIDTH 1
#define SPI_FIFOST_TFF_MASK (((1U << SPI_FIFOST_TFF_WIDTH) - 1U) << SPI_FIFOST_TFF_SHIFT)
#define SPI_FIFOST_TFF_VALUE_NOT_FULL 0U
#define SPI_FIFOST_TFF_BITS_NOT_FULL (SPI_FIFOST_TFF_VALUE_NOT_FULL << SPI_FIFOST_TFF_SHIFT)
#define SPI_FIFOST_TFF_VALUE_FULL 1U
#define SPI_FIFOST_TFF_BITS_FULL (SPI_FIFOST_TFF_VALUE_FULL << SPI_FIFOST_TFF_SHIFT)
#define SPI_FIFOST_TFHF_SHIFT 5
#define SPI_FIFOST_TFHF_WIDTH 1
#define SPI_FIFOST_TFHF_MASK (((1U << SPI_FIFOST_TFHF_WIDTH) - 1U) << SPI_FIFOST_TFHF_SHIFT)
#define SPI_FIFOST_TFHF_VALUE_NOT_HALF_FULL 0U
#define SPI_FIFOST_TFHF_BITS_NOT_HALF_FULL (SPI_FIFOST_TFHF_VALUE_NOT_HALF_FULL << SPI_FIFOST_TFHF_SHIFT)
#define SPI_FIFOST_TFHF_VALUE_HALF_FULL 1U
#define SPI_FIFOST_TFHF_BITS_HALF_FULL (SPI_FIFOST_TFHF_VALUE_HALF_FULL << SPI_FIFOST_TFHF_SHIFT)
#define SPI_FIFOST_RF_LEVEL_SHIFT 6
#define SPI_FIFOST_RF_LEVEL_WIDTH 3
#define SPI_FIFOST_RF_LEVEL_MASK (((1U << SPI_FIFOST_RF_LEVEL_WIDTH) - 1U) << SPI_FIFOST_RF_LEVEL_SHIFT)
#define SPI_FIFOST_RF_LEVEL_VALUE_0_BYTE 0U
#define SPI_FIFOST_RF_LEVEL_BITS_0_BYTE (SPI_FIFOST_RF_LEVEL_VALUE_0_BYTE << SPI_FIFOST_RF_LEVEL_SHIFT)
#define SPI_FIFOST_RF_LEVEL_VALUE_1_BYTE 1U
#define SPI_FIFOST_RF_LEVEL_BITS_1_BYTE (SPI_FIFOST_RF_LEVEL_VALUE_1_BYTE << SPI_FIFOST_RF_LEVEL_SHIFT)
#define SPI_FIFOST_RF_LEVEL_VALUE_2_BYTE 2U
#define SPI_FIFOST_RF_LEVEL_BITS_2_BYTE (SPI_FIFOST_RF_LEVEL_VALUE_2_BYTE << SPI_FIFOST_RF_LEVEL_SHIFT)
#define SPI_FIFOST_RF_LEVEL_VALUE_3_BYTE 3U
#define SPI_FIFOST_RF_LEVEL_BITS_3_BYTE (SPI_FIFOST_RF_LEVEL_VALUE_3_BYTE << SPI_FIFOST_RF_LEVEL_SHIFT)
#define SPI_FIFOST_RF_LEVEL_VALUE_4_BYTE 4U
#define SPI_FIFOST_RF_LEVEL_BITS_4_BYTE (SPI_FIFOST_RF_LEVEL_VALUE_4_BYTE << SPI_FIFOST_RF_LEVEL_SHIFT)
#define SPI_FIFOST_RF_LEVEL_VALUE_5_BYTE 5U
#define SPI_FIFOST_RF_LEVEL_BITS_5_BYTE (SPI_FIFOST_RF_LEVEL_VALUE_5_BYTE << SPI_FIFOST_RF_LEVEL_SHIFT)
#define SPI_FIFOST_RF_LEVEL_VALUE_6_BYTE 6U
#define SPI_FIFOST_RF_LEVEL_BITS_6_BYTE (SPI_FIFOST_RF_LEVEL_VALUE_6_BYTE << SPI_FIFOST_RF_LEVEL_SHIFT)
#define SPI_FIFOST_RF_LEVEL_VALUE_7_BYTE 7U
#define SPI_FIFOST_RF_LEVEL_BITS_7_BYTE (SPI_FIFOST_RF_LEVEL_VALUE_7_BYTE << SPI_FIFOST_RF_LEVEL_SHIFT)
#define SPI_FIFOST_TF_LEVEL_SHIFT 9
#define SPI_FIFOST_TF_LEVEL_WIDTH 3
#define SPI_FIFOST_TF_LEVEL_MASK (((1U << SPI_FIFOST_TF_LEVEL_WIDTH) - 1U) << SPI_FIFOST_TF_LEVEL_SHIFT)
#define SPI_FIFOST_TF_LEVEL_VALUE_0_BYTE 0U
#define SPI_FIFOST_TF_LEVEL_BITS_0_BYTE (SPI_FIFOST_TF_LEVEL_VALUE_0_BYTE << SPI_FIFOST_TF_LEVEL_SHIFT)
#define SPI_FIFOST_TF_LEVEL_VALUE_1_BYTE 1U
#define SPI_FIFOST_TF_LEVEL_BITS_1_BYTE (SPI_FIFOST_TF_LEVEL_VALUE_1_BYTE << SPI_FIFOST_TF_LEVEL_SHIFT)
#define SPI_FIFOST_TF_LEVEL_VALUE_2_BYTE 2U
#define SPI_FIFOST_TF_LEVEL_BITS_2_BYTE (SPI_FIFOST_TF_LEVEL_VALUE_2_BYTE << SPI_FIFOST_TF_LEVEL_SHIFT)
#define SPI_FIFOST_TF_LEVEL_VALUE_3_BYTE 3U
#define SPI_FIFOST_TF_LEVEL_BITS_3_BYTE (SPI_FIFOST_TF_LEVEL_VALUE_3_BYTE << SPI_FIFOST_TF_LEVEL_SHIFT)
#define SPI_FIFOST_TF_LEVEL_VALUE_4_BYTE 4U
#define SPI_FIFOST_TF_LEVEL_BITS_4_BYTE (SPI_FIFOST_TF_LEVEL_VALUE_4_BYTE << SPI_FIFOST_TF_LEVEL_SHIFT)
#define SPI_FIFOST_TF_LEVEL_VALUE_5_BYTE 5U
#define SPI_FIFOST_TF_LEVEL_BITS_5_BYTE (SPI_FIFOST_TF_LEVEL_VALUE_5_BYTE << SPI_FIFOST_TF_LEVEL_SHIFT)
#define SPI_FIFOST_TF_LEVEL_VALUE_6_BYTE 6U
#define SPI_FIFOST_TF_LEVEL_BITS_6_BYTE (SPI_FIFOST_TF_LEVEL_VALUE_6_BYTE << SPI_FIFOST_TF_LEVEL_SHIFT)
#define SPI_FIFOST_TF_LEVEL_VALUE_7_BYTE 7U
#define SPI_FIFOST_TF_LEVEL_BITS_7_BYTE (SPI_FIFOST_TF_LEVEL_VALUE_7_BYTE << SPI_FIFOST_TF_LEVEL_SHIFT)
#endif

348
bsp/dp32g030/syscon.h Normal file
View File

@@ -0,0 +1,348 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef HARDWARE_DP32G030_SYSCON_H
#define HARDWARE_DP32G030_SYSCON_H
#if !defined(__ASSEMBLY__)
#include <stdint.h>
#endif
/* -------- SYSCON -------- */
#define SYSCON_BASE_ADDR 0x40000000U
#define SYSCON_BASE_SIZE 0x00000800U
#define SYSCON_CLK_SEL_ADDR (SYSCON_BASE_ADDR + 0x0000U)
#define SYSCON_CLK_SEL (*(volatile uint32_t *)SYSCON_CLK_SEL_ADDR)
#define SYSCON_CLK_SEL_SYS_SHIFT 0
#define SYSCON_CLK_SEL_SYS_WIDTH 1
#define SYSCON_CLK_SEL_SYS_MASK (((1U << SYSCON_CLK_SEL_SYS_WIDTH) - 1U) << SYSCON_CLK_SEL_SYS_SHIFT)
#define SYSCON_CLK_SEL_SYS_VALUE_RCHF 0U
#define SYSCON_CLK_SEL_SYS_BITS_RCHF (SYSCON_CLK_SEL_SYS_VALUE_RCHF << SYSCON_CLK_SEL_SYS_SHIFT)
#define SYSCON_CLK_SEL_SYS_VALUE_DIV_CLK 1U
#define SYSCON_CLK_SEL_SYS_BITS_DIV_CLK (SYSCON_CLK_SEL_SYS_VALUE_DIV_CLK << SYSCON_CLK_SEL_SYS_SHIFT)
#define SYSCON_CLK_SEL_DIV_SHIFT 1
#define SYSCON_CLK_SEL_DIV_WIDTH 3
#define SYSCON_CLK_SEL_DIV_MASK (((1U << SYSCON_CLK_SEL_DIV_WIDTH) - 1U) << SYSCON_CLK_SEL_DIV_SHIFT)
#define SYSCON_CLK_SEL_DIV_VALUE_1 0U
#define SYSCON_CLK_SEL_DIV_BITS_1 (SYSCON_CLK_SEL_DIV_VALUE_1 << SYSCON_CLK_SEL_DIV_SHIFT)
#define SYSCON_CLK_SEL_DIV_VALUE_2 1U
#define SYSCON_CLK_SEL_DIV_BITS_2 (SYSCON_CLK_SEL_DIV_VALUE_2 << SYSCON_CLK_SEL_DIV_SHIFT)
#define SYSCON_CLK_SEL_DIV_VALUE_4 2U
#define SYSCON_CLK_SEL_DIV_BITS_4 (SYSCON_CLK_SEL_DIV_VALUE_4 << SYSCON_CLK_SEL_DIV_SHIFT)
#define SYSCON_CLK_SEL_DIV_VALUE_8 3U
#define SYSCON_CLK_SEL_DIV_BITS_8 (SYSCON_CLK_SEL_DIV_VALUE_8 << SYSCON_CLK_SEL_DIV_SHIFT)
#define SYSCON_CLK_SEL_DIV_VALUE_16 4U
#define SYSCON_CLK_SEL_DIV_BITS_16 (SYSCON_CLK_SEL_DIV_VALUE_16 << SYSCON_CLK_SEL_DIV_SHIFT)
#define SYSCON_CLK_SEL_DIV_VALUE_32 5U
#define SYSCON_CLK_SEL_DIV_BITS_32 (SYSCON_CLK_SEL_DIV_VALUE_32 << SYSCON_CLK_SEL_DIV_SHIFT)
#define SYSCON_CLK_SEL_SRC_SHIFT 4
#define SYSCON_CLK_SEL_SRC_WIDTH 3
#define SYSCON_CLK_SEL_SRC_MASK (((1U << SYSCON_CLK_SEL_SRC_WIDTH) - 1U) << SYSCON_CLK_SEL_SRC_SHIFT)
#define SYSCON_CLK_SEL_SRC_VALUE_RCHF 0U
#define SYSCON_CLK_SEL_SRC_BITS_RCHF (SYSCON_CLK_SEL_SRC_VALUE_RCHF << SYSCON_CLK_SEL_SRC_SHIFT)
#define SYSCON_CLK_SEL_SRC_VALUE_RCLF 1U
#define SYSCON_CLK_SEL_SRC_BITS_RCLF (SYSCON_CLK_SEL_SRC_VALUE_RCLF << SYSCON_CLK_SEL_SRC_SHIFT)
#define SYSCON_CLK_SEL_SRC_VALUE_XTAH 2U
#define SYSCON_CLK_SEL_SRC_BITS_XTAH (SYSCON_CLK_SEL_SRC_VALUE_XTAH << SYSCON_CLK_SEL_SRC_SHIFT)
#define SYSCON_CLK_SEL_SRC_VALUE_XTAL 3U
#define SYSCON_CLK_SEL_SRC_BITS_XTAL (SYSCON_CLK_SEL_SRC_VALUE_XTAL << SYSCON_CLK_SEL_SRC_SHIFT)
#define SYSCON_CLK_SEL_SRC_VALUE_PLL 4U
#define SYSCON_CLK_SEL_SRC_BITS_PLL (SYSCON_CLK_SEL_SRC_VALUE_PLL << SYSCON_CLK_SEL_SRC_SHIFT)
#define SYSCON_CLK_SEL_W_PLL_SHIFT 7
#define SYSCON_CLK_SEL_W_PLL_WIDTH 1
#define SYSCON_CLK_SEL_W_PLL_MASK (((1U << SYSCON_CLK_SEL_W_PLL_WIDTH) - 1U) << SYSCON_CLK_SEL_W_PLL_SHIFT)
#define SYSCON_CLK_SEL_W_PLL_VALUE_RCHF 0U
#define SYSCON_CLK_SEL_W_PLL_BITS_RCHF (SYSCON_CLK_SEL_W_PLL_VALUE_RCHF << SYSCON_CLK_SEL_W_PLL_SHIFT)
#define SYSCON_CLK_SEL_W_PLL_VALUE_XTAH 1U
#define SYSCON_CLK_SEL_W_PLL_BITS_XTAH (SYSCON_CLK_SEL_W_PLL_VALUE_XTAH << SYSCON_CLK_SEL_W_PLL_SHIFT)
#define SYSCON_CLK_SEL_R_SARADC_SMPL_SHIFT 9
#define SYSCON_CLK_SEL_R_SARADC_SMPL_WIDTH 2
#define SYSCON_CLK_SEL_R_SARADC_SMPL_MASK (((1U << SYSCON_CLK_SEL_R_SARADC_SMPL_WIDTH) - 1U) << SYSCON_CLK_SEL_R_SARADC_SMPL_SHIFT)
#define SYSCON_CLK_SEL_R_SARADC_SMPL_VALUE_DIV1 0U
#define SYSCON_CLK_SEL_R_SARADC_SMPL_BITS_DIV1 (SYSCON_CLK_SEL_R_SARADC_SMPL_VALUE_DIV1 << SYSCON_CLK_SEL_R_SARADC_SMPL_SHIFT)
#define SYSCON_CLK_SEL_R_SARADC_SMPL_VALUE_DIV2 1U
#define SYSCON_CLK_SEL_R_SARADC_SMPL_BITS_DIV2 (SYSCON_CLK_SEL_R_SARADC_SMPL_VALUE_DIV2 << SYSCON_CLK_SEL_R_SARADC_SMPL_SHIFT)
#define SYSCON_CLK_SEL_R_SARADC_SMPL_VALUE_DIV4 2U
#define SYSCON_CLK_SEL_R_SARADC_SMPL_BITS_DIV4 (SYSCON_CLK_SEL_R_SARADC_SMPL_VALUE_DIV4 << SYSCON_CLK_SEL_R_SARADC_SMPL_SHIFT)
#define SYSCON_CLK_SEL_R_SARADC_SMPL_VALUE_DIV8 3U
#define SYSCON_CLK_SEL_R_SARADC_SMPL_BITS_DIV8 (SYSCON_CLK_SEL_R_SARADC_SMPL_VALUE_DIV8 << SYSCON_CLK_SEL_R_SARADC_SMPL_SHIFT)
#define SYSCON_CLK_SEL_W_SARADC_SMPL_SHIFT 10
#define SYSCON_CLK_SEL_W_SARADC_SMPL_WIDTH 2
#define SYSCON_CLK_SEL_W_SARADC_SMPL_MASK (((1U << SYSCON_CLK_SEL_W_SARADC_SMPL_WIDTH) - 1U) << SYSCON_CLK_SEL_W_SARADC_SMPL_SHIFT)
#define SYSCON_CLK_SEL_W_SARADC_SMPL_VALUE_DIV1 0U
#define SYSCON_CLK_SEL_W_SARADC_SMPL_BITS_DIV1 (SYSCON_CLK_SEL_W_SARADC_SMPL_VALUE_DIV1 << SYSCON_CLK_SEL_W_SARADC_SMPL_SHIFT)
#define SYSCON_CLK_SEL_W_SARADC_SMPL_VALUE_DIV2 1U
#define SYSCON_CLK_SEL_W_SARADC_SMPL_BITS_DIV2 (SYSCON_CLK_SEL_W_SARADC_SMPL_VALUE_DIV2 << SYSCON_CLK_SEL_W_SARADC_SMPL_SHIFT)
#define SYSCON_CLK_SEL_W_SARADC_SMPL_VALUE_DIV4 2U
#define SYSCON_CLK_SEL_W_SARADC_SMPL_BITS_DIV4 (SYSCON_CLK_SEL_W_SARADC_SMPL_VALUE_DIV4 << SYSCON_CLK_SEL_W_SARADC_SMPL_SHIFT)
#define SYSCON_CLK_SEL_W_SARADC_SMPL_VALUE_DIV8 3U
#define SYSCON_CLK_SEL_W_SARADC_SMPL_BITS_DIV8 (SYSCON_CLK_SEL_W_SARADC_SMPL_VALUE_DIV8 << SYSCON_CLK_SEL_W_SARADC_SMPL_SHIFT)
#define SYSCON_CLK_SEL_R_PLL_SHIFT 11
#define SYSCON_CLK_SEL_R_PLL_WIDTH 1
#define SYSCON_CLK_SEL_R_PLL_MASK (((1U << SYSCON_CLK_SEL_R_PLL_WIDTH) - 1U) << SYSCON_CLK_SEL_R_PLL_SHIFT)
#define SYSCON_CLK_SEL_R_PLL_VALUE_RCHF 0U
#define SYSCON_CLK_SEL_R_PLL_BITS_RCHF (SYSCON_CLK_SEL_R_PLL_VALUE_RCHF << SYSCON_CLK_SEL_R_PLL_SHIFT)
#define SYSCON_CLK_SEL_R_PLL_VALUE_XTAH 1U
#define SYSCON_CLK_SEL_R_PLL_BITS_XTAH (SYSCON_CLK_SEL_R_PLL_VALUE_XTAH << SYSCON_CLK_SEL_R_PLL_SHIFT)
#define SYSCON_DIV_CLK_GATE_ADDR (SYSCON_BASE_ADDR + 0x0004U)
#define SYSCON_DIV_CLK_GATE (*(volatile uint32_t *)SYSCON_DIV_CLK_GATE_ADDR)
#define SYSCON_DIV_CLK_GATE_DIV_CLK_GATE_SHIFT 0
#define SYSCON_DIV_CLK_GATE_DIV_CLK_GATE_WIDTH 1
#define SYSCON_DIV_CLK_GATE_DIV_CLK_GATE_MASK (((1U << SYSCON_DIV_CLK_GATE_DIV_CLK_GATE_WIDTH) - 1U) << SYSCON_DIV_CLK_GATE_DIV_CLK_GATE_SHIFT)
#define SYSCON_DIV_CLK_GATE_DIV_CLK_GATE_VALUE_DISABLE 0U
#define SYSCON_DIV_CLK_GATE_DIV_CLK_GATE_BITS_DISABLE (SYSCON_DIV_CLK_GATE_DIV_CLK_GATE_VALUE_DISABLE << SYSCON_DIV_CLK_GATE_DIV_CLK_GATE_SHIFT)
#define SYSCON_DIV_CLK_GATE_DIV_CLK_GATE_VALUE_ENABLE 1U
#define SYSCON_DIV_CLK_GATE_DIV_CLK_GATE_BITS_ENABLE (SYSCON_DIV_CLK_GATE_DIV_CLK_GATE_VALUE_ENABLE << SYSCON_DIV_CLK_GATE_DIV_CLK_GATE_SHIFT)
#define SYSCON_DEV_CLK_GATE_ADDR (SYSCON_BASE_ADDR + 0x0008U)
#define SYSCON_DEV_CLK_GATE (*(volatile uint32_t *)SYSCON_DEV_CLK_GATE_ADDR)
#define SYSCON_DEV_CLK_GATE_GPIOA_SHIFT 0
#define SYSCON_DEV_CLK_GATE_GPIOA_WIDTH 1
#define SYSCON_DEV_CLK_GATE_GPIOA_MASK (((1U << SYSCON_DEV_CLK_GATE_GPIOA_WIDTH) - 1U) << SYSCON_DEV_CLK_GATE_GPIOA_SHIFT)
#define SYSCON_DEV_CLK_GATE_GPIOA_VALUE_DISABLE 0U
#define SYSCON_DEV_CLK_GATE_GPIOA_BITS_DISABLE (SYSCON_DEV_CLK_GATE_GPIOA_VALUE_DISABLE << SYSCON_DEV_CLK_GATE_GPIOA_SHIFT)
#define SYSCON_DEV_CLK_GATE_GPIOA_VALUE_ENABLE 1U
#define SYSCON_DEV_CLK_GATE_GPIOA_BITS_ENABLE (SYSCON_DEV_CLK_GATE_GPIOA_VALUE_ENABLE << SYSCON_DEV_CLK_GATE_GPIOA_SHIFT)
#define SYSCON_DEV_CLK_GATE_GPIOB_SHIFT 1
#define SYSCON_DEV_CLK_GATE_GPIOB_WIDTH 1
#define SYSCON_DEV_CLK_GATE_GPIOB_MASK (((1U << SYSCON_DEV_CLK_GATE_GPIOB_WIDTH) - 1U) << SYSCON_DEV_CLK_GATE_GPIOB_SHIFT)
#define SYSCON_DEV_CLK_GATE_GPIOB_VALUE_DISABLE 0U
#define SYSCON_DEV_CLK_GATE_GPIOB_BITS_DISABLE (SYSCON_DEV_CLK_GATE_GPIOB_VALUE_DISABLE << SYSCON_DEV_CLK_GATE_GPIOB_SHIFT)
#define SYSCON_DEV_CLK_GATE_GPIOB_VALUE_ENABLE 1U
#define SYSCON_DEV_CLK_GATE_GPIOB_BITS_ENABLE (SYSCON_DEV_CLK_GATE_GPIOB_VALUE_ENABLE << SYSCON_DEV_CLK_GATE_GPIOB_SHIFT)
#define SYSCON_DEV_CLK_GATE_GPIOC_SHIFT 2
#define SYSCON_DEV_CLK_GATE_GPIOC_WIDTH 1
#define SYSCON_DEV_CLK_GATE_GPIOC_MASK (((1U << SYSCON_DEV_CLK_GATE_GPIOC_WIDTH) - 1U) << SYSCON_DEV_CLK_GATE_GPIOC_SHIFT)
#define SYSCON_DEV_CLK_GATE_GPIOC_VALUE_DISABLE 0U
#define SYSCON_DEV_CLK_GATE_GPIOC_BITS_DISABLE (SYSCON_DEV_CLK_GATE_GPIOC_VALUE_DISABLE << SYSCON_DEV_CLK_GATE_GPIOC_SHIFT)
#define SYSCON_DEV_CLK_GATE_GPIOC_VALUE_ENABLE 1U
#define SYSCON_DEV_CLK_GATE_GPIOC_BITS_ENABLE (SYSCON_DEV_CLK_GATE_GPIOC_VALUE_ENABLE << SYSCON_DEV_CLK_GATE_GPIOC_SHIFT)
#define SYSCON_DEV_CLK_GATE_IIC0_SHIFT 4
#define SYSCON_DEV_CLK_GATE_IIC0_WIDTH 1
#define SYSCON_DEV_CLK_GATE_IIC0_MASK (((1U << SYSCON_DEV_CLK_GATE_IIC0_WIDTH) - 1U) << SYSCON_DEV_CLK_GATE_IIC0_SHIFT)
#define SYSCON_DEV_CLK_GATE_IIC0_VALUE_DISABLE 0U
#define SYSCON_DEV_CLK_GATE_IIC0_BITS_DISABLE (SYSCON_DEV_CLK_GATE_IIC0_VALUE_DISABLE << SYSCON_DEV_CLK_GATE_IIC0_SHIFT)
#define SYSCON_DEV_CLK_GATE_IIC0_VALUE_ENABLE 1U
#define SYSCON_DEV_CLK_GATE_IIC0_BITS_ENABLE (SYSCON_DEV_CLK_GATE_IIC0_VALUE_ENABLE << SYSCON_DEV_CLK_GATE_IIC0_SHIFT)
#define SYSCON_DEV_CLK_GATE_IIC1_SHIFT 5
#define SYSCON_DEV_CLK_GATE_IIC1_WIDTH 1
#define SYSCON_DEV_CLK_GATE_IIC1_MASK (((1U << SYSCON_DEV_CLK_GATE_IIC1_WIDTH) - 1U) << SYSCON_DEV_CLK_GATE_IIC1_SHIFT)
#define SYSCON_DEV_CLK_GATE_IIC1_VALUE_DISABLE 0U
#define SYSCON_DEV_CLK_GATE_IIC1_BITS_DISABLE (SYSCON_DEV_CLK_GATE_IIC1_VALUE_DISABLE << SYSCON_DEV_CLK_GATE_IIC1_SHIFT)
#define SYSCON_DEV_CLK_GATE_IIC1_VALUE_ENABLE 1U
#define SYSCON_DEV_CLK_GATE_IIC1_BITS_ENABLE (SYSCON_DEV_CLK_GATE_IIC1_VALUE_ENABLE << SYSCON_DEV_CLK_GATE_IIC1_SHIFT)
#define SYSCON_DEV_CLK_GATE_UART0_SHIFT 6
#define SYSCON_DEV_CLK_GATE_UART0_WIDTH 1
#define SYSCON_DEV_CLK_GATE_UART0_MASK (((1U << SYSCON_DEV_CLK_GATE_UART0_WIDTH) - 1U) << SYSCON_DEV_CLK_GATE_UART0_SHIFT)
#define SYSCON_DEV_CLK_GATE_UART0_VALUE_DISABLE 0U
#define SYSCON_DEV_CLK_GATE_UART0_BITS_DISABLE (SYSCON_DEV_CLK_GATE_UART0_VALUE_DISABLE << SYSCON_DEV_CLK_GATE_UART0_SHIFT)
#define SYSCON_DEV_CLK_GATE_UART0_VALUE_ENABLE 1U
#define SYSCON_DEV_CLK_GATE_UART0_BITS_ENABLE (SYSCON_DEV_CLK_GATE_UART0_VALUE_ENABLE << SYSCON_DEV_CLK_GATE_UART0_SHIFT)
#define SYSCON_DEV_CLK_GATE_UART1_SHIFT 7
#define SYSCON_DEV_CLK_GATE_UART1_WIDTH 1
#define SYSCON_DEV_CLK_GATE_UART1_MASK (((1U << SYSCON_DEV_CLK_GATE_UART1_WIDTH) - 1U) << SYSCON_DEV_CLK_GATE_UART1_SHIFT)
#define SYSCON_DEV_CLK_GATE_UART1_VALUE_DISABLE 0U
#define SYSCON_DEV_CLK_GATE_UART1_BITS_DISABLE (SYSCON_DEV_CLK_GATE_UART1_VALUE_DISABLE << SYSCON_DEV_CLK_GATE_UART1_SHIFT)
#define SYSCON_DEV_CLK_GATE_UART1_VALUE_ENABLE 1U
#define SYSCON_DEV_CLK_GATE_UART1_BITS_ENABLE (SYSCON_DEV_CLK_GATE_UART1_VALUE_ENABLE << SYSCON_DEV_CLK_GATE_UART1_SHIFT)
#define SYSCON_DEV_CLK_GATE_UART2_SHIFT 8
#define SYSCON_DEV_CLK_GATE_UART2_WIDTH 1
#define SYSCON_DEV_CLK_GATE_UART2_MASK (((1U << SYSCON_DEV_CLK_GATE_UART2_WIDTH) - 1U) << SYSCON_DEV_CLK_GATE_UART2_SHIFT)
#define SYSCON_DEV_CLK_GATE_UART2_VALUE_DISABLE 0U
#define SYSCON_DEV_CLK_GATE_UART2_BITS_DISABLE (SYSCON_DEV_CLK_GATE_UART2_VALUE_DISABLE << SYSCON_DEV_CLK_GATE_UART2_SHIFT)
#define SYSCON_DEV_CLK_GATE_UART2_VALUE_ENABLE 1U
#define SYSCON_DEV_CLK_GATE_UART2_BITS_ENABLE (SYSCON_DEV_CLK_GATE_UART2_VALUE_ENABLE << SYSCON_DEV_CLK_GATE_UART2_SHIFT)
#define SYSCON_DEV_CLK_GATE_SPI0_SHIFT 10
#define SYSCON_DEV_CLK_GATE_SPI0_WIDTH 1
#define SYSCON_DEV_CLK_GATE_SPI0_MASK (((1U << SYSCON_DEV_CLK_GATE_SPI0_WIDTH) - 1U) << SYSCON_DEV_CLK_GATE_SPI0_SHIFT)
#define SYSCON_DEV_CLK_GATE_SPI0_VALUE_DISABLE 0U
#define SYSCON_DEV_CLK_GATE_SPI0_BITS_DISABLE (SYSCON_DEV_CLK_GATE_SPI0_VALUE_DISABLE << SYSCON_DEV_CLK_GATE_SPI0_SHIFT)
#define SYSCON_DEV_CLK_GATE_SPI0_VALUE_ENABLE 1U
#define SYSCON_DEV_CLK_GATE_SPI0_BITS_ENABLE (SYSCON_DEV_CLK_GATE_SPI0_VALUE_ENABLE << SYSCON_DEV_CLK_GATE_SPI0_SHIFT)
#define SYSCON_DEV_CLK_GATE_SPI1_SHIFT 11
#define SYSCON_DEV_CLK_GATE_SPI1_WIDTH 1
#define SYSCON_DEV_CLK_GATE_SPI1_MASK (((1U << SYSCON_DEV_CLK_GATE_SPI1_WIDTH) - 1U) << SYSCON_DEV_CLK_GATE_SPI1_SHIFT)
#define SYSCON_DEV_CLK_GATE_SPI1_VALUE_DISABLE 0U
#define SYSCON_DEV_CLK_GATE_SPI1_BITS_DISABLE (SYSCON_DEV_CLK_GATE_SPI1_VALUE_DISABLE << SYSCON_DEV_CLK_GATE_SPI1_SHIFT)
#define SYSCON_DEV_CLK_GATE_SPI1_VALUE_ENABLE 1U
#define SYSCON_DEV_CLK_GATE_SPI1_BITS_ENABLE (SYSCON_DEV_CLK_GATE_SPI1_VALUE_ENABLE << SYSCON_DEV_CLK_GATE_SPI1_SHIFT)
#define SYSCON_DEV_CLK_GATE_TIMER_BASE0_SHIFT 12
#define SYSCON_DEV_CLK_GATE_TIMER_BASE0_WIDTH 1
#define SYSCON_DEV_CLK_GATE_TIMER_BASE0_MASK (((1U << SYSCON_DEV_CLK_GATE_TIMER_BASE0_WIDTH) - 1U) << SYSCON_DEV_CLK_GATE_TIMER_BASE0_SHIFT)
#define SYSCON_DEV_CLK_GATE_TIMER_BASE0_VALUE_DISABLE 0U
#define SYSCON_DEV_CLK_GATE_TIMER_BASE0_BITS_DISABLE (SYSCON_DEV_CLK_GATE_TIMER_BASE0_VALUE_DISABLE << SYSCON_DEV_CLK_GATE_TIMER_BASE0_SHIFT)
#define SYSCON_DEV_CLK_GATE_TIMER_BASE0_VALUE_ENABLE 1U
#define SYSCON_DEV_CLK_GATE_TIMER_BASE0_BITS_ENABLE (SYSCON_DEV_CLK_GATE_TIMER_BASE0_VALUE_ENABLE << SYSCON_DEV_CLK_GATE_TIMER_BASE0_SHIFT)
#define SYSCON_DEV_CLK_GATE_TIMER_BASE1_SHIFT 13
#define SYSCON_DEV_CLK_GATE_TIMER_BASE1_WIDTH 1
#define SYSCON_DEV_CLK_GATE_TIMER_BASE1_MASK (((1U << SYSCON_DEV_CLK_GATE_TIMER_BASE1_WIDTH) - 1U) << SYSCON_DEV_CLK_GATE_TIMER_BASE1_SHIFT)
#define SYSCON_DEV_CLK_GATE_TIMER_BASE1_VALUE_DISABLE 0U
#define SYSCON_DEV_CLK_GATE_TIMER_BASE1_BITS_DISABLE (SYSCON_DEV_CLK_GATE_TIMER_BASE1_VALUE_DISABLE << SYSCON_DEV_CLK_GATE_TIMER_BASE1_SHIFT)
#define SYSCON_DEV_CLK_GATE_TIMER_BASE1_VALUE_ENABLE 1U
#define SYSCON_DEV_CLK_GATE_TIMER_BASE1_BITS_ENABLE (SYSCON_DEV_CLK_GATE_TIMER_BASE1_VALUE_ENABLE << SYSCON_DEV_CLK_GATE_TIMER_BASE1_SHIFT)
#define SYSCON_DEV_CLK_GATE_TIMER_BASE2_SHIFT 14
#define SYSCON_DEV_CLK_GATE_TIMER_BASE2_WIDTH 1
#define SYSCON_DEV_CLK_GATE_TIMER_BASE2_MASK (((1U << SYSCON_DEV_CLK_GATE_TIMER_BASE2_WIDTH) - 1U) << SYSCON_DEV_CLK_GATE_TIMER_BASE2_SHIFT)
#define SYSCON_DEV_CLK_GATE_TIMER_BASE2_VALUE_DISABLE 0U
#define SYSCON_DEV_CLK_GATE_TIMER_BASE2_BITS_DISABLE (SYSCON_DEV_CLK_GATE_TIMER_BASE2_VALUE_DISABLE << SYSCON_DEV_CLK_GATE_TIMER_BASE2_SHIFT)
#define SYSCON_DEV_CLK_GATE_TIMER_BASE2_VALUE_ENABLE 1U
#define SYSCON_DEV_CLK_GATE_TIMER_BASE2_BITS_ENABLE (SYSCON_DEV_CLK_GATE_TIMER_BASE2_VALUE_ENABLE << SYSCON_DEV_CLK_GATE_TIMER_BASE2_SHIFT)
#define SYSCON_DEV_CLK_GATE_TIMER_PLUS0_SHIFT 15
#define SYSCON_DEV_CLK_GATE_TIMER_PLUS0_WIDTH 1
#define SYSCON_DEV_CLK_GATE_TIMER_PLUS0_MASK (((1U << SYSCON_DEV_CLK_GATE_TIMER_PLUS0_WIDTH) - 1U) << SYSCON_DEV_CLK_GATE_TIMER_PLUS0_SHIFT)
#define SYSCON_DEV_CLK_GATE_TIMER_PLUS0_VALUE_DISABLE 0U
#define SYSCON_DEV_CLK_GATE_TIMER_PLUS0_BITS_DISABLE (SYSCON_DEV_CLK_GATE_TIMER_PLUS0_VALUE_DISABLE << SYSCON_DEV_CLK_GATE_TIMER_PLUS0_SHIFT)
#define SYSCON_DEV_CLK_GATE_TIMER_PLUS0_VALUE_ENABLE 1U
#define SYSCON_DEV_CLK_GATE_TIMER_PLUS0_BITS_ENABLE (SYSCON_DEV_CLK_GATE_TIMER_PLUS0_VALUE_ENABLE << SYSCON_DEV_CLK_GATE_TIMER_PLUS0_SHIFT)
#define SYSCON_DEV_CLK_GATE_TIMER_PLUS1_SHIFT 16
#define SYSCON_DEV_CLK_GATE_TIMER_PLUS1_WIDTH 1
#define SYSCON_DEV_CLK_GATE_TIMER_PLUS1_MASK (((1U << SYSCON_DEV_CLK_GATE_TIMER_PLUS1_WIDTH) - 1U) << SYSCON_DEV_CLK_GATE_TIMER_PLUS1_SHIFT)
#define SYSCON_DEV_CLK_GATE_TIMER_PLUS1_VALUE_DISABLE 0U
#define SYSCON_DEV_CLK_GATE_TIMER_PLUS1_BITS_DISABLE (SYSCON_DEV_CLK_GATE_TIMER_PLUS1_VALUE_DISABLE << SYSCON_DEV_CLK_GATE_TIMER_PLUS1_SHIFT)
#define SYSCON_DEV_CLK_GATE_TIMER_PLUS1_VALUE_ENABLE 1U
#define SYSCON_DEV_CLK_GATE_TIMER_PLUS1_BITS_ENABLE (SYSCON_DEV_CLK_GATE_TIMER_PLUS1_VALUE_ENABLE << SYSCON_DEV_CLK_GATE_TIMER_PLUS1_SHIFT)
#define SYSCON_DEV_CLK_GATE_PWM_BASE0_SHIFT 17
#define SYSCON_DEV_CLK_GATE_PWM_BASE0_WIDTH 1
#define SYSCON_DEV_CLK_GATE_PWM_BASE0_MASK (((1U << SYSCON_DEV_CLK_GATE_PWM_BASE0_WIDTH) - 1U) << SYSCON_DEV_CLK_GATE_PWM_BASE0_SHIFT)
#define SYSCON_DEV_CLK_GATE_PWM_BASE0_VALUE_DISABLE 0U
#define SYSCON_DEV_CLK_GATE_PWM_BASE0_BITS_DISABLE (SYSCON_DEV_CLK_GATE_PWM_BASE0_VALUE_DISABLE << SYSCON_DEV_CLK_GATE_PWM_BASE0_SHIFT)
#define SYSCON_DEV_CLK_GATE_PWM_BASE0_VALUE_ENABLE 1U
#define SYSCON_DEV_CLK_GATE_PWM_BASE0_BITS_ENABLE (SYSCON_DEV_CLK_GATE_PWM_BASE0_VALUE_ENABLE << SYSCON_DEV_CLK_GATE_PWM_BASE0_SHIFT)
#define SYSCON_DEV_CLK_GATE_PWM_BASE1_SHIFT 18
#define SYSCON_DEV_CLK_GATE_PWM_BASE1_WIDTH 1
#define SYSCON_DEV_CLK_GATE_PWM_BASE1_MASK (((1U << SYSCON_DEV_CLK_GATE_PWM_BASE1_WIDTH) - 1U) << SYSCON_DEV_CLK_GATE_PWM_BASE1_SHIFT)
#define SYSCON_DEV_CLK_GATE_PWM_BASE1_VALUE_DISABLE 0U
#define SYSCON_DEV_CLK_GATE_PWM_BASE1_BITS_DISABLE (SYSCON_DEV_CLK_GATE_PWM_BASE1_VALUE_DISABLE << SYSCON_DEV_CLK_GATE_PWM_BASE1_SHIFT)
#define SYSCON_DEV_CLK_GATE_PWM_BASE1_VALUE_ENABLE 1U
#define SYSCON_DEV_CLK_GATE_PWM_BASE1_BITS_ENABLE (SYSCON_DEV_CLK_GATE_PWM_BASE1_VALUE_ENABLE << SYSCON_DEV_CLK_GATE_PWM_BASE1_SHIFT)
#define SYSCON_DEV_CLK_GATE_PWM_PLUS0_SHIFT 20
#define SYSCON_DEV_CLK_GATE_PWM_PLUS0_WIDTH 1
#define SYSCON_DEV_CLK_GATE_PWM_PLUS0_MASK (((1U << SYSCON_DEV_CLK_GATE_PWM_PLUS0_WIDTH) - 1U) << SYSCON_DEV_CLK_GATE_PWM_PLUS0_SHIFT)
#define SYSCON_DEV_CLK_GATE_PWM_PLUS0_VALUE_DISABLE 0U
#define SYSCON_DEV_CLK_GATE_PWM_PLUS0_BITS_DISABLE (SYSCON_DEV_CLK_GATE_PWM_PLUS0_VALUE_DISABLE << SYSCON_DEV_CLK_GATE_PWM_PLUS0_SHIFT)
#define SYSCON_DEV_CLK_GATE_PWM_PLUS0_VALUE_ENABLE 1U
#define SYSCON_DEV_CLK_GATE_PWM_PLUS0_BITS_ENABLE (SYSCON_DEV_CLK_GATE_PWM_PLUS0_VALUE_ENABLE << SYSCON_DEV_CLK_GATE_PWM_PLUS0_SHIFT)
#define SYSCON_DEV_CLK_GATE_PWM_PLUS1_SHIFT 21
#define SYSCON_DEV_CLK_GATE_PWM_PLUS1_WIDTH 1
#define SYSCON_DEV_CLK_GATE_PWM_PLUS1_MASK (((1U << SYSCON_DEV_CLK_GATE_PWM_PLUS1_WIDTH) - 1U) << SYSCON_DEV_CLK_GATE_PWM_PLUS1_SHIFT)
#define SYSCON_DEV_CLK_GATE_PWM_PLUS1_VALUE_DISABLE 0U
#define SYSCON_DEV_CLK_GATE_PWM_PLUS1_BITS_DISABLE (SYSCON_DEV_CLK_GATE_PWM_PLUS1_VALUE_DISABLE << SYSCON_DEV_CLK_GATE_PWM_PLUS1_SHIFT)
#define SYSCON_DEV_CLK_GATE_PWM_PLUS1_VALUE_ENABLE 1U
#define SYSCON_DEV_CLK_GATE_PWM_PLUS1_BITS_ENABLE (SYSCON_DEV_CLK_GATE_PWM_PLUS1_VALUE_ENABLE << SYSCON_DEV_CLK_GATE_PWM_PLUS1_SHIFT)
#define SYSCON_DEV_CLK_GATE_RTC_SHIFT 22
#define SYSCON_DEV_CLK_GATE_RTC_WIDTH 1
#define SYSCON_DEV_CLK_GATE_RTC_MASK (((1U << SYSCON_DEV_CLK_GATE_RTC_WIDTH) - 1U) << SYSCON_DEV_CLK_GATE_RTC_SHIFT)
#define SYSCON_DEV_CLK_GATE_RTC_VALUE_DISABLE 0U
#define SYSCON_DEV_CLK_GATE_RTC_BITS_DISABLE (SYSCON_DEV_CLK_GATE_RTC_VALUE_DISABLE << SYSCON_DEV_CLK_GATE_RTC_SHIFT)
#define SYSCON_DEV_CLK_GATE_RTC_VALUE_ENABLE 1U
#define SYSCON_DEV_CLK_GATE_RTC_BITS_ENABLE (SYSCON_DEV_CLK_GATE_RTC_VALUE_ENABLE << SYSCON_DEV_CLK_GATE_RTC_SHIFT)
#define SYSCON_DEV_CLK_GATE_IWDT_SHIFT 23
#define SYSCON_DEV_CLK_GATE_IWDT_WIDTH 1
#define SYSCON_DEV_CLK_GATE_IWDT_MASK (((1U << SYSCON_DEV_CLK_GATE_IWDT_WIDTH) - 1U) << SYSCON_DEV_CLK_GATE_IWDT_SHIFT)
#define SYSCON_DEV_CLK_GATE_IWDT_VALUE_DISABLE 0U
#define SYSCON_DEV_CLK_GATE_IWDT_BITS_DISABLE (SYSCON_DEV_CLK_GATE_IWDT_VALUE_DISABLE << SYSCON_DEV_CLK_GATE_IWDT_SHIFT)
#define SYSCON_DEV_CLK_GATE_IWDT_VALUE_ENABLE 1U
#define SYSCON_DEV_CLK_GATE_IWDT_BITS_ENABLE (SYSCON_DEV_CLK_GATE_IWDT_VALUE_ENABLE << SYSCON_DEV_CLK_GATE_IWDT_SHIFT)
#define SYSCON_DEV_CLK_GATE_WWDT_SHIFT 24
#define SYSCON_DEV_CLK_GATE_WWDT_WIDTH 1
#define SYSCON_DEV_CLK_GATE_WWDT_MASK (((1U << SYSCON_DEV_CLK_GATE_WWDT_WIDTH) - 1U) << SYSCON_DEV_CLK_GATE_WWDT_SHIFT)
#define SYSCON_DEV_CLK_GATE_WWDT_VALUE_DISABLE 0U
#define SYSCON_DEV_CLK_GATE_WWDT_BITS_DISABLE (SYSCON_DEV_CLK_GATE_WWDT_VALUE_DISABLE << SYSCON_DEV_CLK_GATE_WWDT_SHIFT)
#define SYSCON_DEV_CLK_GATE_WWDT_VALUE_ENABLE 1U
#define SYSCON_DEV_CLK_GATE_WWDT_BITS_ENABLE (SYSCON_DEV_CLK_GATE_WWDT_VALUE_ENABLE << SYSCON_DEV_CLK_GATE_WWDT_SHIFT)
#define SYSCON_DEV_CLK_GATE_SARADC_SHIFT 25
#define SYSCON_DEV_CLK_GATE_SARADC_WIDTH 1
#define SYSCON_DEV_CLK_GATE_SARADC_MASK (((1U << SYSCON_DEV_CLK_GATE_SARADC_WIDTH) - 1U) << SYSCON_DEV_CLK_GATE_SARADC_SHIFT)
#define SYSCON_DEV_CLK_GATE_SARADC_VALUE_DISABLE 0U
#define SYSCON_DEV_CLK_GATE_SARADC_BITS_DISABLE (SYSCON_DEV_CLK_GATE_SARADC_VALUE_DISABLE << SYSCON_DEV_CLK_GATE_SARADC_SHIFT)
#define SYSCON_DEV_CLK_GATE_SARADC_VALUE_ENABLE 1U
#define SYSCON_DEV_CLK_GATE_SARADC_BITS_ENABLE (SYSCON_DEV_CLK_GATE_SARADC_VALUE_ENABLE << SYSCON_DEV_CLK_GATE_SARADC_SHIFT)
#define SYSCON_DEV_CLK_GATE_CRC_SHIFT 27
#define SYSCON_DEV_CLK_GATE_CRC_WIDTH 1
#define SYSCON_DEV_CLK_GATE_CRC_MASK (((1U << SYSCON_DEV_CLK_GATE_CRC_WIDTH) - 1U) << SYSCON_DEV_CLK_GATE_CRC_SHIFT)
#define SYSCON_DEV_CLK_GATE_CRC_VALUE_DISABLE 0U
#define SYSCON_DEV_CLK_GATE_CRC_BITS_DISABLE (SYSCON_DEV_CLK_GATE_CRC_VALUE_DISABLE << SYSCON_DEV_CLK_GATE_CRC_SHIFT)
#define SYSCON_DEV_CLK_GATE_CRC_VALUE_ENABLE 1U
#define SYSCON_DEV_CLK_GATE_CRC_BITS_ENABLE (SYSCON_DEV_CLK_GATE_CRC_VALUE_ENABLE << SYSCON_DEV_CLK_GATE_CRC_SHIFT)
#define SYSCON_DEV_CLK_GATE_AES_SHIFT 28
#define SYSCON_DEV_CLK_GATE_AES_WIDTH 1
#define SYSCON_DEV_CLK_GATE_AES_MASK (((1U << SYSCON_DEV_CLK_GATE_AES_WIDTH) - 1U) << SYSCON_DEV_CLK_GATE_AES_SHIFT)
#define SYSCON_DEV_CLK_GATE_AES_VALUE_DISABLE 0U
#define SYSCON_DEV_CLK_GATE_AES_BITS_DISABLE (SYSCON_DEV_CLK_GATE_AES_VALUE_DISABLE << SYSCON_DEV_CLK_GATE_AES_SHIFT)
#define SYSCON_DEV_CLK_GATE_AES_VALUE_ENABLE 1U
#define SYSCON_DEV_CLK_GATE_AES_BITS_ENABLE (SYSCON_DEV_CLK_GATE_AES_VALUE_ENABLE << SYSCON_DEV_CLK_GATE_AES_SHIFT)
#define SYSCON_RC_FREQ_DELTA_ADDR (SYSCON_BASE_ADDR + 0x0078U)
#define SYSCON_RC_FREQ_DELTA (*(volatile uint32_t *)SYSCON_RC_FREQ_DELTA_ADDR)
#define SYSCON_RC_FREQ_DELTA_RCLF_DELTA_SHIFT 0
#define SYSCON_RC_FREQ_DELTA_RCLF_DELTA_WIDTH 10
#define SYSCON_RC_FREQ_DELTA_RCLF_DELTA_MASK (((1U << SYSCON_RC_FREQ_DELTA_RCLF_DELTA_WIDTH) - 1U) << SYSCON_RC_FREQ_DELTA_RCLF_DELTA_SHIFT)
#define SYSCON_RC_FREQ_DELTA_RCLF_SIG_SHIFT 10
#define SYSCON_RC_FREQ_DELTA_RCLF_SIG_WIDTH 1
#define SYSCON_RC_FREQ_DELTA_RCLF_SIG_MASK (((1U << SYSCON_RC_FREQ_DELTA_RCLF_SIG_WIDTH) - 1U) << SYSCON_RC_FREQ_DELTA_RCLF_SIG_SHIFT)
#define SYSCON_RC_FREQ_DELTA_RCHF_DELTA_SHIFT 11
#define SYSCON_RC_FREQ_DELTA_RCHF_DELTA_WIDTH 20
#define SYSCON_RC_FREQ_DELTA_RCHF_DELTA_MASK (((1U << SYSCON_RC_FREQ_DELTA_RCHF_DELTA_WIDTH) - 1U) << SYSCON_RC_FREQ_DELTA_RCHF_DELTA_SHIFT)
#define SYSCON_RC_FREQ_DELTA_RCHF_SIG_SHIFT 31
#define SYSCON_RC_FREQ_DELTA_RCHF_SIG_WIDTH 1
#define SYSCON_RC_FREQ_DELTA_RCHF_SIG_MASK (((1U << SYSCON_RC_FREQ_DELTA_RCHF_SIG_WIDTH) - 1U) << SYSCON_RC_FREQ_DELTA_RCHF_SIG_SHIFT)
#define SYSCON_VREF_VOLT_DELTA_ADDR (SYSCON_BASE_ADDR + 0x007CU)
#define SYSCON_VREF_VOLT_DELTA (*(volatile uint32_t *)SYSCON_VREF_VOLT_DELTA_ADDR)
#define SYSCON_CHIP_ID0_ADDR (SYSCON_BASE_ADDR + 0x0080U)
#define SYSCON_CHIP_ID0 (*(volatile uint32_t *)SYSCON_CHIP_ID0_ADDR)
#define SYSCON_CHIP_ID1_ADDR (SYSCON_BASE_ADDR + 0x0084U)
#define SYSCON_CHIP_ID1 (*(volatile uint32_t *)SYSCON_CHIP_ID1_ADDR)
#define SYSCON_CHIP_ID2_ADDR (SYSCON_BASE_ADDR + 0x0088U)
#define SYSCON_CHIP_ID2 (*(volatile uint32_t *)SYSCON_CHIP_ID2_ADDR)
#define SYSCON_CHIP_ID3_ADDR (SYSCON_BASE_ADDR + 0x008CU)
#define SYSCON_CHIP_ID3 (*(volatile uint32_t *)SYSCON_CHIP_ID3_ADDR)
#endif

439
bsp/dp32g030/uart.h Normal file
View File

@@ -0,0 +1,439 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef HARDWARE_DP32G030_UART_H
#define HARDWARE_DP32G030_UART_H
#if !defined(__ASSEMBLY__)
#include <stdint.h>
#endif
/* -------- UART0 -------- */
#define UART0_BASE_ADDR 0x4006B000U
#define UART0_BASE_SIZE 0x00000800U
#define UART0 ((volatile UART_Port_t *)UART0_BASE_ADDR)
/* -------- UART1 -------- */
#define UART1_BASE_ADDR 0x4006B800U
#define UART1_BASE_SIZE 0x00000800U
#define UART1 ((volatile UART_Port_t *)UART1_BASE_ADDR)
/* -------- UART2 -------- */
#define UART2_BASE_ADDR 0x4006C000U
#define UART2_BASE_SIZE 0x00000800U
#define UART2 ((volatile UART_Port_t *)UART2_BASE_ADDR)
/* -------- UART -------- */
typedef struct {
uint32_t CTRL;
uint32_t BAUD;
uint32_t TDR;
uint32_t RDR;
uint32_t IE;
uint32_t IF;
uint32_t FIFO;
uint32_t FC;
uint32_t RXTO;
} UART_Port_t;
#define UART_CTRL_UARTEN_SHIFT 0
#define UART_CTRL_UARTEN_WIDTH 1
#define UART_CTRL_UARTEN_MASK (((1U << UART_CTRL_UARTEN_WIDTH) - 1U) << UART_CTRL_UARTEN_SHIFT)
#define UART_CTRL_UARTEN_VALUE_DISABLE 0U
#define UART_CTRL_UARTEN_BITS_DISABLE (UART_CTRL_UARTEN_VALUE_DISABLE << UART_CTRL_UARTEN_SHIFT)
#define UART_CTRL_UARTEN_VALUE_ENABLE 1U
#define UART_CTRL_UARTEN_BITS_ENABLE (UART_CTRL_UARTEN_VALUE_ENABLE << UART_CTRL_UARTEN_SHIFT)
#define UART_CTRL_RXEN_SHIFT 1
#define UART_CTRL_RXEN_WIDTH 1
#define UART_CTRL_RXEN_MASK (((1U << UART_CTRL_RXEN_WIDTH) - 1U) << UART_CTRL_RXEN_SHIFT)
#define UART_CTRL_RXEN_VALUE_DISABLE 0U
#define UART_CTRL_RXEN_BITS_DISABLE (UART_CTRL_RXEN_VALUE_DISABLE << UART_CTRL_RXEN_SHIFT)
#define UART_CTRL_RXEN_VALUE_ENABLE 1U
#define UART_CTRL_RXEN_BITS_ENABLE (UART_CTRL_RXEN_VALUE_ENABLE << UART_CTRL_RXEN_SHIFT)
#define UART_CTRL_TXEN_SHIFT 2
#define UART_CTRL_TXEN_WIDTH 1
#define UART_CTRL_TXEN_MASK (((1U << UART_CTRL_TXEN_WIDTH) - 1U) << UART_CTRL_TXEN_SHIFT)
#define UART_CTRL_TXEN_VALUE_DISABLE 0U
#define UART_CTRL_TXEN_BITS_DISABLE (UART_CTRL_TXEN_VALUE_DISABLE << UART_CTRL_TXEN_SHIFT)
#define UART_CTRL_TXEN_VALUE_ENABLE 1U
#define UART_CTRL_TXEN_BITS_ENABLE (UART_CTRL_TXEN_VALUE_ENABLE << UART_CTRL_TXEN_SHIFT)
#define UART_CTRL_RXDMAEN_SHIFT 3
#define UART_CTRL_RXDMAEN_WIDTH 1
#define UART_CTRL_RXDMAEN_MASK (((1U << UART_CTRL_RXDMAEN_WIDTH) - 1U) << UART_CTRL_RXDMAEN_SHIFT)
#define UART_CTRL_RXDMAEN_VALUE_DISABLE 0U
#define UART_CTRL_RXDMAEN_BITS_DISABLE (UART_CTRL_RXDMAEN_VALUE_DISABLE << UART_CTRL_RXDMAEN_SHIFT)
#define UART_CTRL_RXDMAEN_VALUE_ENABLE 1U
#define UART_CTRL_RXDMAEN_BITS_ENABLE (UART_CTRL_RXDMAEN_VALUE_ENABLE << UART_CTRL_RXDMAEN_SHIFT)
#define UART_CTRL_TXDMAEN_SHIFT 4
#define UART_CTRL_TXDMAEN_WIDTH 1
#define UART_CTRL_TXDMAEN_MASK (((1U << UART_CTRL_TXDMAEN_WIDTH) - 1U) << UART_CTRL_TXDMAEN_SHIFT)
#define UART_CTRL_TXDMAEN_VALUE_DISABLE 0U
#define UART_CTRL_TXDMAEN_BITS_DISABLE (UART_CTRL_TXDMAEN_VALUE_DISABLE << UART_CTRL_TXDMAEN_SHIFT)
#define UART_CTRL_TXDMAEN_VALUE_ENABLE 1U
#define UART_CTRL_TXDMAEN_BITS_ENABLE (UART_CTRL_TXDMAEN_VALUE_ENABLE << UART_CTRL_TXDMAEN_SHIFT)
#define UART_CTRL_NINEBIT_SHIFT 5
#define UART_CTRL_NINEBIT_WIDTH 1
#define UART_CTRL_NINEBIT_MASK (((1U << UART_CTRL_NINEBIT_WIDTH) - 1U) << UART_CTRL_NINEBIT_SHIFT)
#define UART_CTRL_NINEBIT_VALUE_DISABLE 0U
#define UART_CTRL_NINEBIT_BITS_DISABLE (UART_CTRL_NINEBIT_VALUE_DISABLE << UART_CTRL_NINEBIT_SHIFT)
#define UART_CTRL_NINEBIT_VALUE_ENABLE 1U
#define UART_CTRL_NINEBIT_BITS_ENABLE (UART_CTRL_NINEBIT_VALUE_ENABLE << UART_CTRL_NINEBIT_SHIFT)
#define UART_CTRL_PAREN_SHIFT 6
#define UART_CTRL_PAREN_WIDTH 1
#define UART_CTRL_PAREN_MASK (((1U << UART_CTRL_PAREN_WIDTH) - 1U) << UART_CTRL_PAREN_SHIFT)
#define UART_CTRL_PAREN_VALUE_DISABLE 0U
#define UART_CTRL_PAREN_BITS_DISABLE (UART_CTRL_PAREN_VALUE_DISABLE << UART_CTRL_PAREN_SHIFT)
#define UART_CTRL_PAREN_VALUE_ENABLE 1U
#define UART_CTRL_PAREN_BITS_ENABLE (UART_CTRL_PAREN_VALUE_ENABLE << UART_CTRL_PAREN_SHIFT)
#define UART_IE_TXDONE_SHIFT 2
#define UART_IE_TXDONE_WIDTH 1
#define UART_IE_TXDONE_MASK (((1U << UART_IE_TXDONE_WIDTH) - 1U) << UART_IE_TXDONE_SHIFT)
#define UART_IE_TXDONE_VALUE_DISABLE 0U
#define UART_IE_TXDONE_BITS_DISABLE (UART_IE_TXDONE_VALUE_DISABLE << UART_IE_TXDONE_SHIFT)
#define UART_IE_TXDONE_VALUE_ENABLE 1U
#define UART_IE_TXDONE_BITS_ENABLE (UART_IE_TXDONE_VALUE_ENABLE << UART_IE_TXDONE_SHIFT)
#define UART_IE_PARITYE_SHIFT 3
#define UART_IE_PARITYE_WIDTH 1
#define UART_IE_PARITYE_MASK (((1U << UART_IE_PARITYE_WIDTH) - 1U) << UART_IE_PARITYE_SHIFT)
#define UART_IE_PARITYE_VALUE_DISABLE 0U
#define UART_IE_PARITYE_BITS_DISABLE (UART_IE_PARITYE_VALUE_DISABLE << UART_IE_PARITYE_SHIFT)
#define UART_IE_PARITYE_VALUE_ENABLE 1U
#define UART_IE_PARITYE_BITS_ENABLE (UART_IE_PARITYE_VALUE_ENABLE << UART_IE_PARITYE_SHIFT)
#define UART_IE_STOPE_SHIFT 4
#define UART_IE_STOPE_WIDTH 1
#define UART_IE_STOPE_MASK (((1U << UART_IE_STOPE_WIDTH) - 1U) << UART_IE_STOPE_SHIFT)
#define UART_IE_STOPE_VALUE_DISABLE 0U
#define UART_IE_STOPE_BITS_DISABLE (UART_IE_STOPE_VALUE_DISABLE << UART_IE_STOPE_SHIFT)
#define UART_IE_STOPE_VALUE_ENABLE 1U
#define UART_IE_STOPE_BITS_ENABLE (UART_IE_STOPE_VALUE_ENABLE << UART_IE_STOPE_SHIFT)
#define UART_IE_RXTO_SHIFT 5
#define UART_IE_RXTO_WIDTH 1
#define UART_IE_RXTO_MASK (((1U << UART_IE_RXTO_WIDTH) - 1U) << UART_IE_RXTO_SHIFT)
#define UART_IE_RXTO_VALUE_DISABLE 0U
#define UART_IE_RXTO_BITS_DISABLE (UART_IE_RXTO_VALUE_DISABLE << UART_IE_RXTO_SHIFT)
#define UART_IE_RXTO_VALUE_ENABLE 1U
#define UART_IE_RXTO_BITS_ENABLE (UART_IE_RXTO_VALUE_ENABLE << UART_IE_RXTO_SHIFT)
#define UART_IE_RXFIFO_SHIFT 6
#define UART_IE_RXFIFO_WIDTH 1
#define UART_IE_RXFIFO_MASK (((1U << UART_IE_RXFIFO_WIDTH) - 1U) << UART_IE_RXFIFO_SHIFT)
#define UART_IE_RXFIFO_VALUE_DISABLE 0U
#define UART_IE_RXFIFO_BITS_DISABLE (UART_IE_RXFIFO_VALUE_DISABLE << UART_IE_RXFIFO_SHIFT)
#define UART_IE_RXFIFO_VALUE_ENABLE 1U
#define UART_IE_RXFIFO_BITS_ENABLE (UART_IE_RXFIFO_VALUE_ENABLE << UART_IE_RXFIFO_SHIFT)
#define UART_IE_TXFIFO_SHIFT 7
#define UART_IE_TXFIFO_WIDTH 1
#define UART_IE_TXFIFO_MASK (((1U << UART_IE_TXFIFO_WIDTH) - 1U) << UART_IE_TXFIFO_SHIFT)
#define UART_IE_TXFIFO_VALUE_DISABLE 0U
#define UART_IE_TXFIFO_BITS_DISABLE (UART_IE_TXFIFO_VALUE_DISABLE << UART_IE_TXFIFO_SHIFT)
#define UART_IE_TXFIFO_VALUE_ENABLE 1U
#define UART_IE_TXFIFO_BITS_ENABLE (UART_IE_TXFIFO_VALUE_ENABLE << UART_IE_TXFIFO_SHIFT)
#define UART_IE_RXFIFO_OVF_SHIFT 8
#define UART_IE_RXFIFO_OVF_WIDTH 1
#define UART_IE_RXFIFO_OVF_MASK (((1U << UART_IE_RXFIFO_OVF_WIDTH) - 1U) << UART_IE_RXFIFO_OVF_SHIFT)
#define UART_IE_RXFIFO_OVF_VALUE_DISABLE 0U
#define UART_IE_RXFIFO_OVF_BITS_DISABLE (UART_IE_RXFIFO_OVF_VALUE_DISABLE << UART_IE_RXFIFO_OVF_SHIFT)
#define UART_IE_RXFIFO_OVF_VALUE_ENABLE 1U
#define UART_IE_RXFIFO_OVF_BITS_ENABLE (UART_IE_RXFIFO_OVF_VALUE_ENABLE << UART_IE_RXFIFO_OVF_SHIFT)
#define UART_IE_ABRD_OVF_SHIFT 9
#define UART_IE_ABRD_OVF_WIDTH 1
#define UART_IE_ABRD_OVF_MASK (((1U << UART_IE_ABRD_OVF_WIDTH) - 1U) << UART_IE_ABRD_OVF_SHIFT)
#define UART_IE_ABRD_OVF_VALUE_DISABLE 0U
#define UART_IE_ABRD_OVF_BITS_DISABLE (UART_IE_ABRD_OVF_VALUE_DISABLE << UART_IE_ABRD_OVF_SHIFT)
#define UART_IE_ABRD_OVF_VALUE_ENABLE 1U
#define UART_IE_ABRD_OVF_BITS_ENABLE (UART_IE_ABRD_OVF_VALUE_ENABLE << UART_IE_ABRD_OVF_SHIFT)
#define UART_IF_TXDONE_SHIFT 2
#define UART_IF_TXDONE_WIDTH 1
#define UART_IF_TXDONE_MASK (((1U << UART_IF_TXDONE_WIDTH) - 1U) << UART_IF_TXDONE_SHIFT)
#define UART_IF_TXDONE_VALUE_NOT_SET 0U
#define UART_IF_TXDONE_BITS_NOT_SET (UART_IF_TXDONE_VALUE_NOT_SET << UART_IF_TXDONE_SHIFT)
#define UART_IF_TXDONE_VALUE_SET 1U
#define UART_IF_TXDONE_BITS_SET (UART_IF_TXDONE_VALUE_SET << UART_IF_TXDONE_SHIFT)
#define UART_IF_PARITYE_SHIFT 3
#define UART_IF_PARITYE_WIDTH 1
#define UART_IF_PARITYE_MASK (((1U << UART_IF_PARITYE_WIDTH) - 1U) << UART_IF_PARITYE_SHIFT)
#define UART_IF_PARITYE_VALUE_NOT_SET 0U
#define UART_IF_PARITYE_BITS_NOT_SET (UART_IF_PARITYE_VALUE_NOT_SET << UART_IF_PARITYE_SHIFT)
#define UART_IF_PARITYE_VALUE_SET 1U
#define UART_IF_PARITYE_BITS_SET (UART_IF_PARITYE_VALUE_SET << UART_IF_PARITYE_SHIFT)
#define UART_IF_STOPE_SHIFT 4
#define UART_IF_STOPE_WIDTH 1
#define UART_IF_STOPE_MASK (((1U << UART_IF_STOPE_WIDTH) - 1U) << UART_IF_STOPE_SHIFT)
#define UART_IF_STOPE_VALUE_NOT_SET 0U
#define UART_IF_STOPE_BITS_NOT_SET (UART_IF_STOPE_VALUE_NOT_SET << UART_IF_STOPE_SHIFT)
#define UART_IF_STOPE_VALUE_SET 1U
#define UART_IF_STOPE_BITS_SET (UART_IF_STOPE_VALUE_SET << UART_IF_STOPE_SHIFT)
#define UART_IF_RXTO_SHIFT 5
#define UART_IF_RXTO_WIDTH 1
#define UART_IF_RXTO_MASK (((1U << UART_IF_RXTO_WIDTH) - 1U) << UART_IF_RXTO_SHIFT)
#define UART_IF_RXTO_VALUE_NOT_SET 0U
#define UART_IF_RXTO_BITS_NOT_SET (UART_IF_RXTO_VALUE_NOT_SET << UART_IF_RXTO_SHIFT)
#define UART_IF_RXTO_VALUE_SET 1U
#define UART_IF_RXTO_BITS_SET (UART_IF_RXTO_VALUE_SET << UART_IF_RXTO_SHIFT)
#define UART_IF_RXFIFO_SHIFT 6
#define UART_IF_RXFIFO_WIDTH 1
#define UART_IF_RXFIFO_MASK (((1U << UART_IF_RXFIFO_WIDTH) - 1U) << UART_IF_RXFIFO_SHIFT)
#define UART_IF_RXFIFO_VALUE_NOT_SET 0U
#define UART_IF_RXFIFO_BITS_NOT_SET (UART_IF_RXFIFO_VALUE_NOT_SET << UART_IF_RXFIFO_SHIFT)
#define UART_IF_RXFIFO_VALUE_SET 1U
#define UART_IF_RXFIFO_BITS_SET (UART_IF_RXFIFO_VALUE_SET << UART_IF_RXFIFO_SHIFT)
#define UART_IF_TXFIFO_SHIFT 7
#define UART_IF_TXFIFO_WIDTH 1
#define UART_IF_TXFIFO_MASK (((1U << UART_IF_TXFIFO_WIDTH) - 1U) << UART_IF_TXFIFO_SHIFT)
#define UART_IF_TXFIFO_VALUE_NOT_SET 0U
#define UART_IF_TXFIFO_BITS_NOT_SET (UART_IF_TXFIFO_VALUE_NOT_SET << UART_IF_TXFIFO_SHIFT)
#define UART_IF_TXFIFO_VALUE_SET 1U
#define UART_IF_TXFIFO_BITS_SET (UART_IF_TXFIFO_VALUE_SET << UART_IF_TXFIFO_SHIFT)
#define UART_IF_RXFIFO_OVF_SHIFT 8
#define UART_IF_RXFIFO_OVF_WIDTH 1
#define UART_IF_RXFIFO_OVF_MASK (((1U << UART_IF_RXFIFO_OVF_WIDTH) - 1U) << UART_IF_RXFIFO_OVF_SHIFT)
#define UART_IF_RXFIFO_OVF_VALUE_NOT_SET 0U
#define UART_IF_RXFIFO_OVF_BITS_NOT_SET (UART_IF_RXFIFO_OVF_VALUE_NOT_SET << UART_IF_RXFIFO_OVF_SHIFT)
#define UART_IF_RXFIFO_OVF_VALUE_SET 1U
#define UART_IF_RXFIFO_OVF_BITS_SET (UART_IF_RXFIFO_OVF_VALUE_SET << UART_IF_RXFIFO_OVF_SHIFT)
#define UART_IF_ABRD_OVF_SHIFT 9
#define UART_IF_ABRD_OVF_WIDTH 1
#define UART_IF_ABRD_OVF_MASK (((1U << UART_IF_ABRD_OVF_WIDTH) - 1U) << UART_IF_ABRD_OVF_SHIFT)
#define UART_IF_ABRD_OVF_VALUE_NOT_SET 0U
#define UART_IF_ABRD_OVF_BITS_NOT_SET (UART_IF_ABRD_OVF_VALUE_NOT_SET << UART_IF_ABRD_OVF_SHIFT)
#define UART_IF_ABRD_OVF_VALUE_SET 1U
#define UART_IF_ABRD_OVF_BITS_SET (UART_IF_ABRD_OVF_VALUE_SET << UART_IF_ABRD_OVF_SHIFT)
#define UART_IF_RXFIFO_EMPTY_SHIFT 10
#define UART_IF_RXFIFO_EMPTY_WIDTH 1
#define UART_IF_RXFIFO_EMPTY_MASK (((1U << UART_IF_RXFIFO_EMPTY_WIDTH) - 1U) << UART_IF_RXFIFO_EMPTY_SHIFT)
#define UART_IF_RXFIFO_EMPTY_VALUE_NOT_SET 0U
#define UART_IF_RXFIFO_EMPTY_BITS_NOT_SET (UART_IF_RXFIFO_EMPTY_VALUE_NOT_SET << UART_IF_RXFIFO_EMPTY_SHIFT)
#define UART_IF_RXFIFO_EMPTY_VALUE_SET 1U
#define UART_IF_RXFIFO_EMPTY_BITS_SET (UART_IF_RXFIFO_EMPTY_VALUE_SET << UART_IF_RXFIFO_EMPTY_SHIFT)
#define UART_IF_RXFIFO_FULL_SHIFT 11
#define UART_IF_RXFIFO_FULL_WIDTH 1
#define UART_IF_RXFIFO_FULL_MASK (((1U << UART_IF_RXFIFO_FULL_WIDTH) - 1U) << UART_IF_RXFIFO_FULL_SHIFT)
#define UART_IF_RXFIFO_FULL_VALUE_NOT_SET 0U
#define UART_IF_RXFIFO_FULL_BITS_NOT_SET (UART_IF_RXFIFO_FULL_VALUE_NOT_SET << UART_IF_RXFIFO_FULL_SHIFT)
#define UART_IF_RXFIFO_FULL_VALUE_SET 1U
#define UART_IF_RXFIFO_FULL_BITS_SET (UART_IF_RXFIFO_FULL_VALUE_SET << UART_IF_RXFIFO_FULL_SHIFT)
#define UART_IF_RXFIFO_HFULL_SHIFT 12
#define UART_IF_RXFIFO_HFULL_WIDTH 1
#define UART_IF_RXFIFO_HFULL_MASK (((1U << UART_IF_RXFIFO_HFULL_WIDTH) - 1U) << UART_IF_RXFIFO_HFULL_SHIFT)
#define UART_IF_RXFIFO_HFULL_VALUE_NOT_SET 0U
#define UART_IF_RXFIFO_HFULL_BITS_NOT_SET (UART_IF_RXFIFO_HFULL_VALUE_NOT_SET << UART_IF_RXFIFO_HFULL_SHIFT)
#define UART_IF_RXFIFO_HFULL_VALUE_SET 1U
#define UART_IF_RXFIFO_HFULL_BITS_SET (UART_IF_RXFIFO_HFULL_VALUE_SET << UART_IF_RXFIFO_HFULL_SHIFT)
#define UART_IF_TXFIFO_EMPTY_SHIFT 13
#define UART_IF_TXFIFO_EMPTY_WIDTH 1
#define UART_IF_TXFIFO_EMPTY_MASK (((1U << UART_IF_TXFIFO_EMPTY_WIDTH) - 1U) << UART_IF_TXFIFO_EMPTY_SHIFT)
#define UART_IF_TXFIFO_EMPTY_VALUE_NOT_SET 0U
#define UART_IF_TXFIFO_EMPTY_BITS_NOT_SET (UART_IF_TXFIFO_EMPTY_VALUE_NOT_SET << UART_IF_TXFIFO_EMPTY_SHIFT)
#define UART_IF_TXFIFO_EMPTY_VALUE_SET 1U
#define UART_IF_TXFIFO_EMPTY_BITS_SET (UART_IF_TXFIFO_EMPTY_VALUE_SET << UART_IF_TXFIFO_EMPTY_SHIFT)
#define UART_IF_TXFIFO_FULL_SHIFT 14
#define UART_IF_TXFIFO_FULL_WIDTH 1
#define UART_IF_TXFIFO_FULL_MASK (((1U << UART_IF_TXFIFO_FULL_WIDTH) - 1U) << UART_IF_TXFIFO_FULL_SHIFT)
#define UART_IF_TXFIFO_FULL_VALUE_NOT_SET 0U
#define UART_IF_TXFIFO_FULL_BITS_NOT_SET (UART_IF_TXFIFO_FULL_VALUE_NOT_SET << UART_IF_TXFIFO_FULL_SHIFT)
#define UART_IF_TXFIFO_FULL_VALUE_SET 1U
#define UART_IF_TXFIFO_FULL_BITS_SET (UART_IF_TXFIFO_FULL_VALUE_SET << UART_IF_TXFIFO_FULL_SHIFT)
#define UART_IF_TXFIFO_HFULL_SHIFT 15
#define UART_IF_TXFIFO_HFULL_WIDTH 1
#define UART_IF_TXFIFO_HFULL_MASK (((1U << UART_IF_TXFIFO_HFULL_WIDTH) - 1U) << UART_IF_TXFIFO_HFULL_SHIFT)
#define UART_IF_TXFIFO_HFULL_VALUE_NOT_SET 0U
#define UART_IF_TXFIFO_HFULL_BITS_NOT_SET (UART_IF_TXFIFO_HFULL_VALUE_NOT_SET << UART_IF_TXFIFO_HFULL_SHIFT)
#define UART_IF_TXFIFO_HFULL_VALUE_SET 1U
#define UART_IF_TXFIFO_HFULL_BITS_SET (UART_IF_TXFIFO_HFULL_VALUE_SET << UART_IF_TXFIFO_HFULL_SHIFT)
#define UART_IF_TXBUSY_SHIFT 16
#define UART_IF_TXBUSY_WIDTH 1
#define UART_IF_TXBUSY_MASK (((1U << UART_IF_TXBUSY_WIDTH) - 1U) << UART_IF_TXBUSY_SHIFT)
#define UART_IF_TXBUSY_VALUE_NOT_SET 0U
#define UART_IF_TXBUSY_BITS_NOT_SET (UART_IF_TXBUSY_VALUE_NOT_SET << UART_IF_TXBUSY_SHIFT)
#define UART_IF_TXBUSY_VALUE_SET 1U
#define UART_IF_TXBUSY_BITS_SET (UART_IF_TXBUSY_VALUE_SET << UART_IF_TXBUSY_SHIFT)
#define UART_IF_RF_LEVEL_SHIFT 17
#define UART_IF_RF_LEVEL_WIDTH 3
#define UART_IF_RF_LEVEL_MASK (((1U << UART_IF_RF_LEVEL_WIDTH) - 1U) << UART_IF_RF_LEVEL_SHIFT)
#define UART_IF_RF_LEVEL_VALUE_0_8_BYTE 0U
#define UART_IF_RF_LEVEL_BITS_0_8_BYTE (UART_IF_RF_LEVEL_VALUE_0_8_BYTE << UART_IF_RF_LEVEL_SHIFT)
#define UART_IF_RF_LEVEL_VALUE_1_BYTE 1U
#define UART_IF_RF_LEVEL_BITS_1_BYTE (UART_IF_RF_LEVEL_VALUE_1_BYTE << UART_IF_RF_LEVEL_SHIFT)
#define UART_IF_RF_LEVEL_VALUE_2_BYTE 2U
#define UART_IF_RF_LEVEL_BITS_2_BYTE (UART_IF_RF_LEVEL_VALUE_2_BYTE << UART_IF_RF_LEVEL_SHIFT)
#define UART_IF_RF_LEVEL_VALUE_3_BYTE 3U
#define UART_IF_RF_LEVEL_BITS_3_BYTE (UART_IF_RF_LEVEL_VALUE_3_BYTE << UART_IF_RF_LEVEL_SHIFT)
#define UART_IF_RF_LEVEL_VALUE_4_BYTE 4U
#define UART_IF_RF_LEVEL_BITS_4_BYTE (UART_IF_RF_LEVEL_VALUE_4_BYTE << UART_IF_RF_LEVEL_SHIFT)
#define UART_IF_RF_LEVEL_VALUE_5_BYTE 5U
#define UART_IF_RF_LEVEL_BITS_5_BYTE (UART_IF_RF_LEVEL_VALUE_5_BYTE << UART_IF_RF_LEVEL_SHIFT)
#define UART_IF_RF_LEVEL_VALUE_6_BYTE 6U
#define UART_IF_RF_LEVEL_BITS_6_BYTE (UART_IF_RF_LEVEL_VALUE_6_BYTE << UART_IF_RF_LEVEL_SHIFT)
#define UART_IF_RF_LEVEL_VALUE_7_BYTE 7U
#define UART_IF_RF_LEVEL_BITS_7_BYTE (UART_IF_RF_LEVEL_VALUE_7_BYTE << UART_IF_RF_LEVEL_SHIFT)
#define UART_IF_TF_LEVEL_SHIFT 20
#define UART_IF_TF_LEVEL_WIDTH 3
#define UART_IF_TF_LEVEL_MASK (((1U << UART_IF_TF_LEVEL_WIDTH) - 1U) << UART_IF_TF_LEVEL_SHIFT)
#define UART_IF_TF_LEVEL_VALUE_0_8_BYTE 0U
#define UART_IF_TF_LEVEL_BITS_0_8_BYTE (UART_IF_TF_LEVEL_VALUE_0_8_BYTE << UART_IF_TF_LEVEL_SHIFT)
#define UART_IF_TF_LEVEL_VALUE_1_BYTE 1U
#define UART_IF_TF_LEVEL_BITS_1_BYTE (UART_IF_TF_LEVEL_VALUE_1_BYTE << UART_IF_TF_LEVEL_SHIFT)
#define UART_IF_TF_LEVEL_VALUE_2_BYTE 2U
#define UART_IF_TF_LEVEL_BITS_2_BYTE (UART_IF_TF_LEVEL_VALUE_2_BYTE << UART_IF_TF_LEVEL_SHIFT)
#define UART_IF_TF_LEVEL_VALUE_3_BYTE 3U
#define UART_IF_TF_LEVEL_BITS_3_BYTE (UART_IF_TF_LEVEL_VALUE_3_BYTE << UART_IF_TF_LEVEL_SHIFT)
#define UART_IF_TF_LEVEL_VALUE_4_BYTE 4U
#define UART_IF_TF_LEVEL_BITS_4_BYTE (UART_IF_TF_LEVEL_VALUE_4_BYTE << UART_IF_TF_LEVEL_SHIFT)
#define UART_IF_TF_LEVEL_VALUE_5_BYTE 5U
#define UART_IF_TF_LEVEL_BITS_5_BYTE (UART_IF_TF_LEVEL_VALUE_5_BYTE << UART_IF_TF_LEVEL_SHIFT)
#define UART_IF_TF_LEVEL_VALUE_6_BYTE 6U
#define UART_IF_TF_LEVEL_BITS_6_BYTE (UART_IF_TF_LEVEL_VALUE_6_BYTE << UART_IF_TF_LEVEL_SHIFT)
#define UART_IF_TF_LEVEL_VALUE_7_BYTE 7U
#define UART_IF_TF_LEVEL_BITS_7_BYTE (UART_IF_TF_LEVEL_VALUE_7_BYTE << UART_IF_TF_LEVEL_SHIFT)
#define UART_FIFO_RF_LEVEL_SHIFT 0
#define UART_FIFO_RF_LEVEL_WIDTH 3
#define UART_FIFO_RF_LEVEL_MASK (((1U << UART_FIFO_RF_LEVEL_WIDTH) - 1U) << UART_FIFO_RF_LEVEL_SHIFT)
#define UART_FIFO_RF_LEVEL_VALUE_1_BYTE 0U
#define UART_FIFO_RF_LEVEL_BITS_1_BYTE (UART_FIFO_RF_LEVEL_VALUE_1_BYTE << UART_FIFO_RF_LEVEL_SHIFT)
#define UART_FIFO_RF_LEVEL_VALUE_2_BYTE 1U
#define UART_FIFO_RF_LEVEL_BITS_2_BYTE (UART_FIFO_RF_LEVEL_VALUE_2_BYTE << UART_FIFO_RF_LEVEL_SHIFT)
#define UART_FIFO_RF_LEVEL_VALUE_3_BYTE 2U
#define UART_FIFO_RF_LEVEL_BITS_3_BYTE (UART_FIFO_RF_LEVEL_VALUE_3_BYTE << UART_FIFO_RF_LEVEL_SHIFT)
#define UART_FIFO_RF_LEVEL_VALUE_4_BYTE 3U
#define UART_FIFO_RF_LEVEL_BITS_4_BYTE (UART_FIFO_RF_LEVEL_VALUE_4_BYTE << UART_FIFO_RF_LEVEL_SHIFT)
#define UART_FIFO_RF_LEVEL_VALUE_5_BYTE 4U
#define UART_FIFO_RF_LEVEL_BITS_5_BYTE (UART_FIFO_RF_LEVEL_VALUE_5_BYTE << UART_FIFO_RF_LEVEL_SHIFT)
#define UART_FIFO_RF_LEVEL_VALUE_6_BYTE 5U
#define UART_FIFO_RF_LEVEL_BITS_6_BYTE (UART_FIFO_RF_LEVEL_VALUE_6_BYTE << UART_FIFO_RF_LEVEL_SHIFT)
#define UART_FIFO_RF_LEVEL_VALUE_7_BYTE 6U
#define UART_FIFO_RF_LEVEL_BITS_7_BYTE (UART_FIFO_RF_LEVEL_VALUE_7_BYTE << UART_FIFO_RF_LEVEL_SHIFT)
#define UART_FIFO_RF_LEVEL_VALUE_8_BYTE 7U
#define UART_FIFO_RF_LEVEL_BITS_8_BYTE (UART_FIFO_RF_LEVEL_VALUE_8_BYTE << UART_FIFO_RF_LEVEL_SHIFT)
#define UART_FIFO_TF_LEVEL_SHIFT 3
#define UART_FIFO_TF_LEVEL_WIDTH 3
#define UART_FIFO_TF_LEVEL_MASK (((1U << UART_FIFO_TF_LEVEL_WIDTH) - 1U) << UART_FIFO_TF_LEVEL_SHIFT)
#define UART_FIFO_TF_LEVEL_VALUE_0_BYTE 0U
#define UART_FIFO_TF_LEVEL_BITS_0_BYTE (UART_FIFO_TF_LEVEL_VALUE_0_BYTE << UART_FIFO_TF_LEVEL_SHIFT)
#define UART_FIFO_TF_LEVEL_VALUE_1_BYTE 1U
#define UART_FIFO_TF_LEVEL_BITS_1_BYTE (UART_FIFO_TF_LEVEL_VALUE_1_BYTE << UART_FIFO_TF_LEVEL_SHIFT)
#define UART_FIFO_TF_LEVEL_VALUE_2_BYTE 2U
#define UART_FIFO_TF_LEVEL_BITS_2_BYTE (UART_FIFO_TF_LEVEL_VALUE_2_BYTE << UART_FIFO_TF_LEVEL_SHIFT)
#define UART_FIFO_TF_LEVEL_VALUE_3_BYTE 3U
#define UART_FIFO_TF_LEVEL_BITS_3_BYTE (UART_FIFO_TF_LEVEL_VALUE_3_BYTE << UART_FIFO_TF_LEVEL_SHIFT)
#define UART_FIFO_TF_LEVEL_VALUE_4_BYTE 4U
#define UART_FIFO_TF_LEVEL_BITS_4_BYTE (UART_FIFO_TF_LEVEL_VALUE_4_BYTE << UART_FIFO_TF_LEVEL_SHIFT)
#define UART_FIFO_TF_LEVEL_VALUE_5_BYTE 5U
#define UART_FIFO_TF_LEVEL_BITS_5_BYTE (UART_FIFO_TF_LEVEL_VALUE_5_BYTE << UART_FIFO_TF_LEVEL_SHIFT)
#define UART_FIFO_TF_LEVEL_VALUE_6_BYTE 6U
#define UART_FIFO_TF_LEVEL_BITS_6_BYTE (UART_FIFO_TF_LEVEL_VALUE_6_BYTE << UART_FIFO_TF_LEVEL_SHIFT)
#define UART_FIFO_TF_LEVEL_VALUE_7_BYTE 7U
#define UART_FIFO_TF_LEVEL_BITS_7_BYTE (UART_FIFO_TF_LEVEL_VALUE_7_BYTE << UART_FIFO_TF_LEVEL_SHIFT)
#define UART_FIFO_RF_CLR_SHIFT 6
#define UART_FIFO_RF_CLR_WIDTH 1
#define UART_FIFO_RF_CLR_MASK (((1U << UART_FIFO_RF_CLR_WIDTH) - 1U) << UART_FIFO_RF_CLR_SHIFT)
#define UART_FIFO_RF_CLR_VALUE_DISABLE 0U
#define UART_FIFO_RF_CLR_BITS_DISABLE (UART_FIFO_RF_CLR_VALUE_DISABLE << UART_FIFO_RF_CLR_SHIFT)
#define UART_FIFO_RF_CLR_VALUE_ENABLE 1U
#define UART_FIFO_RF_CLR_BITS_ENABLE (UART_FIFO_RF_CLR_VALUE_ENABLE << UART_FIFO_RF_CLR_SHIFT)
#define UART_FIFO_TF_CLR_SHIFT 7
#define UART_FIFO_TF_CLR_WIDTH 1
#define UART_FIFO_TF_CLR_MASK (((1U << UART_FIFO_TF_CLR_WIDTH) - 1U) << UART_FIFO_TF_CLR_SHIFT)
#define UART_FIFO_TF_CLR_VALUE_DISABLE 0U
#define UART_FIFO_TF_CLR_BITS_DISABLE (UART_FIFO_TF_CLR_VALUE_DISABLE << UART_FIFO_TF_CLR_SHIFT)
#define UART_FIFO_TF_CLR_VALUE_ENABLE 1U
#define UART_FIFO_TF_CLR_BITS_ENABLE (UART_FIFO_TF_CLR_VALUE_ENABLE << UART_FIFO_TF_CLR_SHIFT)
#define UART_FC_CTSEN_SHIFT 0
#define UART_FC_CTSEN_WIDTH 1
#define UART_FC_CTSEN_MASK (((1U << UART_FC_CTSEN_WIDTH) - 1U) << UART_FC_CTSEN_SHIFT)
#define UART_FC_CTSEN_VALUE_DISABLE 0U
#define UART_FC_CTSEN_BITS_DISABLE (UART_FC_CTSEN_VALUE_DISABLE << UART_FC_CTSEN_SHIFT)
#define UART_FC_CTSEN_VALUE_ENABLE 1U
#define UART_FC_CTSEN_BITS_ENABLE (UART_FC_CTSEN_VALUE_ENABLE << UART_FC_CTSEN_SHIFT)
#define UART_FC_RTSEN_SHIFT 1
#define UART_FC_RTSEN_WIDTH 1
#define UART_FC_RTSEN_MASK (((1U << UART_FC_RTSEN_WIDTH) - 1U) << UART_FC_RTSEN_SHIFT)
#define UART_FC_RTSEN_VALUE_DISABLE 0U
#define UART_FC_RTSEN_BITS_DISABLE (UART_FC_RTSEN_VALUE_DISABLE << UART_FC_RTSEN_SHIFT)
#define UART_FC_RTSEN_VALUE_ENABLE 1U
#define UART_FC_RTSEN_BITS_ENABLE (UART_FC_RTSEN_VALUE_ENABLE << UART_FC_RTSEN_SHIFT)
#define UART_FC_CTSPOL_SHIFT 2
#define UART_FC_CTSPOL_WIDTH 1
#define UART_FC_CTSPOL_MASK (((1U << UART_FC_CTSPOL_WIDTH) - 1U) << UART_FC_CTSPOL_SHIFT)
#define UART_FC_CTSPOL_VALUE_LOW 0U
#define UART_FC_CTSPOL_BITS_LOW (UART_FC_CTSPOL_VALUE_LOW << UART_FC_CTSPOL_SHIFT)
#define UART_FC_CTSPOL_VALUE_HIGH 1U
#define UART_FC_CTSPOL_BITS_HIGH (UART_FC_CTSPOL_VALUE_HIGH << UART_FC_CTSPOL_SHIFT)
#define UART_FC_RTSPOL_SHIFT 3
#define UART_FC_RTSPOL_WIDTH 1
#define UART_FC_RTSPOL_MASK (((1U << UART_FC_RTSPOL_WIDTH) - 1U) << UART_FC_RTSPOL_SHIFT)
#define UART_FC_RTSPOL_VALUE_LOW 0U
#define UART_FC_RTSPOL_BITS_LOW (UART_FC_RTSPOL_VALUE_LOW << UART_FC_RTSPOL_SHIFT)
#define UART_FC_RTSPOL_VALUE_HIGH 1U
#define UART_FC_RTSPOL_BITS_HIGH (UART_FC_RTSPOL_VALUE_HIGH << UART_FC_RTSPOL_SHIFT)
#define UART_FC_CTS_SIGNAL_SHIFT 4
#define UART_FC_CTS_SIGNAL_WIDTH 1
#define UART_FC_CTS_SIGNAL_MASK (((1U << UART_FC_CTS_SIGNAL_WIDTH) - 1U) << UART_FC_CTS_SIGNAL_SHIFT)
#define UART_FC_CTS_SIGNAL_VALUE_LOW 0U
#define UART_FC_CTS_SIGNAL_BITS_LOW (UART_FC_CTS_SIGNAL_VALUE_LOW << UART_FC_CTS_SIGNAL_SHIFT)
#define UART_FC_CTS_SIGNAL_VALUE_HIGH 1U
#define UART_FC_CTS_SIGNAL_BITS_HIGH (UART_FC_CTS_SIGNAL_VALUE_HIGH << UART_FC_CTS_SIGNAL_SHIFT)
#define UART_FC_RTS_SIGNAL_SHIFT 5
#define UART_FC_RTS_SIGNAL_WIDTH 1
#define UART_FC_RTS_SIGNAL_MASK (((1U << UART_FC_RTS_SIGNAL_WIDTH) - 1U) << UART_FC_RTS_SIGNAL_SHIFT)
#define UART_FC_RTS_SIGNAL_VALUE_LOW 0U
#define UART_FC_RTS_SIGNAL_BITS_LOW (UART_FC_RTS_SIGNAL_VALUE_LOW << UART_FC_RTS_SIGNAL_SHIFT)
#define UART_FC_RTS_SIGNAL_VALUE_HIGH 1U
#define UART_FC_RTS_SIGNAL_BITS_HIGH (UART_FC_RTS_SIGNAL_VALUE_HIGH << UART_FC_RTS_SIGNAL_SHIFT)
#endif

4
compile-with-docker.bat Normal file
View File

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

3
compile-with-docker.sh Executable file
View File

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

113
dcs.c Normal file
View File

@@ -0,0 +1,113 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "dcs.h"
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
#endif
// CTCSS Hz * 10
const uint16_t CTCSS_Options[50] = {
670, 693, 719, 744, 770, 797, 825, 854, 885, 915,
948, 974, 1000, 1035, 1072, 1109, 1148, 1188, 1230, 1273,
1318, 1365, 1413, 1462, 1514, 1567, 1598, 1622, 1655, 1679,
1713, 1738, 1773, 1799, 1835, 1862, 1899, 1928, 1966, 1995,
2035, 2065, 2107, 2181, 2257, 2291, 2336, 2418, 2503, 2541
};
const uint16_t DCS_Options[104] = {
0x0013, 0x0015, 0x0016, 0x0019, 0x001A, 0x001E, 0x0023, 0x0027,
0x0029, 0x002B, 0x002C, 0x0035, 0x0039, 0x003A, 0x003B, 0x003C,
0x004C, 0x004D, 0x004E, 0x0052, 0x0055, 0x0059, 0x005A, 0x005C,
0x0063, 0x0065, 0x006A, 0x006D, 0x006E, 0x0072, 0x0075, 0x007A,
0x007C, 0x0085, 0x008A, 0x0093, 0x0095, 0x0096, 0x00A3, 0x00A4,
0x00A5, 0x00A6, 0x00A9, 0x00AA, 0x00AD, 0x00B1, 0x00B3, 0x00B5,
0x00B6, 0x00B9, 0x00BC, 0x00C6, 0x00C9, 0x00CD, 0x00D5, 0x00D9,
0x00DA, 0x00E3, 0x00E6, 0x00E9, 0x00EE, 0x00F4, 0x00F5, 0x00F9,
0x0109, 0x010A, 0x010B, 0x0113, 0x0119, 0x011A, 0x0125, 0x0126,
0x012A, 0x012C, 0x012D, 0x0132, 0x0134, 0x0135, 0x0136, 0x0143,
0x0146, 0x014E, 0x0153, 0x0156, 0x015A, 0x0166, 0x0175, 0x0186,
0x018A, 0x0194, 0x0197, 0x0199, 0x019A, 0x01AC, 0x01B2, 0x01B4,
0x01C3, 0x01CA, 0x01D3, 0x01D9, 0x01DA, 0x01DC, 0x01E3, 0x01EC,
};
static uint32_t DCS_CalculateGolay(uint32_t CodeWord)
{
unsigned int i;
uint32_t Word = CodeWord;
for (i = 0; i < 12; i++)
{
Word <<= 1;
if (Word & 0x1000)
Word ^= 0x08EA;
}
return CodeWord | ((Word & 0x0FFE) << 11);
}
uint32_t DCS_GetGolayCodeWord(DCS_CodeType_t CodeType, uint8_t Option)
{
uint32_t Code = DCS_CalculateGolay(DCS_Options[Option] + 0x800U);
if (CodeType == CODE_TYPE_REVERSE_DIGITAL)
Code ^= 0x7FFFFF;
return Code;
}
uint8_t DCS_GetCdcssCode(uint32_t Code)
{
unsigned int i;
for (i = 0; i < 23; i++)
{
uint32_t Shift;
if (((Code >> 9) & 0x7U) == 4)
{
unsigned int j;
for (j = 0; j < ARRAY_SIZE(DCS_Options); j++)
if (DCS_Options[j] == (Code & 0x1FF))
if (DCS_GetGolayCodeWord(2, j) == Code)
return j;
}
Shift = Code >> 1;
if (Code & 1U)
Shift |= 0x400000U;
Code = Shift;
}
return 0xFF;
}
uint8_t DCS_GetCtcssCode(int Code)
{
unsigned int i;
uint8_t Result = 0xFF;
int Smallest = ARRAY_SIZE(CTCSS_Options);
for (i = 0; i < ARRAY_SIZE(CTCSS_Options); i++)
{
int Delta = Code - CTCSS_Options[i];
if (Delta < 0)
Delta = -(Code - CTCSS_Options[i]);
if (Smallest > Delta)
{
Smallest = Delta;
Result = i;
}
}
return Result;
}

45
dcs.h Normal file
View File

@@ -0,0 +1,45 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef DCS_H
#define DCS_H
#include <stdint.h>
enum DCS_CodeType_t
{
CODE_TYPE_OFF = 0,
CODE_TYPE_CONTINUOUS_TONE,
CODE_TYPE_DIGITAL,
CODE_TYPE_REVERSE_DIGITAL
};
typedef enum DCS_CodeType_t DCS_CodeType_t;
enum {
CDCSS_POSITIVE_CODE = 1U,
CDCSS_NEGATIVE_CODE = 2U,
};
extern const uint16_t CTCSS_Options[50];
extern const uint16_t DCS_Options[104];
uint32_t DCS_GetGolayCodeWord(DCS_CodeType_t CodeType, uint8_t Option);
uint8_t DCS_GetCdcssCode(uint32_t Code);
uint8_t DCS_GetCtcssCode(int Code);
#endif

48
debugging.h Normal file
View File

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

120
dp32g030.cfg Normal file
View File

@@ -0,0 +1,120 @@
transport select swd
adapter speed 32000
reset_config srst_only srst_nogate connect_assert_srst
gdb_breakpoint_override hard
set _CHIP_NAME DP32G0xx
# Create a new dap, with name chip and role CPU, -enable let's OpenOCD to know to add it to the scan
swd newdap $_CHIP_NAME cpu -enable
# Create the DAP instance, this must be explicitly created according to the OpenOCD docs
dap create $_CHIP_NAME.dap -chain-position $_CHIP_NAME.cpu
# Set up the GDB target for the CPU, cortex_m is the CPU type,
target create $_CHIP_NAME.cpu cortex_m -dap $_CHIP_NAME.dap
set _SECTOR_SIZE 512
proc uv_clear_flash_sector {sector_number} {
echo [format "Erasing sector 0x%02x = offset 0x%04x" [expr {$sector_number}] [expr {$sector_number*256}] ]
write_memory 0x4006F000 32 {0x09} ;#set erasing mode
write_memory 0x4006F004 32 [expr {$sector_number << 6}]
write_memory 0x4006F01c 32 {0xAA} ;#unlock flash
write_memory 0x4006F010 32 {0x01} ;#set OPSTART=1
read_memory 0x4006F014 32 1 ;#check status for 0x02
uv_wait_busy
write_memory 0x4006F018 32 {0x55} ;#lock flash
}
proc uv_clear_whole_flash {} {
for {set i 0} {$i < 0x100} {incr i} {
uv_clear_flash_sector $i
}
}
proc uv_clear_sectors {sectors_count} {
for {set i 0} {$i < $sectors_count} {incr i} {
uv_clear_flash_sector $i
}
}
proc uv_flash_unlock {} {
write_memory 0x4006F01c 32 {0xAA} ;#unlock flash
uv_wait_busy
}
proc uv_flash_lock {} {
write_memory 0x4006F018 32 {0x55} ;#lock flash
uv_wait_busy
}
proc uv_flash_write {address value} {
write_memory 0x4006F000 32 {0x05} ;#set writing mode
write_memory 0x4006F004 32 [expr {($address>>2)+0xC000}] ;#set address in flash
write_memory 0x4006F008 32 $value ;#set data
write_memory 0x4006F010 32 {0x01} ;#set OPSTART=1
while {1} {
set status [read_memory 0x4006F014 32 1]
if {($status & 0x4) != 0} {
break
}
}
uv_wait_busy
}
proc uv_wait_busy {} {
while {1} {
set status [read_memory 0x4006F014 32 1]
if {($status & 0x2) == 0} {
break
}
}
}
proc write_image {filename address} {
global _SECTOR_SIZE
set fs [file size $filename]
set fd [open $filename "rb"]
echo "Checking mask"
set status [read_memory 0x4006F020 32 1]
if {$status != 6} {
echo "Changing mask"
write_memory 0x4006F020 32 0
uv_wait_busy
write_memory 0x4006F020 32 6
uv_wait_busy
set status [read_memory 0x4006F020 32 1]
if {$status != 6} {
echo [format "Cannot set flash mask %d!" $status]
close $fd
return
}
}
uv_clear_sectors [expr {(($fs+$_SECTOR_SIZE-1)&(0x10000000-$_SECTOR_SIZE))/($_SECTOR_SIZE/2)}]
uv_flash_unlock
set addr $address
while {![eof $fd]} {
set data [read $fd 4]
if {[string length $data] == 4} {
set b0 [scan [string index $data 0] %c]
set b1 [scan [string index $data 1] %c]
set b2 [scan [string index $data 2] %c]
set b3 [scan [string index $data 3] %c]
set i_data [expr {$b0 | $b1 << 8 | $b2 << 16 | $b3 << 24}]
echo [format "Writing 0x%04x to address 0x%04x (%02d %%)" $i_data $addr [expr {(100*($addr+4)/$fs)}]]
uv_flash_write $addr $i_data
incr addr 4
}
}
uv_flash_lock
close $fd
}
# dap init
init
halt
# reset halt

165
driver/adc.c Normal file
View File

@@ -0,0 +1,165 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ARMCM0.h"
#include "adc.h"
#include "bsp/dp32g030/irq.h"
#include "bsp/dp32g030/saradc.h"
#include "bsp/dp32g030/syscon.h"
uint8_t ADC_GetChannelNumber(ADC_CH_MASK Mask)
{
if (Mask & ADC_CH15) return 15U;
if (Mask & ADC_CH14) return 14U;
if (Mask & ADC_CH13) return 13U;
if (Mask & ADC_CH12) return 12U;
if (Mask & ADC_CH11) return 11U;
if (Mask & ADC_CH10) return 10U;
if (Mask & ADC_CH9) return 9U;
if (Mask & ADC_CH8) return 8U;
if (Mask & ADC_CH7) return 7U;
if (Mask & ADC_CH6) return 6U;
if (Mask & ADC_CH5) return 5U;
if (Mask & ADC_CH4) return 4U;
if (Mask & ADC_CH3) return 3U;
if (Mask & ADC_CH2) return 2U;
if (Mask & ADC_CH1) return 1U;
if (Mask & ADC_CH0) return 0U;
return 0U;
}
void ADC_Disable(void)
{
SARADC_CFG = (SARADC_CFG & ~SARADC_CFG_ADC_EN_MASK) | SARADC_CFG_ADC_EN_BITS_DISABLE;
}
void ADC_Enable(void)
{
SARADC_CFG = (SARADC_CFG & ~SARADC_CFG_ADC_EN_MASK) | SARADC_CFG_ADC_EN_BITS_ENABLE;
}
void ADC_SoftReset(void)
{
SARADC_START = (SARADC_START & ~SARADC_START_SOFT_RESET_MASK) | SARADC_START_SOFT_RESET_BITS_ASSERT;
SARADC_START = (SARADC_START & ~SARADC_START_SOFT_RESET_MASK) | SARADC_START_SOFT_RESET_BITS_DEASSERT;
}
// The firmware thinks W_SARADC_SMPL_CLK_SEL is at [8:7] but the TRM says it's at [10:9]
#define FW_R_SARADC_SMPL_SHIFT 7
#define FW_R_SARADC_SMPL_MASK (3U << FW_R_SARADC_SMPL_SHIFT)
uint32_t ADC_GetClockConfig(void)
{
uint32_t Value;
Value = SYSCON_CLK_SEL;
Value = 0
| (Value & ~(SYSCON_CLK_SEL_R_PLL_MASK | FW_R_SARADC_SMPL_MASK))
| (((Value & SYSCON_CLK_SEL_R_PLL_MASK) >> SYSCON_CLK_SEL_R_PLL_SHIFT) << SYSCON_CLK_SEL_W_PLL_SHIFT)
| (((Value & FW_R_SARADC_SMPL_MASK) >> FW_R_SARADC_SMPL_SHIFT) << SYSCON_CLK_SEL_W_SARADC_SMPL_SHIFT)
;
return Value;
}
void ADC_Configure(ADC_Config_t *pAdc)
{
SYSCON_DEV_CLK_GATE = (SYSCON_DEV_CLK_GATE & ~SYSCON_DEV_CLK_GATE_SARADC_MASK) | SYSCON_DEV_CLK_GATE_SARADC_BITS_ENABLE;
ADC_Disable();
SYSCON_CLK_SEL = (ADC_GetClockConfig() & ~SYSCON_CLK_SEL_W_SARADC_SMPL_MASK) | ((pAdc->CLK_SEL << SYSCON_CLK_SEL_W_SARADC_SMPL_SHIFT) & SYSCON_CLK_SEL_W_SARADC_SMPL_MASK);
SARADC_CFG = 0
| (SARADC_CFG & ~(0
| SARADC_CFG_CH_SEL_MASK
| SARADC_CFG_AVG_MASK
| SARADC_CFG_CONT_MASK
| SARADC_CFG_SMPL_SETUP_MASK
| SARADC_CFG_MEM_MODE_MASK
| SARADC_CFG_SMPL_CLK_MASK
| SARADC_CFG_SMPL_WIN_MASK
| SARADC_CFG_ADC_TRIG_MASK
| SARADC_CFG_DMA_EN_MASK
))
| ((pAdc->CH_SEL << SARADC_CFG_CH_SEL_SHIFT) & SARADC_CFG_CH_SEL_MASK)
| ((pAdc->AVG << SARADC_CFG_AVG_SHIFT) & SARADC_CFG_AVG_MASK)
| ((pAdc->CONT << SARADC_CFG_CONT_SHIFT) & SARADC_CFG_CONT_MASK)
| ((pAdc->SMPL_SETUP << SARADC_CFG_SMPL_SETUP_SHIFT) & SARADC_CFG_SMPL_SETUP_MASK)
| ((pAdc->MEM_MODE << SARADC_CFG_MEM_MODE_SHIFT) & SARADC_CFG_MEM_MODE_MASK)
| ((pAdc->SMPL_CLK << SARADC_CFG_SMPL_CLK_SHIFT) & SARADC_CFG_SMPL_CLK_MASK)
| ((pAdc->SMPL_WIN << SARADC_CFG_SMPL_WIN_SHIFT) & SARADC_CFG_SMPL_WIN_MASK)
| ((pAdc->ADC_TRIG << SARADC_CFG_ADC_TRIG_SHIFT) & SARADC_CFG_ADC_TRIG_MASK)
| ((pAdc->DMA_EN << SARADC_CFG_DMA_EN_SHIFT) & SARADC_CFG_DMA_EN_MASK)
;
SARADC_EXTTRIG_SEL = pAdc->EXTTRIG_SEL;
if (pAdc->CALIB_OFFSET_VALID) {
SARADC_CALIB_OFFSET = (SARADC_CALIB_OFFSET & ~SARADC_CALIB_OFFSET_VALID_MASK) | SARADC_CALIB_OFFSET_VALID_BITS_YES;
} else {
SARADC_CALIB_OFFSET = (SARADC_CALIB_OFFSET & ~SARADC_CALIB_OFFSET_VALID_MASK) | SARADC_CALIB_OFFSET_VALID_BITS_NO;
}
if (pAdc->CALIB_KD_VALID) {
SARADC_CALIB_KD = (SARADC_CALIB_KD & ~SARADC_CALIB_KD_VALID_MASK) | SARADC_CALIB_KD_VALID_BITS_YES;
} else {
SARADC_CALIB_KD = (SARADC_CALIB_KD & ~SARADC_CALIB_KD_VALID_MASK) | SARADC_CALIB_KD_VALID_BITS_NO;
}
SARADC_IF = 0xFFFFFFFF;
SARADC_IE = 0
| (SARADC_IE & ~(0
| SARADC_IE_CHx_EOC_MASK
| SARADC_IE_FIFO_FULL_MASK
| SARADC_IE_FIFO_HFULL_MASK
))
| ((pAdc->IE_CHx_EOC << SARADC_IE_CHx_EOC_SHIFT) & SARADC_IE_CHx_EOC_MASK)
| ((pAdc->IE_FIFO_FULL << SARADC_IE_FIFO_FULL_SHIFT) & SARADC_IE_FIFO_FULL_MASK)
| ((pAdc->IE_FIFO_HFULL << SARADC_IE_FIFO_HFULL_SHIFT) & SARADC_IE_FIFO_HFULL_MASK)
;
if (SARADC_IE == 0) {
NVIC_DisableIRQ((IRQn_Type)DP32_SARADC_IRQn);
} else {
NVIC_EnableIRQ((IRQn_Type)DP32_SARADC_IRQn);
}
}
void ADC_Start(void)
{
SARADC_START = (SARADC_START & ~SARADC_START_START_MASK) | SARADC_START_START_BITS_ENABLE;
}
bool ADC_CheckEndOfConversion(ADC_CH_MASK Mask)
{
volatile ADC_Channel_t *pChannels = (volatile ADC_Channel_t *)&SARADC_CH0;
uint8_t Channel = ADC_GetChannelNumber(Mask);
return (pChannels[Channel].STAT & ADC_CHx_STAT_EOC_MASK) >> ADC_CHx_STAT_EOC_SHIFT;
}
uint16_t ADC_GetValue(ADC_CH_MASK Mask)
{
volatile ADC_Channel_t *pChannels = (volatile ADC_Channel_t *)&SARADC_CH0;
uint8_t Channel = ADC_GetChannelNumber(Mask);
SARADC_IF = 1 << Channel; // TODO: Or just use 'Mask'
return (pChannels[Channel].DATA & ADC_CHx_DATA_DATA_MASK) >> ADC_CHx_DATA_DATA_SHIFT;
}

75
driver/adc.h Normal file
View File

@@ -0,0 +1,75 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef DRIVER_ADC_H
#define DRIVER_ADC_H
#include <stdbool.h>
#include <stdint.h>
enum ADC_CH_MASK {
ADC_CH0 = 0x0001U,
ADC_CH1 = 0x0002U,
ADC_CH2 = 0x0004U,
ADC_CH3 = 0x0008U,
ADC_CH4 = 0x0010U,
ADC_CH5 = 0x0020U,
ADC_CH6 = 0x0040U,
ADC_CH7 = 0x0080U,
ADC_CH8 = 0x0100U,
ADC_CH9 = 0x0200U,
ADC_CH10 = 0x0400U,
ADC_CH11 = 0x0800U,
ADC_CH12 = 0x1000U,
ADC_CH13 = 0x2000U,
ADC_CH14 = 0x4000U,
ADC_CH15 = 0x8000U,
};
typedef enum ADC_CH_MASK ADC_CH_MASK;
typedef struct {
uint16_t EXTTRIG_SEL;
uint16_t IE_CHx_EOC;
ADC_CH_MASK CH_SEL;
uint8_t CLK_SEL;
uint8_t AVG;
uint8_t CONT;
uint8_t MEM_MODE;
uint8_t SMPL_CLK;
uint8_t SMPL_SETUP;
uint8_t SMPL_WIN;
uint8_t ADC_TRIG;
uint8_t DMA_EN;
uint8_t IE_FIFO_HFULL;
uint8_t IE_FIFO_FULL;
bool CALIB_OFFSET_VALID;
bool CALIB_KD_VALID;
uint8_t _pad[1];
} ADC_Config_t;
uint8_t ADC_GetChannelNumber(ADC_CH_MASK Mask);
void ADC_Disable(void);
void ADC_Enable(void);
void ADC_SoftReset(void);
uint32_t ADC_GetClockConfig(void);
void ADC_Configure(ADC_Config_t *pAdc);
void ADC_Start(void);
bool ADC_CheckEndOfConversion(ADC_CH_MASK Mask);
uint16_t ADC_GetValue(ADC_CH_MASK Mask);
#endif

74
driver/aes.c Normal file
View File

@@ -0,0 +1,74 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdbool.h>
#include "bsp/dp32g030/aes.h"
#include "driver/aes.h"
static void AES_Setup_ENC_CBC(bool IsDecrypt, const void *pKey, const void *pIv)
{
const uint32_t *pK = (const uint32_t *)pKey;
const uint32_t *pI = (const uint32_t *)pIv;
(void)IsDecrypt; // unused
AES_CR = (AES_CR & ~AES_CR_EN_MASK) | AES_CR_EN_BITS_DISABLE;
AES_CR = AES_CR_CHMOD_BITS_CBC;
AES_KEYR3 = pK[0];
AES_KEYR2 = pK[1];
AES_KEYR1 = pK[2];
AES_KEYR0 = pK[3];
AES_IVR3 = pI[0];
AES_IVR2 = pI[1];
AES_IVR1 = pI[2];
AES_IVR0 = pI[3];
AES_CR = (AES_CR & ~AES_CR_EN_MASK) | AES_CR_EN_BITS_ENABLE;
}
static void AES_Transform(const void *pIn, void *pOut)
{
const uint32_t *pI = (const uint32_t *)pIn;
uint32_t *pO = (uint32_t *)pOut;
AES_DINR = pI[0];
AES_DINR = pI[1];
AES_DINR = pI[2];
AES_DINR = pI[3];
while ((AES_SR & AES_SR_CCF_MASK) == AES_SR_CCF_BITS_NOT_COMPLETE) {
}
pO[0] = AES_DOUTR;
pO[1] = AES_DOUTR;
pO[2] = AES_DOUTR;
pO[3] = AES_DOUTR;
AES_CR |= AES_CR_CCFC_BITS_SET;
}
void AES_Encrypt(const void *pKey, const void *pIv, const void *pIn, void *pOut, uint8_t NumBlocks)
{
const uint8_t *pI = (const uint8_t *)pIn;
uint8_t *pO = (uint8_t *)pOut;
uint8_t i;
AES_Setup_ENC_CBC(0, pKey, pIv);
for (i = 0; i < NumBlocks; i++) {
AES_Transform(pI + (i * 16), pO + (i * 16));
}
}

25
driver/aes.h Normal file
View File

@@ -0,0 +1,25 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef DRIVER_AES_H
#define DRIVER_AES_H
#include <stdint.h>
void AES_Encrypt(const void *pKey, const void *pIv, const void *pIn, void *pOut, uint8_t NumBlocks);
#endif

118
driver/backlight.c Normal file
View File

@@ -0,0 +1,118 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "backlight.h"
#include "bsp/dp32g030/gpio.h"
#include "bsp/dp32g030/pwmplus.h"
#include "bsp/dp32g030/portcon.h"
#include "driver/gpio.h"
#include "settings.h"
// this is decremented once every 500ms
uint16_t gBacklightCountdown_500ms = 0;
bool backlightOn;
void BACKLIGHT_InitHardware()
{
// 48MHz / 94 / 1024 ~ 500Hz
const uint32_t PWM_FREQUENCY_HZ = 1000;
PWM_PLUS0_CLKSRC |= ((48000000 / 1024 / PWM_FREQUENCY_HZ) << 16);
PWM_PLUS0_PERIOD = 1023;
PORTCON_PORTB_SEL0 &= ~(0
// Back light
| PORTCON_PORTB_SEL0_B6_MASK
);
PORTCON_PORTB_SEL0 |= 0
// Back light PWM
| PORTCON_PORTB_SEL0_B6_BITS_PWMP0_CH0
;
PWM_PLUS0_GEN =
PWMPLUS_GEN_CH0_OE_BITS_ENABLE |
PWMPLUS_GEN_CH0_OUTINV_BITS_ENABLE |
0;
PWM_PLUS0_CFG =
PWMPLUS_CFG_CNT_REP_BITS_ENABLE |
PWMPLUS_CFG_COUNTER_EN_BITS_ENABLE |
0;
}
void BACKLIGHT_TurnOn(void)
{
if (gEeprom.BACKLIGHT_TIME == 0) {
BACKLIGHT_TurnOff();
return;
}
backlightOn = true;
BACKLIGHT_SetBrightness(gEeprom.BACKLIGHT_MAX);
switch (gEeprom.BACKLIGHT_TIME) {
default:
case 1: // 5 sec
case 2: // 10 sec
case 3: // 20 sec
gBacklightCountdown_500ms = 1 + (2 << (gEeprom.BACKLIGHT_TIME - 1)) * 5;
break;
case 4: // 1 min
case 5: // 2 min
case 6: // 4 min
gBacklightCountdown_500ms = 1 + (2 << (gEeprom.BACKLIGHT_TIME - 4)) * 60;
break;
case 7: // always on
gBacklightCountdown_500ms = 0;
break;
}
}
void BACKLIGHT_TurnOff()
{
#ifdef ENABLE_BLMIN_TMP_OFF
register uint8_t tmp;
if (gEeprom.BACKLIGHT_MIN_STAT == BLMIN_STAT_ON)
tmp = gEeprom.BACKLIGHT_MIN;
else
tmp = 0;
BACKLIGHT_SetBrightness(tmp);
#else
BACKLIGHT_SetBrightness(gEeprom.BACKLIGHT_MIN);
#endif
gBacklightCountdown_500ms = 0;
backlightOn = false;
}
bool BACKLIGHT_IsOn()
{
return backlightOn;
}
static uint8_t currentBrightness;
void BACKLIGHT_SetBrightness(uint8_t brigtness)
{
currentBrightness = brigtness;
PWM_PLUS0_CH0_COMP = (1 << brigtness) - 1;
//PWM_PLUS0_SWLOAD = 1;
}
uint8_t BACKLIGHT_GetBrightness(void)
{
return currentBrightness;
}

41
driver/backlight.h Normal file
View File

@@ -0,0 +1,41 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef DRIVER_BACKLIGHT_H
#define DRIVER_BACKLIGHT_H
#include <stdint.h>
#include <stdbool.h>
extern uint16_t gBacklightCountdown_500ms;
extern uint8_t gBacklightBrightness;
#ifdef ENABLE_BLMIN_TMP_OFF
typedef enum {
BLMIN_STAT_ON,
BLMIN_STAT_OFF,
BLMIN_STAT_UNKNOWN
} BLMIN_STAT_t;
#endif
void BACKLIGHT_InitHardware();
void BACKLIGHT_TurnOn();
void BACKLIGHT_TurnOff();
bool BACKLIGHT_IsOn();
void BACKLIGHT_SetBrightness(uint8_t brigtness);
uint8_t BACKLIGHT_GetBrightness(void);
#endif

57
driver/bk1080-regs.h Normal file
View File

@@ -0,0 +1,57 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef BK1080_REGS_H
#define BK1080_REGS_H
enum BK1080_Register_t {
BK1080_REG_00 = 0x00U,
BK1080_REG_02_POWER_CONFIGURATION = 0x02U,
BK1080_REG_03_CHANNEL = 0x03U,
BK1080_REG_05_SYSTEM_CONFIGURATION2 = 0x05U,
BK1080_REG_07 = 0x07U,
BK1080_REG_10 = 0x0AU,
BK1080_REG_25_INTERNAL = 0x19U,
};
typedef enum BK1080_Register_t BK1080_Register_t;
// REG 07
#define BK1080_REG_07_SHIFT_FREQD 4
#define BK1080_REG_07_SHIFT_SNR 0
#define BK1080_REG_07_MASK_FREQD (0xFFFU << BK1080_REG_07_SHIFT_FREQD)
#define BK1080_REG_07_MASK_SNR (0x00FU << BK1080_REG_07_SHIFT_SNR)
#define BK1080_REG_07_GET_FREQD(x) (((x) & BK1080_REG_07_MASK_FREQD) >> BK1080_REG_07_SHIFT_FREQD)
#define BK1080_REG_07_GET_SNR(x) (((x) & BK1080_REG_07_MASK_SNR) >> BK1080_REG_07_SHIFT_SNR)
// REG 10
#define BK1080_REG_10_SHIFT_AFCRL 12
#define BK1080_REG_10_SHIFT_RSSI 0
#define BK1080_REG_10_MASK_AFCRL (0x01U << BK1080_REG_10_SHIFT_AFCRL)
#define BK1080_REG_10_MASK_RSSI (0xFFU << BK1080_REG_10_SHIFT_RSSI)
#define BK1080_REG_10_AFCRL_NOT_RAILED (0U << BK1080_REG_10_SHIFT_AFCRL)
#define BK1080_REG_10_AFCRL_RAILED (1U << BK1080_REG_10_SHIFT_AFCRL)
#define BK1080_REG_10_GET_RSSI(x) (((x) & BK1080_REG_10_MASK_RSSI) >> BK1080_REG_10_SHIFT_RSSI)
#endif

144
driver/bk1080.c Normal file
View File

@@ -0,0 +1,144 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "bsp/dp32g030/gpio.h"
#include "bk1080.h"
#include "driver/gpio.h"
#include "driver/i2c.h"
#include "driver/system.h"
#include "misc.h"
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
#endif
static const uint16_t BK1080_RegisterTable[] =
{
0x0008, 0x1080, 0x0201, 0x0000, 0x40C0, 0x0A1F, 0x002E, 0x02FF,
0x5B11, 0x0000, 0x411E, 0x0000, 0xCE00, 0x0000, 0x0000, 0x1000,
0x3197, 0x0000, 0x13FF, 0x9852, 0x0000, 0x0000, 0x0008, 0x0000,
0x51E1, 0xA8BC, 0x2645, 0x00E4, 0x1CD8, 0x3A50, 0xEAE0, 0x3000,
0x0200, 0x0000,
};
static bool gIsInitBK1080;
uint16_t BK1080_BaseFrequency;
uint16_t BK1080_FrequencyDeviation;
void BK1080_Init0(void)
{
BK1080_Init(0,0/*,0*/);
}
void BK1080_Init(uint16_t freq, uint8_t band/*, uint8_t space*/)
{
unsigned int i;
if (freq) {
GPIO_ClearBit(&GPIOB->DATA, GPIOB_PIN_BK1080);
if (!gIsInitBK1080) {
for (i = 0; i < ARRAY_SIZE(BK1080_RegisterTable); i++)
BK1080_WriteRegister(i, BK1080_RegisterTable[i]);
SYSTEM_DelayMs(250);
BK1080_WriteRegister(BK1080_REG_25_INTERNAL, 0xA83C);
BK1080_WriteRegister(BK1080_REG_25_INTERNAL, 0xA8BC);
SYSTEM_DelayMs(60);
gIsInitBK1080 = true;
}
else {
BK1080_WriteRegister(BK1080_REG_02_POWER_CONFIGURATION, 0x0201);
}
BK1080_WriteRegister(BK1080_REG_05_SYSTEM_CONFIGURATION2, 0x0A1F);
BK1080_SetFrequency(freq, band/*, space*/);
}
else {
BK1080_WriteRegister(BK1080_REG_02_POWER_CONFIGURATION, 0x0241);
GPIO_SetBit(&GPIOB->DATA, GPIOB_PIN_BK1080);
}
}
uint16_t BK1080_ReadRegister(BK1080_Register_t Register)
{
uint8_t Value[2];
I2C_Start();
I2C_Write(0x80);
I2C_Write((Register << 1) | I2C_READ);
I2C_ReadBuffer(Value, sizeof(Value));
I2C_Stop();
return (Value[0] << 8) | Value[1];
}
void BK1080_WriteRegister(BK1080_Register_t Register, uint16_t Value)
{
I2C_Start();
I2C_Write(0x80);
I2C_Write((Register << 1) | I2C_WRITE);
Value = ((Value >> 8) & 0xFF) | ((Value & 0xFF) << 8);
I2C_WriteBuffer(&Value, sizeof(Value));
I2C_Stop();
}
void BK1080_Mute(bool Mute)
{
BK1080_WriteRegister(BK1080_REG_02_POWER_CONFIGURATION, Mute ? 0x4201 : 0x0201);
}
void BK1080_SetFrequency(uint16_t frequency, uint8_t band/*, uint8_t space*/)
{
//uint8_t spacings[] = {20,10,5};
//space %= 3;
uint16_t channel = (frequency - BK1080_GetFreqLoLimit(band))/* * 10 / spacings[space]*/;
uint16_t regval = BK1080_ReadRegister(BK1080_REG_05_SYSTEM_CONFIGURATION2);
regval = (regval & ~(0b11 << 6)) | ((band & 0b11) << 6);
//regval = (regval & ~(0b11 << 4)) | ((space & 0b11) << 4);
BK1080_WriteRegister(BK1080_REG_05_SYSTEM_CONFIGURATION2, regval);
BK1080_WriteRegister(BK1080_REG_03_CHANNEL, channel);
SYSTEM_DelayMs(10);
BK1080_WriteRegister(BK1080_REG_03_CHANNEL, channel | 0x8000);
}
void BK1080_GetFrequencyDeviation(uint16_t Frequency)
{
BK1080_BaseFrequency = Frequency;
BK1080_FrequencyDeviation = BK1080_ReadRegister(BK1080_REG_07) / 16;
}
uint16_t BK1080_GetFreqLoLimit(uint8_t band)
{
uint16_t lim[] = {875, 760, 760, 640};
return lim[band % 4];
}
uint16_t BK1080_GetFreqHiLimit(uint8_t band)
{
band %= 4;
uint16_t lim[] = {1080, 1080, 900, 760};
return lim[band % 4];
}

38
driver/bk1080.h Normal file
View File

@@ -0,0 +1,38 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef DRIVER_BK1080_H
#define DRIVER_BK1080_H
#include <stdbool.h>
#include <stdint.h>
#include "driver/bk1080-regs.h"
extern uint16_t BK1080_BaseFrequency;
extern uint16_t BK1080_FrequencyDeviation;
void BK1080_Init0(void);
void BK1080_Init(uint16_t Frequency, uint8_t band/*, uint8_t space*/);
uint16_t BK1080_ReadRegister(BK1080_Register_t Register);
void BK1080_WriteRegister(BK1080_Register_t Register, uint16_t Value);
void BK1080_Mute(bool Mute);
uint16_t BK1080_GetFreqLoLimit(uint8_t band);
uint16_t BK1080_GetFreqHiLimit(uint8_t band);
void BK1080_SetFrequency(uint16_t frequency, uint8_t band/*, uint8_t space*/);
void BK1080_GetFrequencyDeviation(uint16_t Frequency);
#endif

390
driver/bk4819-regs.h Normal file
View File

@@ -0,0 +1,390 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef BK4819_REGS_H
#define BK4819_REGS_H
#include <stdint.h>
typedef struct {
const char *name;
uint8_t num;
uint8_t offset;
uint16_t mask;
uint16_t inc;
} RegisterSpec;
static const RegisterSpec afcDisableRegSpec = {"AFC Disable", 0x73, 4, 1, 1};
static const RegisterSpec afOutRegSpec = {"AF Output Select", 0x47, 8, 0xF, 1};
static const RegisterSpec afDacGainRegSpec = {"AF DAC Gain", 0x48, 0, 0xF, 1};
enum BK4819_REGISTER_t {
BK4819_REG_00 = 0x00U,
BK4819_REG_02 = 0x02U,
BK4819_REG_06 = 0x06U,
BK4819_REG_07 = 0x07U,
BK4819_REG_08 = 0x08U,
BK4819_REG_09 = 0x09U,
BK4819_REG_0B = 0x0BU,
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,
BK4819_REG_20 = 0x20U,
BK4819_REG_21 = 0x21U,
BK4819_REG_24 = 0x24U,
BK4819_REG_28 = 0x28U,
BK4819_REG_29 = 0x29U,
BK4819_REG_2B = 0x2BU,
BK4819_REG_30 = 0x30U,
BK4819_REG_31 = 0x31U,
BK4819_REG_32 = 0x32U,
BK4819_REG_33 = 0x33U,
BK4819_REG_36 = 0x36U,
BK4819_REG_37 = 0x37U,
BK4819_REG_38 = 0x38U,
BK4819_REG_39 = 0x39U,
BK4819_REG_3A = 0x3AU,
BK4819_REG_3B = 0x3BU,
BK4819_REG_3C = 0x3CU,
BK4819_REG_3D = 0x3DU,
BK4819_REG_3E = 0x3EU,
BK4819_REG_3F = 0x3FU,
BK4819_REG_43 = 0x43U,
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,
BK4819_REG_4F = 0x4FU,
BK4819_REG_50 = 0x50U,
BK4819_REG_51 = 0x51U,
BK4819_REG_52 = 0x52U,
BK4819_REG_58 = 0x58U,
BK4819_REG_59 = 0x59U,
BK4819_REG_5A = 0x5AU,
BK4819_REG_5B = 0x5BU,
BK4819_REG_5C = 0x5CU,
BK4819_REG_5D = 0x5DU,
BK4819_REG_5F = 0x5FU,
BK4819_REG_63 = 0x63U,
BK4819_REG_64 = 0x64U,
BK4819_REG_65 = 0x65U,
BK4819_REG_67 = 0x67U,
BK4819_REG_68 = 0x68U,
BK4819_REG_69 = 0x69U,
BK4819_REG_6A = 0x6AU,
BK4819_REG_6F = 0x6FU,
BK4819_REG_70 = 0x70U,
BK4819_REG_71 = 0x71U,
BK4819_REG_72 = 0x72U,
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,
};
typedef enum BK4819_REGISTER_t BK4819_REGISTER_t;
enum BK4819_GPIO_PIN_t {
BK4819_GPIO0_PIN28_RX_ENABLE = 0,
BK4819_GPIO1_PIN29_PA_ENABLE = 1,
BK4819_GPIO3_PIN31_UHF_LNA = 3,
BK4819_GPIO4_PIN32_VHF_LNA = 4,
BK4819_GPIO5_PIN1_RED = 5,
BK4819_GPIO6_PIN2_GREEN = 6,
};
typedef enum BK4819_GPIO_PIN_t BK4819_GPIO_PIN_t;
// REG 02
#define BK4819_REG_02_SHIFT_FSK_TX_FINISHED 15
#define BK4819_REG_02_SHIFT_FSK_FIFO_ALMOST_EMPTY 14
#define BK4819_REG_02_SHIFT_FSK_RX_FINISHED 13
#define BK4819_REG_02_SHIFT_FSK_FIFO_ALMOST_FULL 12
#define BK4819_REG_02_SHIFT_DTMF_5TONE_FOUND 11
#define BK4819_REG_02_SHIFT_CxCSS_TAIL 10
#define BK4819_REG_02_SHIFT_CDCSS_FOUND 9
#define BK4819_REG_02_SHIFT_CDCSS_LOST 8
#define BK4819_REG_02_SHIFT_CTCSS_FOUND 7
#define BK4819_REG_02_SHIFT_CTCSS_LOST 6
#define BK4819_REG_02_SHIFT_VOX_FOUND 5
#define BK4819_REG_02_SHIFT_VOX_LOST 4
#define BK4819_REG_02_SHIFT_SQUELCH_FOUND 3
#define BK4819_REG_02_SHIFT_SQUELCH_LOST 2
#define BK4819_REG_02_SHIFT_FSK_RX_SYNC 1
#define BK4819_REG_02_MASK_FSK_TX_FINISHED (1U << BK4819_REG_02_SHIFT_FSK_TX)
#define BK4819_REG_02_MASK_FSK_FIFO_ALMOST_EMPTY (1U << BK4819_REG_02_SHIFT_FSK_FIFO_ALMOST_EMPTY)
#define BK4819_REG_02_MASK_FSK_RX_FINISHED (1U << BK4819_REG_02_SHIFT_FSK_RX_FINISHED)
#define BK4819_REG_02_MASK_FSK_FIFO_ALMOST_FULL (1U << BK4819_REG_02_SHIFT_FSK_FIFO_ALMOST_FULL)
#define BK4819_REG_02_MASK_DTMF_5TONE_FOUND (1U << BK4819_REG_02_SHIFT_DTMF_5TONE_FOUND)
#define BK4819_REG_02_MASK_CxCSS_TAIL (1U << BK4819_REG_02_SHIFT_CxCSS_TAIL)
#define BK4819_REG_02_MASK_CDCSS_FOUND (1U << BK4819_REG_02_SHIFT_CDCSS_FOUND)
#define BK4819_REG_02_MASK_CDCSS_LOST (1U << BK4819_REG_02_SHIFT_CDCSS_LOST)
#define BK4819_REG_02_MASK_CTCSS_FOUND (1U << BK4819_REG_02_SHIFT_CTCSS_FOUND)
#define BK4819_REG_02_MASK_CTCSS_LOST (1U << BK4819_REG_02_SHIFT_CTCSS_LOST)
#define BK4819_REG_02_MASK_VOX_FOUND (1U << BK4819_REG_02_SHIFT_VOX_FOUND)
#define BK4819_REG_02_MASK_VOX_LOST (1U << BK4819_REG_02_SHIFT_VOX_LOST)
#define BK4819_REG_02_MASK_SQUELCH_FOUND (1U << BK4819_REG_02_SHIFT_SQUELCH_FOUND)
#define BK4819_REG_02_MASK_SQUELCH_LOST (1U << BK4819_REG_02_SHIFT_SQUELCH_LOST)
#define BK4819_REG_02_MASK_FSK_RX_SYNC (1U << BK4819_REG_02_SHIFT_FSK_RX_SYNC)
#define BK4819_REG_02_FSK_TX_FINISHED (1U << BK4819_REG_02_SHIFT_FSK_TX_FINISHED)
#define BK4819_REG_02_FSK_FIFO_ALMOST_EMPTY (1U << BK4819_REG_02_SHIFT_FSK_FIFO_ALMOST_EMPTY)
#define BK4819_REG_02_FSK_RX_FINISHED (1U << BK4819_REG_02_SHIFT_FSK_RX_FINISHED)
#define BK4819_REG_02_FSK_FIFO_ALMOST_FULL (1U << BK4819_REG_02_SHIFT_FSK_FIFO_ALMOST_FULL)
#define BK4819_REG_02_DTMF_5TONE_FOUND (1U << BK4819_REG_02_SHIFT_DTMF_5TONE_FOUND)
#define BK4819_REG_02_CxCSS_TAIL (1U << BK4819_REG_02_SHIFT_CxCSS_TAIL)
#define BK4819_REG_02_CDCSS_FOUND (1U << BK4819_REG_02_SHIFT_CDCSS_FOUND)
#define BK4819_REG_02_CDCSS_LOST (1U << BK4819_REG_02_SHIFT_CDCSS_LOST)
#define BK4819_REG_02_CTCSS_FOUND (1U << BK4819_REG_02_SHIFT_CTCSS_FOUND)
#define BK4819_REG_02_CTCSS_LOST (1U << BK4819_REG_02_SHIFT_CTCSS_LOST)
#define BK4819_REG_02_VOX_FOUND (1U << BK4819_REG_02_SHIFT_VOX_FOUND)
#define BK4819_REG_02_VOX_LOST (1U << BK4819_REG_02_SHIFT_VOX_LOST)
#define BK4819_REG_02_SQUELCH_FOUND (1U << BK4819_REG_02_SHIFT_SQUELCH_FOUND)
#define BK4819_REG_02_SQUELCH_LOST (1U << BK4819_REG_02_SHIFT_SQUELCH_LOST)
#define BK4819_REG_02_FSK_RX_SYNC (1U << BK4819_REG_02_SHIFT_FSK_RX_SYNC)
// REG 07
#define BK4819_REG_07_SHIFT_FREQUENCY_MODE 13
#define BK4819_REG_07_SHIFT_FREQUENCY 0
#define BK4819_REG_07_MASK_FREQUENCY_MODE (0x0007U << BK4819_REG_07_SHIFT_FREQUENCY_MODE)
#define BK4819_REG_07_MASK_FREQUENCY (0x1FFFU << BK4819_REG_07_SHIFT_FREQUENCY)
#define BK4819_REG_07_MODE_CTC1 (0U << BK4819_REG_07_SHIFT_FREQUENCY_MODE)
#define BK4819_REG_07_MODE_CTC2 (1U << BK4819_REG_07_SHIFT_FREQUENCY_MODE)
#define BK4819_REG_07_MODE_CDCSS (2U << BK4819_REG_07_SHIFT_FREQUENCY_MODE)
// REG 24
#define BK4819_REG_24_SHIFT_UNKNOWN_15 15
#define BK4819_REG_24_SHIFT_THRESHOLD 7
#define BK4819_REG_24_SHIFT_UNKNOWN_6 6
#define BK4819_REG_24_SHIFT_ENABLE 5
#define BK4819_REG_24_SHIFT_SELECT 4
#define BK4819_REG_24_SHIFT_MAX_SYMBOLS 0
#define BK4819_REG_24_MASK_THRESHOLD (0x2Fu << BK4819_REG_24_SHIFT_THRESHOLD)
#define BK4819_REG_24_MASK_ENABLE (0x01u << BK4819_REG_24_SHIFT_ENABLE)
#define BK4819_REG_24_MASK_SELECT (0x04u << BK4819_REG_24_SHIFT_SELECT)
#define BK4819_REG_24_MASK_MAX_SYMBOLS (0x0Fu << BK4819_REG_24_SHIFT_MAX_SYMBOLS)
#define BK4819_REG_24_ENABLE (1u << BK4819_REG_24_SHIFT_ENABLE)
#define BK4819_REG_24_DISABLE (0u << BK4819_REG_24_SHIFT_ENABLE)
#define BK4819_REG_24_SELECT_DTMF (1u << BK4819_REG_24_SHIFT_SELECT)
#define BK4819_REG_24_SELECT_SELCALL (0u << BK4819_REG_24_SHIFT_SELECT)
// REG 30
#define BK4819_REG_30_SHIFT_ENABLE_VCO_CALIB 15
#define BK4819_REG_30_SHIFT_ENABLE_UNKNOWN 14
#define BK4819_REG_30_SHIFT_ENABLE_RX_LINK 10
#define BK4819_REG_30_SHIFT_ENABLE_AF_DAC 9
#define BK4819_REG_30_SHIFT_ENABLE_DISC_MODE 8
#define BK4819_REG_30_SHIFT_ENABLE_PLL_VCO 4
#define BK4819_REG_30_SHIFT_ENABLE_PA_GAIN 3
#define BK4819_REG_30_SHIFT_ENABLE_MIC_ADC 2
#define BK4819_REG_30_SHIFT_ENABLE_TX_DSP 1
#define BK4819_REG_30_SHIFT_ENABLE_RX_DSP 0
#define BK4819_REG_30_MASK_ENABLE_VCO_CALIB (0x1U << BK4819_REG_30_SHIFT_ENABLE_VCO_CALIB)
#define BK4819_REG_30_MASK_ENABLE_UNKNOWN (0x1U << BK4819_REG_30_SHIFT_ENABLE_UNKNOWN)
#define BK4819_REG_30_MASK_ENABLE_RX_LINK (0xFU << BK4819_REG_30_SHIFT_ENABLE_RX_LINK)
#define BK4819_REG_30_MASK_ENABLE_AF_DAC (0x1U << BK4819_REG_30_SHIFT_ENABLE_AF_DAC)
#define BK4819_REG_30_MASK_ENABLE_DISC_MODE (0x1U << BK4819_REG_30_SHIFT_ENABLE_DISC_MODE)
#define BK4819_REG_30_MASK_ENABLE_PLL_VCO (0xFU << BK4819_REG_30_SHIFT_ENABLE_PLL_VCO)
#define BK4819_REG_30_MASK_ENABLE_PA_GAIN (0x1U << BK4819_REG_30_SHIFT_ENABLE_PA_GAIN)
#define BK4819_REG_30_MASK_ENABLE_MIC_ADC (0x1U << BK4819_REG_30_SHIFT_ENABLE_MIC_ADC)
#define BK4819_REG_30_MASK_ENABLE_TX_DSP (0x1U << BK4819_REG_30_SHIFT_ENABLE_TX_DSP)
#define BK4819_REG_30_MASK_ENABLE_RX_DSP (0x1U << BK4819_REG_30_SHIFT_ENABLE_RX_DSP)
enum {
BK4819_REG_30_ENABLE_VCO_CALIB = (0x1U << BK4819_REG_30_SHIFT_ENABLE_VCO_CALIB),
BK4819_REG_30_DISABLE_VCO_CALIB = (0x0U << BK4819_REG_30_SHIFT_ENABLE_VCO_CALIB),
BK4819_REG_30_ENABLE_UNKNOWN = (0x1U << BK4819_REG_30_SHIFT_ENABLE_UNKNOWN),
BK4819_REG_30_DISABLE_UNKNOWN = (0x0U << BK4819_REG_30_SHIFT_ENABLE_UNKNOWN),
BK4819_REG_30_ENABLE_RX_LINK = (0xFU << BK4819_REG_30_SHIFT_ENABLE_RX_LINK),
BK4819_REG_30_DISABLE_RX_LINK = (0x0U << BK4819_REG_30_SHIFT_ENABLE_RX_LINK),
BK4819_REG_30_ENABLE_AF_DAC = (0x1U << BK4819_REG_30_SHIFT_ENABLE_AF_DAC),
BK4819_REG_30_DISABLE_AF_DAC = (0x0U << BK4819_REG_30_SHIFT_ENABLE_AF_DAC),
BK4819_REG_30_ENABLE_DISC_MODE = (0x1U << BK4819_REG_30_SHIFT_ENABLE_DISC_MODE),
BK4819_REG_30_DISABLE_DISC_MODE = (0x0U << BK4819_REG_30_SHIFT_ENABLE_DISC_MODE),
BK4819_REG_30_ENABLE_PLL_VCO = (0xFU << BK4819_REG_30_SHIFT_ENABLE_PLL_VCO),
BK4819_REG_30_DISABLE_PLL_VCO = (0x0U << BK4819_REG_30_SHIFT_ENABLE_PLL_VCO),
BK4819_REG_30_ENABLE_PA_GAIN = (0x1U << BK4819_REG_30_SHIFT_ENABLE_PA_GAIN),
BK4819_REG_30_DISABLE_PA_GAIN = (0x0U << BK4819_REG_30_SHIFT_ENABLE_PA_GAIN),
BK4819_REG_30_ENABLE_MIC_ADC = (0x1U << BK4819_REG_30_SHIFT_ENABLE_MIC_ADC),
BK4819_REG_30_DISABLE_MIC_ADC = (0x0U << BK4819_REG_30_SHIFT_ENABLE_MIC_ADC),
BK4819_REG_30_ENABLE_TX_DSP = (0x1U << BK4819_REG_30_SHIFT_ENABLE_TX_DSP),
BK4819_REG_30_DISABLE_TX_DSP = (0x0U << BK4819_REG_30_SHIFT_ENABLE_TX_DSP),
BK4819_REG_30_ENABLE_RX_DSP = (0x1U << BK4819_REG_30_SHIFT_ENABLE_RX_DSP),
BK4819_REG_30_DISABLE_RX_DSP = (0x0U << BK4819_REG_30_SHIFT_ENABLE_RX_DSP),
};
// REG 3F
#define BK4819_REG_3F_SHIFT_FSK_TX_FINISHED 15
#define BK4819_REG_3F_SHIFT_FSK_FIFO_ALMOST_EMPTY 14
#define BK4819_REG_3F_SHIFT_FSK_RX_FINISHED 13
#define BK4819_REG_3F_SHIFT_FSK_FIFO_ALMOST_FULL 12
#define BK4819_REG_3F_SHIFT_DTMF_5TONE_FOUND 11
#define BK4819_REG_3F_SHIFT_CxCSS_TAIL 10
#define BK4819_REG_3F_SHIFT_CDCSS_FOUND 9
#define BK4819_REG_3F_SHIFT_CDCSS_LOST 8
#define BK4819_REG_3F_SHIFT_CTCSS_FOUND 7
#define BK4819_REG_3F_SHIFT_CTCSS_LOST 6
#define BK4819_REG_3F_SHIFT_VOX_FOUND 5
#define BK4819_REG_3F_SHIFT_VOX_LOST 4
#define BK4819_REG_3F_SHIFT_SQUELCH_FOUND 3
#define BK4819_REG_3F_SHIFT_SQUELCH_LOST 2
#define BK4819_REG_3F_SHIFT_FSK_RX_SYNC 1
#define BK4819_REG_3F_MASK_FSK_TX_FINISHED (1U << BK4819_REG_3F_SHIFT_FSK_TX)
#define BK4819_REG_3F_MASK_FSK_FIFO_ALMOST_EMPTY (1U << BK4819_REG_3F_SHIFT_FSK_FIFO_ALMOST_EMPTY)
#define BK4819_REG_3F_MASK_FSK_RX_FINISHED (1U << BK4819_REG_3F_SHIFT_FSK_RX_FINISHED)
#define BK4819_REG_3F_MASK_FSK_FIFO_ALMOST_FULL (1U << BK4819_REG_3F_SHIFT_FSK_FIFO_ALMOST_FULL)
#define BK4819_REG_3F_MASK_DTMF_5TONE_FOUND (1U << BK4819_REG_3F_SHIFT_DTMF_5TONE_FOUND)
#define BK4819_REG_3F_MASK_CxCSS_TAIL (1U << BK4819_REG_3F_SHIFT_CxCSS_TAIL)
#define BK4819_REG_3F_MASK_CDCSS_FOUND (1U << BK4819_REG_3F_SHIFT_CDCSS_FOUND)
#define BK4819_REG_3F_MASK_CDCSS_LOST (1U << BK4819_REG_3F_SHIFT_CDCSS_LOST)
#define BK4819_REG_3F_MASK_CTCSS_FOUND (1U << BK4819_REG_3F_SHIFT_CTCSS_FOUND)
#define BK4819_REG_3F_MASK_CTCSS_LOST (1U << BK4819_REG_3F_SHIFT_CTCSS_LOST)
#define BK4819_REG_3F_MASK_VOX_FOUND (1U << BK4819_REG_3F_SHIFT_VOX_FOUND)
#define BK4819_REG_3F_MASK_VOX_LOST (1U << BK4819_REG_3F_SHIFT_VOX_LOST)
#define BK4819_REG_3F_MASK_SQUELCH_FOUND (1U << BK4819_REG_3F_SHIFT_SQUELCH_FOUND)
#define BK4819_REG_3F_MASK_SQUELCH_LOST (1U << BK4819_REG_3F_SHIFT_SQUELCH_LOST)
#define BK4819_REG_3F_MASK_FSK_RX_SYNC (1U << BK4819_REG_3F_SHIFT_FSK_RX_SYNC)
#define BK4819_REG_3F_FSK_TX_FINISHED (1U << BK4819_REG_3F_SHIFT_FSK_TX_FINISHED)
#define BK4819_REG_3F_FSK_FIFO_ALMOST_EMPTY (1U << BK4819_REG_3F_SHIFT_FSK_FIFO_ALMOST_EMPTY)
#define BK4819_REG_3F_FSK_RX_FINISHED (1U << BK4819_REG_3F_SHIFT_FSK_RX_FINISHED)
#define BK4819_REG_3F_FSK_FIFO_ALMOST_FULL (1U << BK4819_REG_3F_SHIFT_FSK_FIFO_ALMOST_FULL)
#define BK4819_REG_3F_DTMF_5TONE_FOUND (1U << BK4819_REG_3F_SHIFT_DTMF_5TONE_FOUND)
#define BK4819_REG_3F_CxCSS_TAIL (1U << BK4819_REG_3F_SHIFT_CxCSS_TAIL)
#define BK4819_REG_3F_CDCSS_FOUND (1U << BK4819_REG_3F_SHIFT_CDCSS_FOUND)
#define BK4819_REG_3F_CDCSS_LOST (1U << BK4819_REG_3F_SHIFT_CDCSS_LOST)
#define BK4819_REG_3F_CTCSS_FOUND (1U << BK4819_REG_3F_SHIFT_CTCSS_FOUND)
#define BK4819_REG_3F_CTCSS_LOST (1U << BK4819_REG_3F_SHIFT_CTCSS_LOST)
#define BK4819_REG_3F_VOX_FOUND (1U << BK4819_REG_3F_SHIFT_VOX_FOUND)
#define BK4819_REG_3F_VOX_LOST (1U << BK4819_REG_3F_SHIFT_VOX_LOST)
#define BK4819_REG_3F_SQUELCH_FOUND (1U << BK4819_REG_3F_SHIFT_SQUELCH_FOUND)
#define BK4819_REG_3F_SQUELCH_LOST (1U << BK4819_REG_3F_SHIFT_SQUELCH_LOST)
#define BK4819_REG_3F_FSK_RX_SYNC (1U << BK4819_REG_3F_SHIFT_FSK_RX_SYNC)
// REG 51
#define BK4819_REG_51_SHIFT_ENABLE_CxCSS 15
#define BK4819_REG_51_SHIFT_GPIO6_PIN2_INPUT 14
#define BK4819_REG_51_SHIFT_TX_CDCSS_POLARITY 13
#define BK4819_REG_51_SHIFT_CxCSS_MODE 12
#define BK4819_REG_51_SHIFT_CDCSS_BIT_WIDTH 11
#define BK4819_REG_51_SHIFT_1050HZ_DETECTION 10
#define BK4819_REG_51_SHIFT_AUTO_CDCSS_BW 9
#define BK4819_REG_51_SHIFT_AUTO_CTCSS_BW 8
#define BK4819_REG_51_SHIFT_CxCSS_TX_GAIN1 0
#define BK4819_REG_51_MASK_ENABLE_CxCSS (0x01U << BK4819_REG_51_SHIFT_ENABLE_CxCSS)
#define BK4819_REG_51_MASK_GPIO6_PIN2_INPUT (0x01U << BK4819_REG_51_SHIFT_GPIO6_PIN2_INPUT)
#define BK4819_REG_51_MASK_TX_CDCSS_POLARITY (0x01U << BK4819_REG_51_SHIFT_TX_CDCSS_POLARITY)
#define BK4819_REG_51_MASK_CxCSS_MODE (0x01U << BK4819_REG_51_SHIFT_CxCSS_MODE)
#define BK4819_REG_51_MASK_CDCSS_BIT_WIDTH (0x01U << BK4819_REG_51_SHIFT_CDCSS_BIT_WIDTH)
#define BK4819_REG_51_MASK_1050HZ_DETECTION (0x01U << BK4819_REG_51_SHIFT_1050HZ_DETECTION)
#define BK4819_REG_51_MASK_AUTO_CDCSS_BW (0x01U << BK4819_REG_51_SHIFT_AUTO_CDCSS_BW)
#define BK4819_REG_51_MASK_AUTO_CTCSS_BW (0x01U << BK4819_REG_51_SHIFT_AUTO_CTCSS_BW)
#define BK4819_REG_51_MASK_CxCSS_TX_GAIN1 (0x7FU << BK4819_REG_51_SHIFT_CxCSS_TX_GAIN1)
enum {
BK4819_REG_51_ENABLE_CxCSS = (1U << BK4819_REG_51_SHIFT_ENABLE_CxCSS),
BK4819_REG_51_DISABLE_CxCSS = (0U << BK4819_REG_51_SHIFT_ENABLE_CxCSS),
BK4819_REG_51_GPIO6_PIN2_INPUT = (1U << BK4819_REG_51_SHIFT_GPIO6_PIN2_INPUT),
BK4819_REG_51_GPIO6_PIN2_NORMAL = (0U << BK4819_REG_51_SHIFT_GPIO6_PIN2_INPUT),
BK4819_REG_51_TX_CDCSS_NEGATIVE = (1U << BK4819_REG_51_SHIFT_TX_CDCSS_POLARITY),
BK4819_REG_51_TX_CDCSS_POSITIVE = (0U << BK4819_REG_51_SHIFT_TX_CDCSS_POLARITY),
BK4819_REG_51_MODE_CTCSS = (1U << BK4819_REG_51_SHIFT_CxCSS_MODE),
BK4819_REG_51_MODE_CDCSS = (0U << BK4819_REG_51_SHIFT_CxCSS_MODE),
BK4819_REG_51_CDCSS_24_BIT = (1U << BK4819_REG_51_SHIFT_CDCSS_BIT_WIDTH),
BK4819_REG_51_CDCSS_23_BIT = (0U << BK4819_REG_51_SHIFT_CDCSS_BIT_WIDTH),
BK4819_REG_51_1050HZ_DETECTION = (1U << BK4819_REG_51_SHIFT_1050HZ_DETECTION),
BK4819_REG_51_1050HZ_NO_DETECTION = (0U << BK4819_REG_51_SHIFT_1050HZ_DETECTION),
BK4819_REG_51_AUTO_CDCSS_BW_DISABLE = (1U << BK4819_REG_51_SHIFT_AUTO_CDCSS_BW),
BK4819_REG_51_AUTO_CDCSS_BW_ENABLE = (0U << BK4819_REG_51_SHIFT_AUTO_CDCSS_BW),
BK4819_REG_51_AUTO_CTCSS_BW_DISABLE = (1U << BK4819_REG_51_SHIFT_AUTO_CTCSS_BW),
BK4819_REG_51_AUTO_CTCSS_BW_ENABLE = (0U << BK4819_REG_51_SHIFT_AUTO_CTCSS_BW),
};
// REG 70
#define BK4819_REG_70_SHIFT_ENABLE_TONE1 15
#define BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN 8
#define BK4819_REG_70_SHIFT_ENABLE_TONE2 7
#define BK4819_REG_70_SHIFT_TONE2_TUNING_GAIN 0
#define BK4819_REG_70_MASK_ENABLE_TONE1 (0x01U << BK4819_REG_70_SHIFT_ENABLE_TONE1)
#define BK4819_REG_70_MASK_TONE1_TUNING_GAIN (0x7FU << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN)
#define BK4819_REG_70_MASK_ENABLE_TONE2 (0x01U << BK4819_REG_70_SHIFT_ENABLE_TONE2)
#define BK4819_REG_70_MASK_TONE2_TUNING_GAIN (0x7FU << BK4819_REG_70_SHIFT_TONE2_TUNING_GAIN)
enum {
BK4819_REG_70_ENABLE_TONE1 = (1U << BK4819_REG_70_SHIFT_ENABLE_TONE1),
BK4819_REG_70_ENABLE_TONE2 = (1U << BK4819_REG_70_SHIFT_ENABLE_TONE2),
};
#endif

1819
driver/bk4819.c Normal file

File diff suppressed because it is too large Load Diff

173
driver/bk4819.h Normal file
View File

@@ -0,0 +1,173 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef DRIVER_BK4819_h
#define DRIVER_BK4819_h
#include <stdbool.h>
#include <stdint.h>
#include "driver/bk4819-regs.h"
enum BK4819_AF_Type_t
{
BK4819_AF_MUTE = 0u, //
BK4819_AF_FM = 1u, // FM
BK4819_AF_ALAM = 2u, //
BK4819_AF_BEEP = 3u, //
BK4819_AF_BASEBAND1 = 4u, // RAW
BK4819_AF_BASEBAND2 = 5u, // USB
BK4819_AF_CTCO = 6u, // strange LF audio .. maybe the CTCSS LF line ?
BK4819_AF_AM = 7u, // AM
BK4819_AF_FSKO = 8u, // nothing
BK4819_AF_UNKNOWN3 = 9u, // BYP
BK4819_AF_UNKNOWN4 = 10u, // nothing at all
BK4819_AF_UNKNOWN5 = 11u, // distorted
BK4819_AF_UNKNOWN6 = 12u, // distorted
BK4819_AF_UNKNOWN7 = 13u, // interesting
BK4819_AF_UNKNOWN8 = 14u, // interesting
BK4819_AF_UNKNOWN9 = 15u // not a lot
};
typedef enum BK4819_AF_Type_t BK4819_AF_Type_t;
enum BK4819_FilterBandwidth_t
{
BK4819_FILTER_BW_WIDE = 0,
BK4819_FILTER_BW_NARROW,
BK4819_FILTER_BW_NARROWER
};
typedef enum BK4819_FilterBandwidth_t BK4819_FilterBandwidth_t;
enum BK4819_CssScanResult_t
{
BK4819_CSS_RESULT_NOT_FOUND = 0,
BK4819_CSS_RESULT_CTCSS,
BK4819_CSS_RESULT_CDCSS
};
typedef enum BK4819_CssScanResult_t BK4819_CssScanResult_t;
// radio is asleep, not listening
extern bool gRxIdleMode;
void BK4819_Init(void);
uint16_t BK4819_ReadRegister(BK4819_REGISTER_t Register);
void BK4819_WriteRegister(BK4819_REGISTER_t Register, uint16_t Data);
void BK4819_SetRegValue(RegisterSpec s, uint16_t v);
void BK4819_WriteU8(uint8_t Data);
void BK4819_WriteU16(uint16_t Data);
void BK4819_SetAGC(bool enable);
void BK4819_InitAGC(bool amModulation);
void BK4819_ToggleGpioOut(BK4819_GPIO_PIN_t Pin, bool bSet);
void BK4819_SetCDCSSCodeWord(uint32_t CodeWord);
void BK4819_SetCTCSSFrequency(uint32_t BaudRate);
void BK4819_SetTailDetection(const uint32_t freq_10Hz);
void BK4819_EnableVox(uint16_t Vox1Threshold, uint16_t Vox0Threshold);
void BK4819_SetFilterBandwidth(const BK4819_FilterBandwidth_t Bandwidth, const bool weak_no_different);
void BK4819_SetupPowerAmplifier(const uint8_t bias, const uint32_t frequency);
void BK4819_SetFrequency(uint32_t Frequency);
void BK4819_SetupSquelch(
uint8_t SquelchOpenRSSIThresh,
uint8_t SquelchCloseRSSIThresh,
uint8_t SquelchOpenNoiseThresh,
uint8_t SquelchCloseNoiseThresh,
uint8_t SquelchCloseGlitchThresh,
uint8_t SquelchOpenGlitchThresh);
void BK4819_SetAF(BK4819_AF_Type_t AF);
void BK4819_RX_TurnOn(void);
void BK4819_PickRXFilterPathBasedOnFrequency(uint32_t Frequency);
void BK4819_DisableScramble(void);
void BK4819_EnableScramble(uint8_t Type);
bool BK4819_CompanderEnabled(void);
void BK4819_SetCompander(const unsigned int mode);
void BK4819_DisableVox(void);
void BK4819_DisableDTMF(void);
void BK4819_EnableDTMF(void);
void BK4819_PlayTone(uint16_t Frequency, bool bTuningGainSwitch);
void BK4819_PlaySingleTone(const unsigned int tone_Hz, const unsigned int delay, const unsigned int level, const bool play_speaker);
void BK4819_EnterTxMute(void);
void BK4819_ExitTxMute(void);
void BK4819_Sleep(void);
void BK4819_TurnsOffTones_TurnsOnRX(void);
#ifdef ENABLE_AIRCOPY
void BK4819_SetupAircopy(void);
#endif
void BK4819_ResetFSK(void);
void BK4819_Idle(void);
void BK4819_ExitBypass(void);
void BK4819_PrepareTransmit(void);
void BK4819_TxOn_Beep(void);
void BK4819_ExitSubAu(void);
void BK4819_Conditional_RX_TurnOn_and_GPIO6_Enable(void);
void BK4819_EnterDTMF_TX(bool bLocalLoopback);
void BK4819_ExitDTMF_TX(bool bKeep);
void BK4819_EnableTXLink(void);
void BK4819_PlayDTMF(char Code);
void BK4819_PlayDTMFString(const char *pString, bool bDelayFirst, uint16_t FirstCodePersistTime, uint16_t HashCodePersistTime, uint16_t CodePersistTime, uint16_t CodeInternalTime);
void BK4819_TransmitTone(bool bLocalLoopback, uint32_t Frequency);
void BK4819_GenTail(uint8_t Tail);
void BK4819_PlayCDCSSTail(void);
void BK4819_PlayCTCSSTail(void);
uint16_t BK4819_GetRSSI(void);
int8_t BK4819_GetRxGain_dB(void);
int16_t BK4819_GetRSSI_dBm(void);
uint8_t BK4819_GetGlitchIndicator(void);
uint8_t BK4819_GetExNoiceIndicator(void);
uint16_t BK4819_GetVoiceAmplitudeOut(void);
uint8_t BK4819_GetAfTxRx(void);
bool BK4819_GetFrequencyScanResult(uint32_t *pFrequency);
BK4819_CssScanResult_t BK4819_GetCxCSSScanResult(uint32_t *pCdcssFreq, uint16_t *pCtcssFreq);
void BK4819_DisableFrequencyScan(void);
void BK4819_EnableFrequencyScan(void);
void BK4819_SetScanFrequency(uint32_t Frequency);
void BK4819_Disable(void);
void BK4819_StopScan(void);
uint8_t BK4819_GetDTMF_5TONE_Code(void);
uint8_t BK4819_GetCDCSSCodeType(void);
uint8_t BK4819_GetCTCShift(void);
uint8_t BK4819_GetCTCType(void);
void BK4819_SendFSKData(uint16_t *pData);
void BK4819_PrepareFSKReceive(void);
void BK4819_PlayRoger(void);
void BK4819_Enable_AfDac_DiscMode_TxDsp(void);
void BK4819_GetVoxAmp(uint16_t *pResult);
void BK4819_SetScrambleFrequencyControlWord(uint32_t Frequency);
void BK4819_PlayDTMFEx(bool bLocalLoopback, char Code);
#endif

49
driver/crc.c Normal file
View File

@@ -0,0 +1,49 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "../bsp/dp32g030/crc.h"
#include "crc.h"
void CRC_Init(void)
{
CRC_CR = 0
| CRC_CR_CRC_EN_BITS_DISABLE
| CRC_CR_INPUT_REV_BITS_NORMAL
| CRC_CR_INPUT_INV_BITS_NORMAL
| CRC_CR_OUTPUT_REV_BITS_NORMAL
| CRC_CR_OUTPUT_INV_BITS_NORMAL
| CRC_CR_DATA_WIDTH_BITS_8
| CRC_CR_CRC_SEL_BITS_CRC_16_CCITT
;
CRC_IV = 0;
}
uint16_t CRC_Calculate(const void *pBuffer, uint16_t Size)
{
const uint8_t *pData = (const uint8_t *)pBuffer;
uint16_t i, Crc;
CRC_CR = (CRC_CR & ~CRC_CR_CRC_EN_MASK) | CRC_CR_CRC_EN_BITS_ENABLE;
for (i = 0; i < Size; i++) {
CRC_DATAIN = pData[i];
}
Crc = (uint16_t)CRC_DATAOUT;
CRC_CR = (CRC_CR & ~CRC_CR_CRC_EN_MASK) | CRC_CR_CRC_EN_BITS_DISABLE;
return Crc;
}

26
driver/crc.h Normal file
View File

@@ -0,0 +1,26 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef DRIVER_CRC_H
#define DRIVER_CRC_H
#include <stdint.h>
void CRC_Init(void);
uint16_t CRC_Calculate(const void *pBuffer, uint16_t Size);
#endif

63
driver/eeprom.c Normal file
View File

@@ -0,0 +1,63 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stddef.h>
#include <string.h>
#include "driver/eeprom.h"
#include "driver/i2c.h"
#include "driver/system.h"
void EEPROM_ReadBuffer(uint16_t Address, void *pBuffer, uint8_t Size)
{
I2C_Start();
I2C_Write(0xA0);
I2C_Write((Address >> 8) & 0xFF);
I2C_Write((Address >> 0) & 0xFF);
I2C_Start();
I2C_Write(0xA1);
I2C_ReadBuffer(pBuffer, Size);
I2C_Stop();
}
void EEPROM_WriteBuffer(uint16_t Address, const void *pBuffer)
{
if (pBuffer == NULL || Address >= 0x2000)
return;
uint8_t buffer[8];
EEPROM_ReadBuffer(Address, buffer, 8);
if (memcmp(pBuffer, buffer, 8) == 0) {
return;
}
I2C_Start();
I2C_Write(0xA0);
I2C_Write((Address >> 8) & 0xFF);
I2C_Write((Address >> 0) & 0xFF);
I2C_WriteBuffer(pBuffer, 8);
I2C_Stop();
// give the EEPROM time to burn the data in (apparently takes 5ms)
SYSTEM_DelayMs(8);
}

26
driver/eeprom.h Normal file
View File

@@ -0,0 +1,26 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef DRIVER_EEPROM_H
#define DRIVER_EEPROM_H
#include <stdint.h>
void EEPROM_ReadBuffer(uint16_t Address, void *pBuffer, uint8_t Size);
void EEPROM_WriteBuffer(uint16_t Address, const void *pBuffer);
#endif

33
driver/flash.c Normal file
View File

@@ -0,0 +1,33 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "driver/flash.h"
#include "sram-overlay.h"
void FLASH_Init(FLASH_READ_MODE ReadMode)
{
overlay_FLASH_Init(ReadMode);
}
void FLASH_ConfigureTrimValues(void)
{
overlay_FLASH_ConfigureTrimValues();
}
uint32_t FLASH_ReadNvrWord(uint32_t Address)
{
return overlay_FLASH_ReadNvrWord(Address);
}

59
driver/flash.h Normal file
View File

@@ -0,0 +1,59 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef DRIVER_FLASH_H
#define DRIVER_FLASH_H
#include "bsp/dp32g030/flash.h"
enum FLASH_READ_MODE {
FLASH_READ_MODE_1_CYCLE = FLASH_CFG_READ_MD_VALUE_1_CYCLE,
FLASH_READ_MODE_2_CYCLE = FLASH_CFG_READ_MD_VALUE_2_CYCLE,
};
typedef enum FLASH_READ_MODE FLASH_READ_MODE;
enum FLASH_MASK_SELECTION {
FLASH_MASK_SELECTION_NONE = FLASH_MASK_SEL_VALUE_NONE,
FLASH_MASK_SELECTION_2KB = FLASH_MASK_SEL_VALUE_2KB,
FLASH_MASK_SELECTION_4KB = FLASH_MASK_SEL_VALUE_4KB,
FLASH_MASK_SELECTION_8KB = FLASH_MASK_SEL_VALUE_8KB,
};
typedef enum FLASH_MASK_SELECTION FLASH_MASK_SELECTION;
enum FLASH_MODE {
FLASH_MODE_READ_AHB = FLASH_CFG_MODE_VALUE_READ_AHB,
FLASH_MODE_PROGRAM = FLASH_CFG_MODE_VALUE_PROGRAM,
FLASH_MODE_ERASE = FLASH_CFG_MODE_VALUE_ERASE,
FLASH_MODE_READ_APB = FLASH_CFG_MODE_VALUE_READ_APB,
};
typedef enum FLASH_MODE FLASH_MODE;
enum FLASH_AREA {
FLASH_AREA_MAIN = FLASH_CFG_NVR_SEL_VALUE_MAIN,
FLASH_AREA_NVR = FLASH_CFG_NVR_SEL_VALUE_NVR,
};
typedef enum FLASH_AREA FLASH_AREA;
void FLASH_Init(FLASH_READ_MODE ReadMode);
void FLASH_ConfigureTrimValues(void);
uint32_t FLASH_ReadNvrWord(uint32_t Address);
#endif

18
driver/gpio.c Normal file
View File

@@ -0,0 +1,18 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

78
driver/gpio.h Normal file
View File

@@ -0,0 +1,78 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef DRIVER_GPIO_H
#define DRIVER_GPIO_H
#include <stdint.h>
enum GPIOA_PINS {
GPIOA_PIN_KEYBOARD_0 = 3,
GPIOA_PIN_KEYBOARD_1 = 4,
GPIOA_PIN_KEYBOARD_2 = 5,
GPIOA_PIN_KEYBOARD_3 = 6,
GPIOA_PIN_KEYBOARD_4 = 10, // Shared with I2C!
GPIOA_PIN_KEYBOARD_5 = 11, // Shared with I2C!
GPIOA_PIN_KEYBOARD_6 = 12, // Shared with voice chip!
GPIOA_PIN_KEYBOARD_7 = 13, // Shared with voice chip!
GPIOA_PIN_I2C_SCL = 10, // Shared with keyboard!
GPIOA_PIN_I2C_SDA = 11, // Shared with keyboard!
GPIOA_PIN_VOICE_0 = 12, // Shared with keyboard!
GPIOA_PIN_VOICE_1 = 13 // Shared with keyboard!
};
enum GPIOB_PINS {
GPIOB_PIN_BACKLIGHT = 6,
GPIOB_PIN_ST7565_A0 = 9,
GPIOB_PIN_ST7565_RES = 11, // Shared with SWD!
GPIOB_PIN_SWD_IO = 11, // Shared with ST7565!
GPIOB_PIN_SWD_CLK = 14,
GPIOB_PIN_BK1080 = 15
};
enum GPIOC_PINS {
GPIOC_PIN_BK4819_SCN = 0,
GPIOC_PIN_BK4819_SCL = 1,
GPIOC_PIN_BK4819_SDA = 2,
GPIOC_PIN_FLASHLIGHT = 3,
GPIOC_PIN_AUDIO_PATH = 4,
GPIOC_PIN_PTT = 5
};
static inline void GPIO_ClearBit(volatile uint32_t *pReg, uint8_t Bit) {
*pReg &= ~(1U << Bit);
}
static inline uint8_t GPIO_CheckBit(volatile uint32_t *pReg, uint8_t Bit) {
return (*pReg >> Bit) & 1U;
}
static inline void GPIO_FlipBit(volatile uint32_t *pReg, uint8_t Bit) {
*pReg ^= 1U << Bit;
}
static inline void GPIO_SetBit(volatile uint32_t *pReg, uint8_t Bit) {
*pReg |= 1U << Bit;
}
#endif

164
driver/i2c.c Normal file
View File

@@ -0,0 +1,164 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "bsp/dp32g030/gpio.h"
#include "bsp/dp32g030/portcon.h"
#include "driver/gpio.h"
#include "driver/i2c.h"
#include "driver/systick.h"
void I2C_Start(void)
{
GPIO_SetBit(&GPIOA->DATA, GPIOA_PIN_I2C_SDA);
SYSTICK_DelayUs(1);
GPIO_SetBit(&GPIOA->DATA, GPIOA_PIN_I2C_SCL);
SYSTICK_DelayUs(1);
GPIO_ClearBit(&GPIOA->DATA, GPIOA_PIN_I2C_SDA);
SYSTICK_DelayUs(1);
GPIO_ClearBit(&GPIOA->DATA, GPIOA_PIN_I2C_SCL);
SYSTICK_DelayUs(1);
}
void I2C_Stop(void)
{
GPIO_ClearBit(&GPIOA->DATA, GPIOA_PIN_I2C_SDA);
SYSTICK_DelayUs(1);
GPIO_ClearBit(&GPIOA->DATA, GPIOA_PIN_I2C_SCL);
SYSTICK_DelayUs(1);
GPIO_SetBit(&GPIOA->DATA, GPIOA_PIN_I2C_SCL);
SYSTICK_DelayUs(1);
GPIO_SetBit(&GPIOA->DATA, GPIOA_PIN_I2C_SDA);
SYSTICK_DelayUs(1);
}
uint8_t I2C_Read(bool bFinal)
{
uint8_t i, Data;
PORTCON_PORTA_IE |= PORTCON_PORTA_IE_A11_BITS_ENABLE;
PORTCON_PORTA_OD &= ~PORTCON_PORTA_OD_A11_MASK;
GPIOA->DIR &= ~GPIO_DIR_11_MASK;
Data = 0;
for (i = 0; i < 8; i++) {
GPIO_ClearBit(&GPIOA->DATA, GPIOA_PIN_I2C_SCL);
SYSTICK_DelayUs(1);
GPIO_SetBit(&GPIOA->DATA, GPIOA_PIN_I2C_SCL);
SYSTICK_DelayUs(1);
Data <<= 1;
SYSTICK_DelayUs(1);
if (GPIO_CheckBit(&GPIOA->DATA, GPIOA_PIN_I2C_SDA)) {
Data |= 1U;
}
GPIO_ClearBit(&GPIOA->DATA, GPIOA_PIN_I2C_SCL);
SYSTICK_DelayUs(1);
}
PORTCON_PORTA_IE &= ~PORTCON_PORTA_IE_A11_MASK;
PORTCON_PORTA_OD |= PORTCON_PORTA_OD_A11_BITS_ENABLE;
GPIOA->DIR |= GPIO_DIR_11_BITS_OUTPUT;
GPIO_ClearBit(&GPIOA->DATA, GPIOA_PIN_I2C_SCL);
SYSTICK_DelayUs(1);
if (bFinal) {
GPIO_SetBit(&GPIOA->DATA, GPIOA_PIN_I2C_SDA);
} else {
GPIO_ClearBit(&GPIOA->DATA, GPIOA_PIN_I2C_SDA);
}
SYSTICK_DelayUs(1);
GPIO_SetBit(&GPIOA->DATA, GPIOA_PIN_I2C_SCL);
SYSTICK_DelayUs(1);
GPIO_ClearBit(&GPIOA->DATA, GPIOA_PIN_I2C_SCL);
SYSTICK_DelayUs(1);
return Data;
}
int I2C_Write(uint8_t Data)
{
uint8_t i;
int ret = -1;
GPIO_ClearBit(&GPIOA->DATA, GPIOA_PIN_I2C_SCL);
SYSTICK_DelayUs(1);
for (i = 0; i < 8; i++) {
if ((Data & 0x80) == 0) {
GPIO_ClearBit(&GPIOA->DATA, GPIOA_PIN_I2C_SDA);
} else {
GPIO_SetBit(&GPIOA->DATA, GPIOA_PIN_I2C_SDA);
}
Data <<= 1;
SYSTICK_DelayUs(1);
GPIO_SetBit(&GPIOA->DATA, GPIOA_PIN_I2C_SCL);
SYSTICK_DelayUs(1);
GPIO_ClearBit(&GPIOA->DATA, GPIOA_PIN_I2C_SCL);
SYSTICK_DelayUs(1);
}
PORTCON_PORTA_IE |= PORTCON_PORTA_IE_A11_BITS_ENABLE;
PORTCON_PORTA_OD &= ~PORTCON_PORTA_OD_A11_MASK;
GPIOA->DIR &= ~GPIO_DIR_11_MASK;
GPIO_SetBit(&GPIOA->DATA, GPIOA_PIN_I2C_SDA);
SYSTICK_DelayUs(1);
GPIO_SetBit(&GPIOA->DATA, GPIOA_PIN_I2C_SCL);
SYSTICK_DelayUs(1);
for (i = 0; i < 255; i++) {
if (GPIO_CheckBit(&GPIOA->DATA, GPIOA_PIN_I2C_SDA) == 0) {
ret = 0;
break;
}
}
GPIO_ClearBit(&GPIOA->DATA, GPIOA_PIN_I2C_SCL);
SYSTICK_DelayUs(1);
PORTCON_PORTA_IE &= ~PORTCON_PORTA_IE_A11_MASK;
PORTCON_PORTA_OD |= PORTCON_PORTA_OD_A11_BITS_ENABLE;
GPIOA->DIR |= GPIO_DIR_11_BITS_OUTPUT;
GPIO_SetBit(&GPIOA->DATA, GPIOA_PIN_I2C_SDA);
return ret;
}
int I2C_ReadBuffer(void *pBuffer, uint8_t Size)
{
uint8_t *pData = (uint8_t *)pBuffer;
uint8_t i;
for (i = 0; i < Size - 1; i++) {
SYSTICK_DelayUs(1);
pData[i] = I2C_Read(false);
}
SYSTICK_DelayUs(1);
pData[i] = I2C_Read(true);
return Size;
}
int I2C_WriteBuffer(const void *pBuffer, uint8_t Size)
{
const uint8_t *pData = (const uint8_t *)pBuffer;
uint8_t i;
for (i = 0; i < Size; i++) {
if (I2C_Write(*pData++) < 0) {
return -1;
}
}
return 0;
}

38
driver/i2c.h Normal file
View File

@@ -0,0 +1,38 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef DRIVER_I2C_H
#define DRIVER_I2C_H
#include <stdbool.h>
#include <stdint.h>
enum {
I2C_WRITE = 0U,
I2C_READ = 1U,
};
void I2C_Start(void);
void I2C_Stop(void);
uint8_t I2C_Read(bool bFinal);
int I2C_Write(uint8_t Data);
int I2C_ReadBuffer(void *pBuffer, uint8_t Size);
int I2C_WriteBuffer(const void *pBuffer, uint8_t Size);
#endif

153
driver/keyboard.c Normal file
View File

@@ -0,0 +1,153 @@
/* Copyright 2023 Manuel Jinger
* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "bsp/dp32g030/gpio.h"
#include "driver/gpio.h"
#include "driver/keyboard.h"
#include "driver/systick.h"
#include "driver/i2c.h"
#include "misc.h"
KEY_Code_t gKeyReading0 = KEY_INVALID;
KEY_Code_t gKeyReading1 = KEY_INVALID;
uint16_t gDebounceCounter = 0;
bool gWasFKeyPressed = false;
static const struct {
// Using a 16 bit pre-calculated shift and invert is cheaper
// than using 8 bit and doing shift and invert in code.
uint16_t set_to_zero_mask;
// We are very fortunate.
// The key and pin defines fit together in a single u8, making this very efficient
struct {
KEY_Code_t key : 5;
uint8_t pin : 3; // Pin 6 is highest
} pins[4];
} keyboard[] = {
{ // Zero row
// Set to zero to handle special case of nothing pulled down
.set_to_zero_mask = 0xffff,
.pins = {
{ .key = KEY_SIDE1, .pin = GPIOA_PIN_KEYBOARD_0},
{ .key = KEY_SIDE2, .pin = GPIOA_PIN_KEYBOARD_1},
// Duplicate to fill the array with valid values
{ .key = KEY_INVALID, .pin = GPIOA_PIN_KEYBOARD_1},
{ .key = KEY_INVALID, .pin = GPIOA_PIN_KEYBOARD_1}
}
},
{ // First row
.set_to_zero_mask = ~(1u << GPIOA_PIN_KEYBOARD_4) & 0xffff,
.pins = {
{ .key = KEY_MENU, .pin = GPIOA_PIN_KEYBOARD_0},
{ .key = KEY_1, .pin = GPIOA_PIN_KEYBOARD_1},
{ .key = KEY_4, .pin = GPIOA_PIN_KEYBOARD_2},
{ .key = KEY_7, .pin = GPIOA_PIN_KEYBOARD_3}
}
},
{ // Second row
.set_to_zero_mask = ~(1u << GPIOA_PIN_KEYBOARD_5) & 0xffff,
.pins = {
{ .key = KEY_UP, .pin = GPIOA_PIN_KEYBOARD_0},
{ .key = KEY_2 , .pin = GPIOA_PIN_KEYBOARD_1},
{ .key = KEY_5 , .pin = GPIOA_PIN_KEYBOARD_2},
{ .key = KEY_8 , .pin = GPIOA_PIN_KEYBOARD_3}
}
},
{ // Third row
.set_to_zero_mask = ~(1u << GPIOA_PIN_KEYBOARD_6) & 0xffff,
.pins = {
{ .key = KEY_DOWN, .pin = GPIOA_PIN_KEYBOARD_0},
{ .key = KEY_3 , .pin = GPIOA_PIN_KEYBOARD_1},
{ .key = KEY_6 , .pin = GPIOA_PIN_KEYBOARD_2},
{ .key = KEY_9 , .pin = GPIOA_PIN_KEYBOARD_3}
}
},
{ // Fourth row
.set_to_zero_mask = ~(1u << GPIOA_PIN_KEYBOARD_7) & 0xffff,
.pins = {
{ .key = KEY_EXIT, .pin = GPIOA_PIN_KEYBOARD_0},
{ .key = KEY_STAR, .pin = GPIOA_PIN_KEYBOARD_1},
{ .key = KEY_0 , .pin = GPIOA_PIN_KEYBOARD_2},
{ .key = KEY_F , .pin = GPIOA_PIN_KEYBOARD_3}
}
}
};
KEY_Code_t KEYBOARD_Poll(void)
{
KEY_Code_t Key = KEY_INVALID;
// if (!GPIO_CheckBit(&GPIOC->DATA, GPIOC_PIN_PTT))
// return KEY_PTT;
// *****************
for (unsigned int j = 0; j < ARRAY_SIZE(keyboard); j++)
{
uint16_t reg;
unsigned int i;
unsigned int k;
// Set all high
GPIOA->DATA |= 1u << GPIOA_PIN_KEYBOARD_4 |
1u << GPIOA_PIN_KEYBOARD_5 |
1u << GPIOA_PIN_KEYBOARD_6 |
1u << GPIOA_PIN_KEYBOARD_7;
// Clear the pin we are selecting
GPIOA->DATA &= keyboard[j].set_to_zero_mask;
// Read all 4 GPIO pins at once .. with de-noise, max of 8 sample loops
for (i = 0, k = 0, reg = 0; i < 3 && k < 8; i++, k++) {
SYSTICK_DelayUs(1);
uint16_t reg2 = GPIOA->DATA;
i *= reg == reg2;
reg = reg2;
}
if (i < 3)
break; // noise is too bad
for (unsigned int i = 0; i < ARRAY_SIZE(keyboard[j].pins); i++)
{
const uint16_t mask = 1u << keyboard[j].pins[i].pin;
if (!(reg & mask))
{
Key = keyboard[j].pins[i].key;
break;
}
}
if (Key != KEY_INVALID)
break;
}
// Create I2C stop condition since we might have toggled I2C pins
// This leaves GPIOA_PIN_KEYBOARD_4 and GPIOA_PIN_KEYBOARD_5 high
I2C_Stop();
// Reset VOICE pins
GPIO_ClearBit(&GPIOA->DATA, GPIOA_PIN_KEYBOARD_6);
GPIO_SetBit( &GPIOA->DATA, GPIOA_PIN_KEYBOARD_7);
return Key;
}

56
driver/keyboard.h Normal file
View File

@@ -0,0 +1,56 @@
/* Copyright 2023 Manuel Jinger
* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef DRIVER_KEYBOARD_H
#define DRIVER_KEYBOARD_H
#include <stdbool.h>
#include <stdint.h>
enum KEY_Code_e {
KEY_0 = 0, // 0
KEY_1, // 1
KEY_2, // 2
KEY_3, // 3
KEY_4, // 4
KEY_5, // 5
KEY_6, // 6
KEY_7, // 7
KEY_8, // 8
KEY_9, // 9
KEY_MENU, // A
KEY_UP, // B
KEY_DOWN, // C
KEY_EXIT, // D
KEY_STAR, // *
KEY_F, // #
KEY_PTT, //
KEY_SIDE2, //
KEY_SIDE1, //
KEY_INVALID //
};
typedef enum KEY_Code_e KEY_Code_t;
extern KEY_Code_t gKeyReading0;
extern KEY_Code_t gKeyReading1;
extern uint16_t gDebounceCounter;
extern bool gWasFKeyPressed;
KEY_Code_t KEYBOARD_Poll(void);
#endif

116
driver/spi.c Normal file
View File

@@ -0,0 +1,116 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ARMCM0.h"
#include "bsp/dp32g030/spi.h"
#include "bsp/dp32g030/syscon.h"
#include "bsp/dp32g030/irq.h"
#include "driver/spi.h"
void SPI0_Init(void)
{
SPI_Config_t Config;
SPI_Disable(&SPI0->CR);
Config.TXFIFO_EMPTY = 0;
Config.RXFIFO_HFULL = 0;
Config.RXFIFO_FULL = 0;
Config.RXFIFO_OVF = 0;
Config.MSTR = 1;
Config.SPR = 2;
Config.CPHA = 1;
Config.CPOL = 1;
Config.LSB = 0;
Config.TF_CLR = 0;
Config.RF_CLR = 0;
Config.TXFIFO_HFULL = 0;
SPI_Configure(SPI0, &Config);
SPI_Enable(&SPI0->CR);
}
void SPI_WaitForUndocumentedTxFifoStatusBit(void)
{
uint32_t Timeout;
Timeout = 0;
do {
// Undocumented bit!
if ((SPI0->IF & 0x20) == 0) {
break;
}
Timeout++;
} while (Timeout <= 100000);
}
void SPI_Disable(volatile uint32_t *pCR)
{
*pCR = (*pCR & ~SPI_CR_SPE_MASK) | SPI_CR_SPE_BITS_DISABLE;
}
void SPI_Configure(volatile SPI_Port_t *pPort, SPI_Config_t *pConfig)
{
if (pPort == SPI0) {
SYSCON_DEV_CLK_GATE = (SYSCON_DEV_CLK_GATE & ~SYSCON_DEV_CLK_GATE_SPI0_MASK) | SYSCON_DEV_CLK_GATE_SPI0_BITS_ENABLE;
} else if (pPort == SPI1) {
SYSCON_DEV_CLK_GATE = (SYSCON_DEV_CLK_GATE & ~SYSCON_DEV_CLK_GATE_SPI1_MASK) | SYSCON_DEV_CLK_GATE_SPI1_BITS_ENABLE;
}
SPI_Disable(&pPort->CR);
pPort->CR = 0
| (pPort->CR & ~(SPI_CR_SPR_MASK | SPI_CR_CPHA_MASK | SPI_CR_CPOL_MASK | SPI_CR_MSTR_MASK | SPI_CR_LSB_MASK | SPI_CR_RF_CLR_MASK))
| ((pConfig->SPR << SPI_CR_SPR_SHIFT) & SPI_CR_SPR_MASK)
| ((pConfig->CPHA << SPI_CR_CPHA_SHIFT) & SPI_CR_CPHA_MASK)
| ((pConfig->CPOL << SPI_CR_CPOL_SHIFT) & SPI_CR_CPOL_MASK)
| ((pConfig->MSTR << SPI_CR_MSTR_SHIFT) & SPI_CR_MSTR_MASK)
| ((pConfig->LSB << SPI_CR_LSB_SHIFT) & SPI_CR_LSB_MASK)
| ((pConfig->RF_CLR << SPI_CR_RF_CLR_SHIFT) & SPI_CR_RF_CLR_MASK)
| ((pConfig->TF_CLR << SPI_CR_TF_CLR_SHIFT) & SPI_CR_TF_CLR_MASK)
;
pPort->IE = 0
| ((pConfig->RXFIFO_OVF << SPI_IE_RXFIFO_OVF_SHIFT) & SPI_IE_RXFIFO_OVF_MASK)
| ((pConfig->RXFIFO_FULL << SPI_IE_RXFIFO_FULL_SHIFT) & SPI_IE_RXFIFO_FULL_MASK)
| ((pConfig->RXFIFO_HFULL << SPI_IE_RXFIFO_HFULL_SHIFT) & SPI_IE_RXFIFO_HFULL_MASK)
| ((pConfig->TXFIFO_EMPTY << SPI_IE_TXFIFO_EMPTY_SHIFT) & SPI_IE_TXFIFO_EMPTY_MASK)
| ((pConfig->TXFIFO_HFULL << SPI_IE_TXFIFO_HFULL_SHIFT) & SPI_IE_TXFIFO_HFULL_MASK)
;
if (pPort->IE) {
if (pPort == SPI0) {
NVIC_EnableIRQ((IRQn_Type)DP32_SPI0_IRQn);
} else if (pPort == SPI1) {
NVIC_EnableIRQ((IRQn_Type)DP32_SPI1_IRQn);
}
}
}
void SPI_ToggleMasterMode(volatile uint32_t *pCR, bool bIsMaster)
{
if (bIsMaster) {
*pCR = (*pCR & ~SPI_CR_MSR_SSN_MASK) | SPI_CR_MSR_SSN_BITS_ENABLE;
} else {
*pCR = (*pCR & ~SPI_CR_MSR_SSN_MASK) | SPI_CR_MSR_SSN_BITS_DISABLE;
}
}
void SPI_Enable(volatile uint32_t *pCR)
{
*pCR = (*pCR & ~SPI_CR_SPE_MASK) | SPI_CR_SPE_BITS_ENABLE;
}

47
driver/spi.h Normal file
View File

@@ -0,0 +1,47 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef DRIVER_SPI_H
#define DRIVER_SPI_H
#include <stdbool.h>
#include <stdint.h>
typedef struct {
uint8_t MSTR;
uint8_t SPR;
uint8_t CPHA;
uint8_t CPOL;
uint8_t LSB;
uint8_t TF_CLR;
uint8_t RF_CLR;
uint8_t TXFIFO_HFULL;
uint8_t TXFIFO_EMPTY;
uint8_t RXFIFO_HFULL;
uint8_t RXFIFO_FULL;
uint8_t RXFIFO_OVF;
} SPI_Config_t;
void SPI0_Init(void);
void SPI_WaitForUndocumentedTxFifoStatusBit(void);
void SPI_Disable(volatile uint32_t *pCR);
void SPI_Configure(volatile SPI_Port_t *pPort, SPI_Config_t *pConfig);
void SPI_ToggleMasterMode(volatile uint32_t *pCr, bool bIsMaster);
void SPI_Enable(volatile uint32_t *pCR);
#endif

214
driver/st7565.c Normal file
View File

@@ -0,0 +1,214 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdint.h>
#include <stdio.h> // NULL
#include "bsp/dp32g030/gpio.h"
#include "bsp/dp32g030/spi.h"
#include "driver/gpio.h"
#include "driver/spi.h"
#include "driver/st7565.h"
#include "driver/system.h"
#include "misc.h"
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);
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;
}
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)
{
SPI_ToggleMasterMode(&SPI0->CR, false);
ST7565_WriteByte(0x40);
for (unsigned line = 0; line < FRAME_LINES; line++) {
DrawLine(0, line+1, gFrameBuffer[line], LCD_WIDTH);
}
SPI_ToggleMasterMode(&SPI0->CR, true);
}
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
SPI_ToggleMasterMode(&SPI0->CR, false);
ST7565_WriteByte(0x40); // start line ?
DrawLine(0, 0, gStatusLine, LCD_WIDTH);
SPI_ToggleMasterMode(&SPI0->CR, true);
}
void ST7565_FillScreen(uint8_t value)
{
SPI_ToggleMasterMode(&SPI0->CR, false);
for (unsigned i = 0; i < 8; i++) {
DrawLine(0, i, NULL, value);
}
SPI_ToggleMasterMode(&SPI0->CR, true);
}
// Software reset
const uint8_t ST7565_CMD_SOFTWARE_RESET = 0xE2;
// Bias Select
// 1 0 1 0 0 0 1 BS
// Select bias setting 0=1/9; 1=1/7 (at 1/65 duty)
const uint8_t ST7565_CMD_BIAS_SELECT = 0xA2;
// COM Direction
// 1 1 0 0 MY - - -
// Set output direction of COM
// MY=1, reverse direction
// MY=0, normal direction
const uint8_t ST7565_CMD_COM_DIRECTION = 0xC0;
// SEG Direction
// 1 0 1 0 0 0 0 MX
// Set scan direction of SEG
// MX=1, reverse direction
// MX=0, normal direction
const uint8_t ST7565_CMD_SEG_DIRECTION = 0xA0;
// Inverse Display
// 1 0 1 0 0 1 1 INV
// INV =1, inverse display
// INV =0, normal display
const uint8_t ST7565_CMD_INVERSE_DISPLAY = 0xA6;
// All Pixel ON
// 1 0 1 0 0 1 0 AP
// AP=1, set all pixel ON
// AP=0, normal display
const uint8_t ST7565_CMD_ALL_PIXEL_ON = 0xA4;
// Regulation Ratio
// 0 0 1 0 0 RR2 RR1 RR0
// This instruction controls the regulation ratio of the built-in regulator
const uint8_t ST7565_CMD_REGULATION_RATIO = 0x20;
// Double command!! Set electronic volume (EV) level
// Send next: 0 0 EV5 EV4 EV3 EV2 EV1 EV0 contrast 0-63
const uint8_t ST7565_CMD_SET_EV = 0x81;
// Control built-in power circuit ON/OFF - 0 0 1 0 1 VB VR VF
// VB: Built-in Booster
// VR: Built-in Regulator
// VF: Built-in Follower
const uint8_t ST7565_CMD_POWER_CIRCUIT = 0x28;
// Set display start line 0-63
// 0 0 0 1 S5 S4 S3 S2 S1 S0
const uint8_t ST7565_CMD_SET_START_LINE = 0x40;
// Display ON/OFF
// 0 0 1 0 1 0 1 1 1 D
// D=1, display ON
// D=0, display OFF
const uint8_t ST7565_CMD_DISPLAY_ON_OFF = 0xAE;
uint8_t cmds[] = {
ST7565_CMD_BIAS_SELECT | 0, // Select bias setting: 1/9
ST7565_CMD_COM_DIRECTION | (0 << 3), // Set output direction of COM: normal
ST7565_CMD_SEG_DIRECTION | 1, // Set scan direction of SEG: reverse
ST7565_CMD_INVERSE_DISPLAY | 0, // Inverse Display: false
ST7565_CMD_ALL_PIXEL_ON | 0, // All Pixel ON: false - normal display
ST7565_CMD_REGULATION_RATIO | (4 << 0), // Regulation Ratio 5.0
ST7565_CMD_SET_EV, // Set contrast
31,
ST7565_CMD_POWER_CIRCUIT | 0b111, // Built-in power circuit ON/OFF: VB=1 VR=1 VF=1
ST7565_CMD_SET_START_LINE | 0, // Set Start Line: 0
ST7565_CMD_DISPLAY_ON_OFF | 1, // Display ON/OFF: ON
};
void ST7565_Init(void)
{
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]);
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);
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);
ST7565_FillScreen(0x00);
}
void ST7565_FixInterfGlitch(void)
{
SPI_ToggleMasterMode(&SPI0->CR, false);
for(uint8_t i = 0; i < ARRAY_SIZE(cmds); i++)
ST7565_WriteByte(cmds[i]);
SPI_WaitForUndocumentedTxFifoStatusBit();
SPI_ToggleMasterMode(&SPI0->CR, true);
}
void ST7565_HardwareReset(void)
{
GPIO_SetBit(&GPIOB->DATA, GPIOB_PIN_ST7565_RES);
SYSTEM_DelayMs(1);
GPIO_ClearBit(&GPIOB->DATA, GPIOB_PIN_ST7565_RES);
SYSTEM_DelayMs(20);
GPIO_SetBit(&GPIOB->DATA, GPIOB_PIN_ST7565_RES);
SYSTEM_DelayMs(120);
}
void ST7565_SelectColumnAndLine(uint8_t Column, uint8_t Line)
{
GPIO_ClearBit(&GPIOB->DATA, GPIOB_PIN_ST7565_A0);
while ((SPI0->FIFOST & SPI_FIFOST_TFF_MASK) != SPI_FIFOST_TFF_BITS_NOT_FULL) {}
SPI0->WDR = Line + 176;
while ((SPI0->FIFOST & SPI_FIFOST_TFF_MASK) != SPI_FIFOST_TFF_BITS_NOT_FULL) {}
SPI0->WDR = ((Column >> 4) & 0x0F) | 0x10;
while ((SPI0->FIFOST & SPI_FIFOST_TFF_MASK) != SPI_FIFOST_TFF_BITS_NOT_FULL) {}
SPI0->WDR = ((Column >> 0) & 0x0F);
SPI_WaitForUndocumentedTxFifoStatusBit();
}
void ST7565_WriteByte(uint8_t Value)
{
GPIO_ClearBit(&GPIOB->DATA, GPIOB_PIN_ST7565_A0);
while ((SPI0->FIFOST & SPI_FIFOST_TFF_MASK) != SPI_FIFOST_TFF_BITS_NOT_FULL) {}
SPI0->WDR = Value;
}

42
driver/st7565.h Normal file
View File

@@ -0,0 +1,42 @@
/* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef DRIVER_ST7565_H
#define DRIVER_ST7565_H
#include <stdbool.h>
#include <stdint.h>
#define LCD_WIDTH 128
#define LCD_HEIGHT 64
#define FRAME_LINES 7
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 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(void);
void ST7565_FixInterfGlitch(void);
void ST7565_HardwareReset(void);
void ST7565_SelectColumnAndLine(uint8_t Column, uint8_t Line);
void ST7565_WriteByte(uint8_t Value);
#endif

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