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:
166
main.c
Normal file
166
main.c
Normal file
@@ -0,0 +1,166 @@
|
||||
/* UA1ZBE Custom Firmware for Quansheng UV-K5/K6
|
||||
* Based on egzumer/uv-k5-firmware-custom
|
||||
*
|
||||
* Three modes: VFO, POCSAG decoder, Spectrum analyzer
|
||||
* Custom boot splash, RSSI indicator, direct frequency input
|
||||
*
|
||||
* Entry point: Main()
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "audio.h"
|
||||
#include "board.h"
|
||||
#include "misc.h"
|
||||
#include "radio.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include "app/app.h"
|
||||
#include "app/boot_splash.h"
|
||||
#include "app/mode.h"
|
||||
#include "app/dtmf.h"
|
||||
|
||||
#include "bsp/dp32g030/gpio.h"
|
||||
#include "bsp/dp32g030/syscon.h"
|
||||
|
||||
#include "driver/backlight.h"
|
||||
#include "driver/bk4819.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/system.h"
|
||||
#include "driver/systick.h"
|
||||
#include "driver/keyboard.h"
|
||||
|
||||
#include "app/display_rssi.h"
|
||||
#include "helper/battery.h"
|
||||
#include "helper/boot.h"
|
||||
|
||||
#include "ui/lock.h"
|
||||
#include "ui/welcome.h"
|
||||
#include "ui/menu.h"
|
||||
|
||||
void _putchar(__attribute__((unused)) char c)
|
||||
{
|
||||
#ifdef ENABLE_UART
|
||||
extern void UART_Send(const uint8_t *p, uint16_t len);
|
||||
UART_Send((uint8_t *)&c, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Main(void)
|
||||
{
|
||||
/* Enable clock gating of blocks we need */
|
||||
SYSCON_DEV_CLK_GATE = 0
|
||||
| SYSCON_DEV_CLK_GATE_GPIOA_BITS_ENABLE
|
||||
| SYSCON_DEV_CLK_GATE_GPIOB_BITS_ENABLE
|
||||
| SYSCON_DEV_CLK_GATE_GPIOC_BITS_ENABLE
|
||||
| SYSCON_DEV_CLK_GATE_UART1_BITS_ENABLE
|
||||
| SYSCON_DEV_CLK_GATE_SPI0_BITS_ENABLE
|
||||
| SYSCON_DEV_CLK_GATE_SARADC_BITS_ENABLE
|
||||
| SYSCON_DEV_CLK_GATE_CRC_BITS_ENABLE
|
||||
| SYSCON_DEV_CLK_GATE_AES_BITS_ENABLE
|
||||
| SYSCON_DEV_CLK_GATE_PWM_PLUS0_BITS_ENABLE;
|
||||
|
||||
SYSTICK_Init();
|
||||
BOARD_Init();
|
||||
|
||||
boot_counter_10ms = 250;
|
||||
|
||||
/* Clear DTMF string */
|
||||
memset(gDTMF_String, '-', sizeof(gDTMF_String));
|
||||
gDTMF_String[sizeof(gDTMF_String) - 1] = 0;
|
||||
|
||||
BK4819_Init();
|
||||
|
||||
BOARD_ADC_GetBatteryInfo(&gBatteryCurrentVoltage, &gBatteryCurrent);
|
||||
|
||||
SETTINGS_InitEEPROM();
|
||||
SETTINGS_WriteBuildOptions();
|
||||
SETTINGS_LoadCalibration();
|
||||
|
||||
RADIO_ConfigureChannel(0, VFO_CONFIGURE_RELOAD);
|
||||
RADIO_ConfigureChannel(1, VFO_CONFIGURE_RELOAD);
|
||||
|
||||
RADIO_SelectVfos();
|
||||
RADIO_SetupRegisters(true);
|
||||
|
||||
for (unsigned int i = 0; i < ARRAY_SIZE(gBatteryVoltages); i++)
|
||||
BOARD_ADC_GetBatteryInfo(&gBatteryVoltages[i], &gBatteryCurrent);
|
||||
|
||||
BATTERY_GetReadings(false);
|
||||
|
||||
/* Wait for user to release keys */
|
||||
const BOOT_Mode_t BootMode = BOOT_GetMode();
|
||||
|
||||
if (BootMode == BOOT_MODE_F_LOCK) {
|
||||
extern bool gF_LOCK;
|
||||
gF_LOCK = true;
|
||||
}
|
||||
|
||||
/* Count menu items */
|
||||
gMenuListCount = 0;
|
||||
while (MenuList[gMenuListCount].name[0] != '\0') {
|
||||
if (!gF_LOCK && MenuList[gMenuListCount].menu_id == FIRST_HIDDEN_MENU_ITEM)
|
||||
break;
|
||||
gMenuListCount++;
|
||||
}
|
||||
|
||||
if (!GPIO_CheckBit(&GPIOC->DATA, GPIOC_PIN_PTT) ||
|
||||
KEYBOARD_Poll() != KEY_INVALID ||
|
||||
BootMode != BOOT_MODE_NORMAL)
|
||||
{
|
||||
UI_DisplayReleaseKeys();
|
||||
BACKLIGHT_TurnOn();
|
||||
|
||||
for (int i = 0; i < 50;) {
|
||||
i = (GPIO_CheckBit(&GPIOC->DATA, GPIOC_PIN_PTT) &&
|
||||
KEYBOARD_Poll() == KEY_INVALID) ? i + 1 : 0;
|
||||
SYSTEM_DelayMs(10);
|
||||
}
|
||||
gKeyReading0 = KEY_INVALID;
|
||||
gKeyReading1 = KEY_INVALID;
|
||||
gDebounceCounter = 0;
|
||||
}
|
||||
|
||||
if (!gChargingWithTypeC && gBatteryDisplayLevel == 0)
|
||||
{
|
||||
FUNCTION_Select(FUNCTION_POWER_SAVE);
|
||||
if (gEeprom.BACKLIGHT_TIME < (ARRAY_SIZE(gSubMenu_BACKLIGHT) - 1))
|
||||
BACKLIGHT_TurnOff();
|
||||
else
|
||||
BACKLIGHT_TurnOn();
|
||||
gReducedService = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* === CUSTOM BOOT SPLASH (2 seconds) === */
|
||||
BACKLIGHT_TurnOn();
|
||||
BOOT_SplashShow();
|
||||
|
||||
/* Initialize RSSI display */
|
||||
RSSI_Init();
|
||||
|
||||
/* Initialize mode dispatcher — start in VFO mode */
|
||||
MODE_Init();
|
||||
|
||||
gUpdateStatus = true;
|
||||
}
|
||||
|
||||
/* === MAIN LOOP === */
|
||||
while (true) {
|
||||
APP_Update();
|
||||
|
||||
if (gNextTimeslice) {
|
||||
/* Update RSSI periodically */
|
||||
RSSI_Update();
|
||||
|
||||
/* Dispatch to current mode */
|
||||
MODE_TimeSlice10ms();
|
||||
|
||||
if (gNextTimeslice_500ms) {
|
||||
MODE_TimeSlice500ms();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user