mirror of
https://github.com/armel/uv-k1-k5v3-firmware-custom.git
synced 2026-10-02 03:15:37 +00:00
20 files changed
+715
-50
No files matched your search
+2
-1
@@ -1,4 +1,5 @@
|
||||
FROM --platform=amd64 archlinux:latest
|
||||
ARG BUILDPLATFORM
|
||||
FROM --platform=${BUILDPLATFORM} archlinux:latest
|
||||
RUN pacman -Syyu base-devel --noconfirm
|
||||
RUN pacman -Syyu arm-none-eabi-gcc --noconfirm
|
||||
RUN pacman -Syyu arm-none-eabi-newlib --noconfirm
|
||||
|
||||
@@ -41,6 +41,7 @@ ENABLE_BYP_RAW_DEMODULATORS ?= 0
|
||||
ENABLE_BLMIN_TMP_OFF ?= 0
|
||||
ENABLE_SCAN_RANGES ?= 1
|
||||
ENABLE_FEAT_F4HWN ?= 1
|
||||
ENABLE_FEAT_F4HWN_GAME ?= 0
|
||||
ENABLE_FEAT_F4HWN_SCREENSHOT ?= 0
|
||||
ENABLE_FEAT_F4HWN_SPECTRUM ?= 1
|
||||
ENABLE_FEAT_F4HWN_RX_TX_TIMER ?= 1
|
||||
@@ -153,6 +154,9 @@ OBJS += app/menu.o
|
||||
ifeq ($(ENABLE_SPECTRUM), 1)
|
||||
OBJS += app/spectrum.o
|
||||
endif
|
||||
ifeq ($(ENABLE_FEAT_F4HWN_GAME), 1)
|
||||
OBJS += app/breakout.o
|
||||
endif
|
||||
OBJS += app/scanner.o
|
||||
ifeq ($(ENABLE_UART),1)
|
||||
OBJS += app/uart.o
|
||||
@@ -230,7 +234,7 @@ ifeq ($(ENABLE_FEAT_F4HWN),1)
|
||||
VERSION_STRING_1 ?= v0.22
|
||||
|
||||
AUTHOR_STRING_2 ?= F4HWN
|
||||
VERSION_STRING_2 ?= v4.0
|
||||
VERSION_STRING_2 ?= v4.1
|
||||
|
||||
EDITION_STRING ?= Custom
|
||||
|
||||
@@ -430,6 +434,9 @@ ifeq ($(ENABLE_FEAT_F4HWN),1)
|
||||
else
|
||||
CFLAGS += -DSQL_TONE=550
|
||||
endif
|
||||
ifeq ($(ENABLE_FEAT_F4HWN_GAME),1)
|
||||
CFLAGS += -DENABLE_FEAT_F4HWN_GAME
|
||||
endif
|
||||
ifeq ($(ENABLE_FEAT_F4HWN_SCREENSHOT),1)
|
||||
CFLAGS += -DENABLE_FEAT_F4HWN_SCREENSHOT
|
||||
endif
|
||||
|
||||
@@ -26,7 +26,7 @@ Anyway, have fun.
|
||||
|
||||
# Donations
|
||||
|
||||
Special thanks to Jean-Cyrille F6IWW (2 times), Fabrice 14RC123, David F4BPP, Olivier 14RC206, Frédéric F4ESO, Stéphane F5LGW, Jorge Ornelas (4 times), Laurent F4AXK, Christophe Morel, Clayton W0LED, Pierre Antoine F6FWB, Jean-Claude 14FRS3306, Thierry F4GVO, Eric F1NOU, PricelessToolkit, Ady M6NYJ, Tom McGovern (3 times), Joseph Roth, Pierre-Yves Colin, Frank DJ7FG, Marcel Testaz, Brian Frobisher, Yannick F4JFO, Paolo Bussola, Dirk DL8DF, Levente Szőke (2 times), Bernard-Michel Herrera, Jérôme Saintespes, Paul Davies, RS (3 times), Johan F4WAT, Robert Wörle, Rafael Sundorf, Paul Harker, Peter Fintl, Pascal F4ICR (2 times), Mike DL2MF, Eric KI1C (2 times), Phil G0ELM, Jérôme Lambert, Meinhard Frank Günther, Eliot Vedel, Alfonso EA7KDF, Jean-François F1EVM, Robert DC1RDB, Ian KE2CHJ and Daryl VK3AWA for their [donations](https://www.paypal.com/paypalme/F4HWN). That’s so kind of them. Thanks so much 🙏🏻
|
||||
Special thanks to Jean-Cyrille F6IWW (2 times), Fabrice 14RC123, David F4BPP, Olivier 14RC206, Frédéric F4ESO, Stéphane F5LGW, Jorge Ornelas (4 times), Laurent F4AXK, Christophe Morel, Clayton W0LED, Pierre Antoine F6FWB, Jean-Claude 14FRS3306, Thierry F4GVO, Eric F1NOU, PricelessToolkit, Ady M6NYJ, Tom McGovern (3 times), Joseph Roth, Pierre-Yves Colin, Frank DJ7FG, Marcel Testaz, Brian Frobisher, Yannick F4JFO, Paolo Bussola, Dirk DL8DF, Levente Szőke (2 times), Bernard-Michel Herrera, Jérôme Saintespes, Paul Davies, RS (3 times), Johan F4WAT, Robert Wörle, Rafael Sundorf, Paul Harker, Peter Fintl, Pascal F4ICR (2 times), Mike DL2MF, Eric KI1C (2 times), Phil G0ELM, Jérôme Lambert, Meinhard Frank Günther, Eliot Vedel, Alfonso EA7KDF, Jean-François F1EVM, Robert DC1RDB, Ian KE2CHJ, Daryl VK3AWA, Roberto Brunelli, Robert Boardman and Stephen Oliver for their [donations](https://www.paypal.com/paypalme/F4HWN). That’s so kind of them. Thanks so much 🙏🏻
|
||||
|
||||
## Table of Contents
|
||||
|
||||
|
||||
+504
@@ -0,0 +1,504 @@
|
||||
/* Copyright 2025 Armel F4HWN
|
||||
* https://github.com/armel
|
||||
*
|
||||
* 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/breakout.h"
|
||||
|
||||
static uint32_t randSeed = 1;
|
||||
static uint8_t blockAnim = 0;
|
||||
|
||||
bool isInitialized = false;
|
||||
bool isPaused = false;
|
||||
bool isBeep = false;
|
||||
|
||||
uint8_t levelCountBreackout = 1;
|
||||
|
||||
uint16_t tone = 0;
|
||||
uint16_t score = 0;
|
||||
|
||||
int16_t ballCount = BALL_NUMBER;
|
||||
|
||||
char str[12];
|
||||
|
||||
KeyboardState kbd = {KEY_INVALID, KEY_INVALID, 0};
|
||||
|
||||
Brick brick[BRICK_NUMBER];
|
||||
Racket racket;
|
||||
Ball ball;
|
||||
|
||||
const uint8_t BITMAP_block[4][15] =
|
||||
{
|
||||
{
|
||||
0b00011110,
|
||||
0b00110001,
|
||||
0b00101001,
|
||||
0b00100101,
|
||||
0b00100011,
|
||||
0b00110001,
|
||||
0b00101001,
|
||||
0b00100101,
|
||||
0b00100011,
|
||||
0b00110001,
|
||||
0b00101001,
|
||||
0b00100101,
|
||||
0b00100011,
|
||||
0b00110001,
|
||||
0b00011110,
|
||||
},
|
||||
{
|
||||
0b00011110,
|
||||
0b00101001,
|
||||
0b00100101,
|
||||
0b00100011,
|
||||
0b00110001,
|
||||
0b00101001,
|
||||
0b00100101,
|
||||
0b00100011,
|
||||
0b00110001,
|
||||
0b00101001,
|
||||
0b00100101,
|
||||
0b00100011,
|
||||
0b00110001,
|
||||
0b00101001,
|
||||
0b00011110,
|
||||
},
|
||||
{
|
||||
0b00011110,
|
||||
0b00100101,
|
||||
0b00100011,
|
||||
0b00110001,
|
||||
0b00101001,
|
||||
0b00100101,
|
||||
0b00100011,
|
||||
0b00110001,
|
||||
0b00101001,
|
||||
0b00100101,
|
||||
0b00100011,
|
||||
0b00110001,
|
||||
0b00101001,
|
||||
0b00100101,
|
||||
0b00011110,
|
||||
},
|
||||
{
|
||||
0b00011110,
|
||||
0b00100011,
|
||||
0b00110001,
|
||||
0b00101001,
|
||||
0b00100101,
|
||||
0b00100011,
|
||||
0b00110001,
|
||||
0b00101001,
|
||||
0b00100101,
|
||||
0b00100011,
|
||||
0b00110001,
|
||||
0b00101001,
|
||||
0b00100101,
|
||||
0b00100011,
|
||||
0b00011110,
|
||||
}
|
||||
};
|
||||
|
||||
const uint8_t BITMAP_blockOn[15] =
|
||||
{
|
||||
0b00011110,
|
||||
0b00111111,
|
||||
0b00111111,
|
||||
0b00111111,
|
||||
0b00111111,
|
||||
0b00111111,
|
||||
0b00111111,
|
||||
0b00111111,
|
||||
0b00111111,
|
||||
0b00111111,
|
||||
0b00111111,
|
||||
0b00111111,
|
||||
0b00111111,
|
||||
0b00111111,
|
||||
0b00011110,
|
||||
};
|
||||
|
||||
const uint8_t BITMAP_blockEmpty[15] =
|
||||
{
|
||||
0b00000000,
|
||||
0b00000000,
|
||||
0b00000000,
|
||||
0b00000000,
|
||||
0b00000000,
|
||||
0b00000000,
|
||||
0b00000000,
|
||||
0b00000000,
|
||||
0b00000000,
|
||||
0b00000000,
|
||||
0b00000000,
|
||||
0b00000000,
|
||||
0b00000000,
|
||||
0b00000000,
|
||||
0b00000000,
|
||||
};
|
||||
|
||||
// Initialise seed
|
||||
void srand_custom(uint32_t seed) {
|
||||
randSeed = seed;
|
||||
}
|
||||
|
||||
// Return pseudo-random from 0 to RAND_MAX (here 32767)
|
||||
int rand_custom(void) {
|
||||
randSeed = randSeed * 1103515245 + 12345;
|
||||
return (randSeed >> 16) & 0x7FFF; // 15 bits
|
||||
}
|
||||
|
||||
// Return integer from min to max include
|
||||
int randInt(int min, int max) {
|
||||
return min + (rand_custom() % (max - min + 1));
|
||||
}
|
||||
|
||||
// Reset
|
||||
void reset(void)
|
||||
{
|
||||
ballCount = BALL_NUMBER;
|
||||
levelCountBreackout = 1;
|
||||
score = 0;
|
||||
}
|
||||
|
||||
// PlayBeep
|
||||
void playBeep(uint16_t tone)
|
||||
{
|
||||
BK4819_PlayTone(tone, true); // 500 Hz ON
|
||||
AUDIO_AudioPathOn();
|
||||
BK4819_ExitTxMute();
|
||||
SYSTEM_DelayMs(100);
|
||||
BK4819_EnterTxMute();
|
||||
AUDIO_AudioPathOff();
|
||||
}
|
||||
|
||||
// Draw score
|
||||
void drawScore()
|
||||
{
|
||||
// Clean status line
|
||||
memset(gStatusLine, 0, sizeof(gStatusLine));
|
||||
|
||||
// Level
|
||||
sprintf(str, "Level %02u", levelCountBreackout);
|
||||
GUI_DisplaySmallest(str, 0, 1, true, true);
|
||||
|
||||
// Ball
|
||||
sprintf(str, "Ball %02u", (ballCount < 0) ? 0 : ballCount);
|
||||
GUI_DisplaySmallest(str, 45, 1, true, true);
|
||||
|
||||
// Score
|
||||
sprintf(str, "Score %04u", score);
|
||||
GUI_DisplaySmallest(str, 88, 1, true, true);
|
||||
}
|
||||
|
||||
// Init ball
|
||||
void initBall() {
|
||||
ball.x = 62;
|
||||
ball.y = 30;
|
||||
ball.w = 3;
|
||||
ball.h = 3;
|
||||
ball.dx = 0;
|
||||
ball.dy = 1;
|
||||
|
||||
UI_DrawRectangleBuffer(gFrameBuffer, ball.x, ball.y, ball.x + ball.w -1, ball.y + ball.h - 1, true);
|
||||
UI_DrawLineBuffer(gFrameBuffer, ball.x - 1, ball.y + 1, ball.x + ball.w, ball.y + 1, true);
|
||||
}
|
||||
|
||||
// Draw ball
|
||||
void drawBall() {
|
||||
UI_DrawRectangleBuffer(gFrameBuffer, ball.x, ball.y, ball.x + ball.w -1, ball.y + ball.h -1, false);
|
||||
UI_DrawLineBuffer(gFrameBuffer, ball.x - 1, ball.y + 1, ball.x + ball.w, ball.y + 1, false);
|
||||
|
||||
ball.x += ball.dx;
|
||||
ball.y += ball.dy;
|
||||
|
||||
if (ball.y <= 0) // Up
|
||||
{
|
||||
ball.dx = map(randInt(0, 7), 0, 7, 3, -3);
|
||||
ball.dy = 1;
|
||||
}
|
||||
else if (ball.x <= 2) // Left
|
||||
{
|
||||
ball.dx = abs(ball.dx);
|
||||
}
|
||||
else if (ball.x >= 124) // Right
|
||||
{
|
||||
ball.dx = -abs(ball.dx);
|
||||
}
|
||||
// And now Down...
|
||||
if (ball.y == 47) {
|
||||
if (ball.x + 1 >= racket.x && ball.x - 1 <= racket.x + racket.w) {
|
||||
ball.dx = map(racket.x + racket.w - ball.x, 0, racket.w, 3, -3);
|
||||
ball.dy *= -1;
|
||||
isBeep = true;
|
||||
tone = 400;
|
||||
}
|
||||
}
|
||||
else if(ball.y > 49) {
|
||||
ballCount--;
|
||||
UI_DisplayClear();
|
||||
drawScore();
|
||||
isBeep = true;
|
||||
tone = 800;
|
||||
if (ballCount < 0) {
|
||||
reset();
|
||||
initWall();
|
||||
drawWall();
|
||||
|
||||
isPaused = true;
|
||||
UI_PrintStringSmallBold("GAME", 32, 0, 4);
|
||||
UI_PrintStringSmallBold("OVER", 66, 0, 4);
|
||||
}
|
||||
initRacket();
|
||||
initBall();
|
||||
}
|
||||
|
||||
UI_DrawRectangleBuffer(gFrameBuffer, ball.x, ball.y, ball.x + ball.w -1, ball.y + ball.h - 1, true);
|
||||
UI_DrawLineBuffer(gFrameBuffer, ball.x - 1, ball.y + 1, ball.x + ball.w, ball.y + 1, true);
|
||||
}
|
||||
|
||||
// Init wall
|
||||
void initWall() {
|
||||
uint8_t offset = 6;
|
||||
uint8_t i = 0;
|
||||
uint8_t j = 0;
|
||||
uint8_t k = 0;
|
||||
|
||||
for (i = 0; i < BRICK_NUMBER; i++) {
|
||||
if (i % 6 == 0) {
|
||||
j = 0;
|
||||
k++;
|
||||
}
|
||||
|
||||
brick[i].x = offset + (20 * j);
|
||||
brick[i].y = -8 + 8 * k;
|
||||
brick[i].w = 14;
|
||||
brick[i].h = 5;
|
||||
brick[i].s = randInt(0, 3);
|
||||
brick[i].destroy = false;
|
||||
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw wall
|
||||
void drawWall() {
|
||||
uint8_t i = 0;
|
||||
|
||||
for (i = 0; i < BRICK_NUMBER; i++) {
|
||||
if (brick[i].destroy == false) {
|
||||
if ((ball.x + 1 >= brick[i].x &&
|
||||
ball.x - 1 <= brick[i].x + brick[i].w) &&
|
||||
((ball.y + 1 >= brick[i].y &&
|
||||
ball.y - 1 <= brick[i].y + brick[i].h))) {
|
||||
brick[i].destroy = true;
|
||||
score++;
|
||||
|
||||
ball.dx = map(brick[i].x + brick[i].w - ball.x, 0, brick[i].w, 2, -2);
|
||||
ball.dy *= -1;
|
||||
|
||||
BK4819_ToggleGpioOut(BK4819_GPIO6_PIN2_GREEN, true);
|
||||
memcpy(gFrameBuffer[brick[i].y / 8] + brick[i].x, BITMAP_blockOn, sizeof(BITMAP_blockOn));
|
||||
ST7565_BlitLine(brick[i].y / 8);
|
||||
playBeep(600);
|
||||
memcpy(gFrameBuffer[brick[i].y / 8] + brick[i].x, BITMAP_blockEmpty, sizeof(BITMAP_blockEmpty));
|
||||
ST7565_BlitLine(brick[i].y / 8);
|
||||
BK4819_ToggleGpioOut(BK4819_GPIO6_PIN2_GREEN, false);
|
||||
|
||||
if (score % BRICK_NUMBER == 0) {
|
||||
levelCountBreackout++;
|
||||
ballCount++;
|
||||
initWall();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (brick[i].destroy == false) {
|
||||
memcpy(gFrameBuffer[brick[i].y / 8] + brick[i].x, BITMAP_block[(brick[i].s + blockAnim) % 4], sizeof(BITMAP_block[(brick[i].s + blockAnim) % 4]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Init racket
|
||||
void initRacket() {
|
||||
racket.w = 24;
|
||||
racket.x = (64) - (racket.w / 2);
|
||||
racket.y = 50;
|
||||
racket.h = 2;
|
||||
racket.p = racket.x;
|
||||
|
||||
UI_DrawRectangleBuffer(gFrameBuffer, racket.x + 1, racket.y, racket.x + racket.w - 2, racket.y + racket.h, true);
|
||||
UI_DrawLineBuffer(gFrameBuffer, racket.x, racket.y + 1, racket.x + racket.w - 1, racket.y + 1, true);
|
||||
}
|
||||
|
||||
// Draw racket
|
||||
void drawRacket() {
|
||||
if (racket.p != racket.x) {
|
||||
UI_DrawRectangleBuffer(gFrameBuffer, racket.p + 1, racket.y, racket.p + racket.w - 2, racket.y + racket.h, false);
|
||||
UI_DrawLineBuffer(gFrameBuffer, racket.p, racket.y + 1, racket.p + racket.w - 1, racket.y + 1, false);
|
||||
racket.p = racket.x;
|
||||
UI_DrawRectangleBuffer(gFrameBuffer, racket.x + 1, racket.y, racket.x + racket.w - 2, racket.y + racket.h, true);
|
||||
UI_DrawLineBuffer(gFrameBuffer, racket.x, racket.y + 1, racket.x + racket.w - 1, racket.y + 1, true);
|
||||
}
|
||||
}
|
||||
|
||||
// OnKeyDown
|
||||
static void OnKeyDown(uint8_t key)
|
||||
{
|
||||
bool wasPaused = isPaused;
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case KEY_4:
|
||||
case KEY_UP:
|
||||
if(!isPaused && racket.x > 0)
|
||||
racket.x -= 2;
|
||||
isPaused = false;
|
||||
break;
|
||||
case KEY_0:
|
||||
case KEY_DOWN:
|
||||
if(!isPaused && racket.x < 102)
|
||||
racket.x += 2;
|
||||
isPaused = false;
|
||||
break;
|
||||
case KEY_MENU:
|
||||
isPaused = !isPaused;
|
||||
kbd.counter = 0;
|
||||
if(isPaused)
|
||||
{
|
||||
UI_PrintStringSmallBold("PAUSE", 0, 128, 4);
|
||||
}
|
||||
break;
|
||||
case KEY_EXIT:
|
||||
isPaused = false;
|
||||
isInitialized = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if(wasPaused == true && isPaused == false)
|
||||
{
|
||||
// Clear the pause text
|
||||
for(uint8_t i = 0; i < 8; i++)
|
||||
{
|
||||
UI_DrawLineBuffer(gFrameBuffer, 32, 32 + i, 96, 32 + i, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Key
|
||||
KEY_Code_t GetKey()
|
||||
{
|
||||
KEY_Code_t btn = KEYBOARD_Poll();
|
||||
if (btn == KEY_INVALID && !GPIO_CheckBit(&GPIOC->DATA, GPIOC_PIN_PTT))
|
||||
{
|
||||
btn = KEY_PTT;
|
||||
}
|
||||
return btn;
|
||||
}
|
||||
|
||||
// HandleUserInput
|
||||
bool HandleUserInput()
|
||||
{
|
||||
// Store previous key state
|
||||
kbd.prev = kbd.current;
|
||||
|
||||
// Get the current key
|
||||
kbd.current = GetKey();
|
||||
|
||||
// Detect valid key press continuation (same key still pressed)
|
||||
if (kbd.current != KEY_INVALID && kbd.current == kbd.prev)
|
||||
{
|
||||
kbd.counter = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
kbd.counter = 0;
|
||||
}
|
||||
|
||||
// Process the key if counter indicates it should be handled
|
||||
if (kbd.counter == 1)
|
||||
{
|
||||
OnKeyDown(kbd.current);
|
||||
|
||||
// Special handling for MENU key
|
||||
if(kbd.current == KEY_MENU)
|
||||
{
|
||||
kbd.counter = 0;
|
||||
SYSTEM_DelayMs(250);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Tick
|
||||
static void Tick()
|
||||
{
|
||||
HandleUserInput();
|
||||
HandleUserInput();
|
||||
}
|
||||
|
||||
// APP_RunBreakout
|
||||
void APP_RunBreakout(void) {
|
||||
static uint8_t swap = 0;
|
||||
|
||||
// Init seed
|
||||
srand_custom(BK4819_ReadRegister(BK4819_REG_67) & 0x01FF * gBatteryVoltageAverage * gEeprom.VfoInfo[0].pRX->Frequency);
|
||||
|
||||
// Init led
|
||||
BK4819_ToggleGpioOut(BK4819_GPIO6_PIN2_GREEN, false);
|
||||
|
||||
// Init game
|
||||
UI_DisplayClear();
|
||||
reset();
|
||||
initWall();
|
||||
initRacket();
|
||||
initBall();
|
||||
memset(gStatusLine, 0, sizeof(gStatusLine));
|
||||
isInitialized = true;
|
||||
|
||||
while(isInitialized)
|
||||
{
|
||||
Tick();
|
||||
if(!isPaused)
|
||||
{
|
||||
if(swap == 0)
|
||||
{
|
||||
blockAnim = (blockAnim + 1) % 4;
|
||||
}
|
||||
|
||||
swap = (swap + 1) % 4;
|
||||
|
||||
drawScore();
|
||||
drawWall();
|
||||
drawRacket();
|
||||
drawBall();
|
||||
|
||||
if(isBeep)
|
||||
{
|
||||
playBeep(tone);
|
||||
isBeep = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
SYSTEM_DelayMs(40 - MIN(levelCountBreackout - 1, 20)); // Add more fun...
|
||||
}
|
||||
}
|
||||
|
||||
ST7565_BlitStatusLine(); // Blank status line
|
||||
ST7565_BlitFullScreen();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/* Copyright 2025 Armel F4HWN
|
||||
* https://github.com/armel
|
||||
*
|
||||
* 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 "../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 "../audio.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define BRICK_NUMBER 18
|
||||
#define BALL_NUMBER 5
|
||||
|
||||
typedef struct {
|
||||
uint8_t x; // x
|
||||
uint8_t y; // y
|
||||
uint8_t w; // width
|
||||
uint8_t h; // height
|
||||
uint8_t s; // style
|
||||
bool destroy; // active, if true, check this button, else bypass
|
||||
} Brick;
|
||||
|
||||
typedef struct {
|
||||
int8_t x; // x
|
||||
uint8_t y; // y
|
||||
uint8_t w; // width
|
||||
uint8_t h; // height
|
||||
uint8_t p; // previous x
|
||||
} Racket;
|
||||
|
||||
typedef struct {
|
||||
int16_t x; // x
|
||||
int8_t y; // y
|
||||
uint8_t w; // width
|
||||
uint8_t h; // height
|
||||
int8_t dx; // move x
|
||||
int8_t dy; // move y
|
||||
} Ball;
|
||||
|
||||
typedef struct KeyboardState
|
||||
{
|
||||
KEY_Code_t current;
|
||||
KEY_Code_t prev;
|
||||
uint8_t counter;
|
||||
} KeyboardState;
|
||||
|
||||
void initWall(void);
|
||||
void drawWall(void);
|
||||
void initRacket(void);
|
||||
void drawRacket(void);
|
||||
void APP_RunBreakout(void);
|
||||
+12
-1
@@ -31,6 +31,10 @@
|
||||
#include "app/spectrum.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_GAME
|
||||
#include "app/breakout.h"
|
||||
#endif
|
||||
|
||||
#include "audio.h"
|
||||
#include "board.h"
|
||||
#include "driver/bk4819.h"
|
||||
@@ -582,6 +586,13 @@ static void MAIN_Key_DIGITS(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld)
|
||||
ACTION_BackLight();
|
||||
return;
|
||||
}
|
||||
#ifdef ENABLE_FEAT_F4HWN_GAME
|
||||
else if(Key == 7)
|
||||
{
|
||||
APP_RunBreakout();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
processFKeyFunction(Key, true);
|
||||
}
|
||||
@@ -660,7 +671,7 @@ static void MAIN_Key_MENU(bool bKeyPressed, bool bKeyHeld)
|
||||
// Exclude work with list 1, 2, 3 or all list
|
||||
if(gScanStateDir != SCAN_OFF)
|
||||
{
|
||||
if(FUNCTION_IsRx())
|
||||
if(FUNCTION_IsRx() || gScanPauseDelayIn_10ms > 9)
|
||||
{
|
||||
gMR_ChannelExclude[gTxVfo->CHANNEL_SAVE] = true;
|
||||
|
||||
|
||||
+29
-2
@@ -103,11 +103,18 @@ RegisterSpec registerSpecs[] = {
|
||||
{},
|
||||
{"LNAs", BK4819_REG_13, 8, 0b11, 1},
|
||||
{"LNA", BK4819_REG_13, 5, 0b111, 1},
|
||||
{"PGA", BK4819_REG_13, 0, 0b111, 1},
|
||||
{"IF", BK4819_REG_3D, 0, 0xFFFF, 0x2aaa},
|
||||
{"VGA", BK4819_REG_13, 0, 0b111, 1},
|
||||
{"BPF", BK4819_REG_3D, 0, 0xFFFF, 0x2aaa},
|
||||
// {"MIX", 0x13, 3, 0b11, 1}, // TODO: hidden
|
||||
};
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_SPECTRUM
|
||||
const int8_t LNAsOptions[] = {-19, -16, -11, 0};
|
||||
const int8_t LNAOptions[] = {-24, -19, -14, -9, -6, -4, -2, 0};
|
||||
const int8_t VGAOptions[] = {-33, -27, -21, -15, -9, -6, -3, 0};
|
||||
const char *BPFOptions[] = {"8.46", "7.25", "6.35", "5.64", "5.08", "4.62", "4.23"};
|
||||
#endif
|
||||
|
||||
uint16_t statuslineUpdateTimer = 0;
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_SPECTRUM
|
||||
@@ -1387,7 +1394,27 @@ static void RenderStill()
|
||||
sprintf(String, "%s", registerSpecs[idx].name);
|
||||
GUI_DisplaySmallest(String, offset + 2, row * 8 + 2, false,
|
||||
menuState != idx);
|
||||
|
||||
#ifdef ENABLE_FEAT_F4HWN_SPECTRUM
|
||||
if(idx == 1)
|
||||
{
|
||||
sprintf(String, "%ddB", LNAsOptions[GetRegMenuValue(idx)]);
|
||||
}
|
||||
else if(idx == 2)
|
||||
{
|
||||
sprintf(String, "%ddB", LNAOptions[GetRegMenuValue(idx)]);
|
||||
}
|
||||
else if(idx == 3)
|
||||
{
|
||||
sprintf(String, "%ddB", VGAOptions[GetRegMenuValue(idx)]);
|
||||
}
|
||||
else if(idx == 4)
|
||||
{
|
||||
sprintf(String, "%skHz", BPFOptions[(GetRegMenuValue(idx) / 0x2aaa)]);
|
||||
}
|
||||
#else
|
||||
sprintf(String, "%u", GetRegMenuValue(idx));
|
||||
#endif
|
||||
GUI_DisplaySmallest(String, offset + 2, (row + 1) * 8 + 1, false,
|
||||
menuState != idx);
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+76
-43
@@ -1,26 +1,38 @@
|
||||
#!/bin/sh
|
||||
#export DOCKER_DEFAULT_PLATFORM=linux/amd64
|
||||
#export DOCKER_NETWORK="--network=host"
|
||||
|
||||
IMAGE_NAME="uvk5"
|
||||
rm "${PWD}/compiled-firmware/*"
|
||||
echo "Building docker image $IMAGE_NAME"
|
||||
if ! docker build -t $DOCKER_NETWORK $IMAGE_NAME .
|
||||
then
|
||||
echo "Failed to build docker image"
|
||||
exit 1
|
||||
FIRMWARE_DIR="${PWD}/compiled-firmware"
|
||||
|
||||
# Create firmware output directory if it doesn't exist
|
||||
mkdir -p "$FIRMWARE_DIR"
|
||||
|
||||
# Clean previously compiled firmware files
|
||||
rm -f "$FIRMWARE_DIR"/*
|
||||
|
||||
# Build image only if it doesn't already exist
|
||||
if ! docker image inspect "$IMAGE_NAME" >/dev/null 2>&1; then
|
||||
echo "Docker image '$IMAGE_NAME' not found, building..."
|
||||
if ! docker build --build-arg BUILDPLATFORM=linux/amd64 -t "$IMAGE_NAME" .; then
|
||||
echo "❌ Failed to build docker image"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# ------------------ BUILD VARIANTS ------------------
|
||||
|
||||
custom() {
|
||||
echo "Custom compilation..."
|
||||
docker run --rm -v "${PWD}/compiled-firmware/:/app/compiled-firmware" $IMAGE_NAME /bin/bash -c "rm ./compiled-firmware/*; cd /app && make -s \
|
||||
echo "🔧 Custom compilation..."
|
||||
docker run --rm -v "$FIRMWARE_DIR:/app/compiled-firmware" "$IMAGE_NAME" /bin/bash -c "\
|
||||
rm -f ./compiled-firmware/* && cd /app && make -s \
|
||||
EDITION_STRING=Custom \
|
||||
TARGET=f4hwn.custom \
|
||||
&& cp f4hwn.custom* compiled-firmware/"
|
||||
}
|
||||
|
||||
standard() {
|
||||
echo "Standard compilation..."
|
||||
docker run --rm -v "${PWD}/compiled-firmware:/app/compiled-firmware" $IMAGE_NAME /bin/bash -c "rm ./compiled-firmware/*; cd /app && make -s \
|
||||
echo "📦 Standard compilation..."
|
||||
docker run --rm -v "$FIRMWARE_DIR:/app/compiled-firmware" "$IMAGE_NAME" /bin/bash -c "\
|
||||
rm -f ./compiled-firmware/* && cd /app && make -s \
|
||||
ENABLE_SPECTRUM=0 \
|
||||
ENABLE_FMRADIO=0 \
|
||||
ENABLE_AIRCOPY=0 \
|
||||
@@ -31,11 +43,14 @@ standard() {
|
||||
}
|
||||
|
||||
bandscope() {
|
||||
echo "Bandscope compilation..."
|
||||
docker run --rm -v "${PWD}/compiled-firmware/:/app/compiled-firmware" $IMAGE_NAME /bin/bash -c "rm ./compiled-firmware/*; cd /app && make -s \
|
||||
echo "📺 Bandscope compilation..."
|
||||
docker run --rm -v "$FIRMWARE_DIR:/app/compiled-firmware" "$IMAGE_NAME" /bin/bash -c "\
|
||||
rm -f ./compiled-firmware/* && cd /app && make -s \
|
||||
ENABLE_SPECTRUM=1 \
|
||||
ENABLE_FMRADIO=0 \
|
||||
ENABLE_VOX=0 \
|
||||
ENABLE_AIRCOPY=1 \
|
||||
ENABLE_FEAT_F4HWN_GAME=0 \
|
||||
ENABLE_FEAT_F4HWN_PMR=1 \
|
||||
ENABLE_FEAT_F4HWN_GMRS_FRS_MURS=1 \
|
||||
ENABLE_NOAA=0 \
|
||||
@@ -46,32 +61,37 @@ bandscope() {
|
||||
}
|
||||
|
||||
broadcast() {
|
||||
echo "Broadcast compilation..."
|
||||
docker run --rm -v "${PWD}/compiled-firmware:/app/compiled-firmware" $IMAGE_NAME /bin/bash -c "cd /app && make -s \
|
||||
echo "📻 Broadcast compilation..."
|
||||
docker run --rm -v "$FIRMWARE_DIR:/app/compiled-firmware" "$IMAGE_NAME" /bin/bash -c "\
|
||||
cd /app && make -s \
|
||||
ENABLE_SPECTRUM=0 \
|
||||
ENABLE_FMRADIO=1 \
|
||||
ENABLE_VOX=1 \
|
||||
ENABLE_AIRCOPY=1 \
|
||||
ENABLE_FEAT_F4HWN_GAME=0 \
|
||||
ENABLE_FEAT_F4HWN_PMR=1 \
|
||||
ENABLE_FEAT_F4HWN_GMRS_FRS_MURS=1 \
|
||||
ENABLE_NOAA=0 \
|
||||
EDITION_STRING=Broadcast \
|
||||
ENABLE_FEAT_F4HWN_RESCUE_OPS=0 \
|
||||
EDITION_STRING=Broadcast \
|
||||
TARGET=f4hwn.broadcast \
|
||||
&& cp f4hwn.broadcast* compiled-firmware/"
|
||||
}
|
||||
|
||||
basic() {
|
||||
echo "Basic compilation..."
|
||||
docker run --rm -v "${PWD}/compiled-firmware:/app/compiled-firmware" $IMAGE_NAME /bin/bash -c "cd /app && make -s \
|
||||
echo "☘️ Basic compilation..."
|
||||
docker run --rm -v "$FIRMWARE_DIR:/app/compiled-firmware" "$IMAGE_NAME" /bin/bash -c "\
|
||||
cd /app && make -s \
|
||||
ENABLE_SPECTRUM=1 \
|
||||
ENABLE_FMRADIO=1 \
|
||||
ENABLE_VOX=0 \
|
||||
ENABLE_AIRCOPY=0 \
|
||||
ENABLE_AUDIO_BAR=0 \
|
||||
ENABLE_FEAT_F4HWN_GAME=0 \
|
||||
ENABLE_FEAT_F4HWN_SPECTRUM=0 \
|
||||
ENABLE_FEAT_F4HWN_PMR=1 \
|
||||
ENABLE_FEAT_F4HWN_GMRS_FRS_MURS=1 \
|
||||
ENABLE_NOAA=0 \
|
||||
ENABLE_AUDIO_BAR=0 \
|
||||
ENABLE_FEAT_F4HWN_RESUME_STATE=0 \
|
||||
ENABLE_FEAT_F4HWN_CHARGING_C=0 \
|
||||
ENABLE_FEAT_F4HWN_INV=1 \
|
||||
@@ -84,11 +104,14 @@ basic() {
|
||||
}
|
||||
|
||||
rescueops() {
|
||||
echo "RescueOps compilation..."
|
||||
docker run --rm -v "${PWD}/compiled-firmware:/app/compiled-firmware" $IMAGE_NAME /bin/bash -c "cd /app && make -s \
|
||||
echo "🚨 RescueOps compilation..."
|
||||
docker run --rm -v "$FIRMWARE_DIR:/app/compiled-firmware" "$IMAGE_NAME" /bin/bash -c "\
|
||||
cd /app && make -s \
|
||||
ENABLE_SPECTRUM=0 \
|
||||
ENABLE_FMRADIO=0 \
|
||||
ENABLE_VOX=1 \
|
||||
ENABLE_AIRCOPY=1 \
|
||||
ENABLE_FEAT_F4HWN_GAME=0 \
|
||||
ENABLE_FEAT_F4HWN_PMR=1 \
|
||||
ENABLE_FEAT_F4HWN_GMRS_FRS_MURS=1 \
|
||||
ENABLE_NOAA=1 \
|
||||
@@ -98,33 +121,43 @@ rescueops() {
|
||||
&& cp f4hwn.rescueops* compiled-firmware/"
|
||||
}
|
||||
|
||||
game() {
|
||||
echo "🎮 Game compilation..."
|
||||
docker run --rm -v "$FIRMWARE_DIR:/app/compiled-firmware" "$IMAGE_NAME" /bin/bash -c "\
|
||||
cd /app && make -s \
|
||||
ENABLE_SPECTRUM=0 \
|
||||
ENABLE_FMRADIO=1 \
|
||||
ENABLE_VOX=0 \
|
||||
ENABLE_AIRCOPY=1 \
|
||||
ENABLE_FEAT_F4HWN_GAME=1 \
|
||||
ENABLE_FEAT_F4HWN_PMR=1 \
|
||||
ENABLE_FEAT_F4HWN_GMRS_FRS_MURS=1 \
|
||||
ENABLE_NOAA=0 \
|
||||
ENABLE_FEAT_F4HWN_RESCUE_OPS=0 \
|
||||
EDITION_STRING=Game \
|
||||
TARGET=f4hwn.game \
|
||||
&& cp f4hwn.game* compiled-firmware/"
|
||||
}
|
||||
|
||||
# ------------------ MENU ------------------
|
||||
|
||||
case "$1" in
|
||||
custom)
|
||||
custom
|
||||
;;
|
||||
standard)
|
||||
standard
|
||||
;;
|
||||
bandscope)
|
||||
bandscope
|
||||
;;
|
||||
broadcast)
|
||||
broadcast
|
||||
;;
|
||||
basic)
|
||||
basic
|
||||
;;
|
||||
rescueops)
|
||||
rescueops
|
||||
;;
|
||||
custom) custom ;;
|
||||
standard) standard ;;
|
||||
bandscope) bandscope ;;
|
||||
broadcast) broadcast ;;
|
||||
basic) basic ;;
|
||||
rescueops) rescueops ;;
|
||||
game) game ;;
|
||||
all)
|
||||
bandscope
|
||||
broadcast
|
||||
rescueops
|
||||
basic
|
||||
rescueops
|
||||
game
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {custom|bandscope|broadcast|basic|standard|all}"
|
||||
echo "Usage: $0 {custom|standard|bandscope|broadcast|basic|rescueops|game|all} [--rebuild]"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
esac
|
||||
+1
-1
@@ -1004,7 +1004,7 @@ State[1] = 0
|
||||
#ifdef ENABLE_BYP_RAW_DEMODULATORS
|
||||
| (1 << 2)
|
||||
#endif
|
||||
#ifdef ENABLE_BLMIN_TMP_OFF
|
||||
#ifdef ENABLE_FEAT_F4HWN_GAME
|
||||
| (1 << 3)
|
||||
#endif
|
||||
#ifdef ENABLE_AM_FIX
|
||||
|
||||
@@ -1227,6 +1227,8 @@ void UI_DisplayMenu(void)
|
||||
|
||||
#if defined(ENABLE_SPECTRUM) && defined(ENABLE_FMRADIO)
|
||||
UI_PrintStringSmallNormal("Basic", 54, 127, 6);
|
||||
#elif defined(ENABLE_FEAT_F4HWN_GAME)
|
||||
UI_PrintStringSmallNormal("Game", 54, 127, 6);
|
||||
#elif defined(ENABLE_SPECTRUM)
|
||||
UI_PrintStringSmallNormal("Bandscope", 54, 127, 6);
|
||||
#elif defined(ENABLE_FMRADIO)
|
||||
|
||||
Reference in new issue
Block a user