diff --git a/App/app/action.c b/App/app/action.c index dd59cfaa..df33e903 100644 --- a/App/app/action.c +++ b/App/app/action.c @@ -212,7 +212,7 @@ void ACTION_Scan(bool bRestart) DTMF_clear_RX(); #endif gDTMF_RX_live_timeout = 0; - memset(gDTMF_RX_live, 0, sizeof(gDTMF_RX_live)); + DTMF_clear_input_box_memory(); RADIO_SelectVfos(); diff --git a/App/app/app.c b/App/app/app.c index 45243570..555340e3 100644 --- a/App/app/app.c +++ b/App/app/app.c @@ -1560,7 +1560,7 @@ void APP_TimeSlice500ms(void) { if (gDTMF_RX_live[0] != 0) { - memset(gDTMF_RX_live, 0, sizeof(gDTMF_RX_live)); + DTMF_clear_input_box_memory(); gUpdateDisplay = true; } } @@ -1908,7 +1908,7 @@ static void ProcessKey(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld) if (Key == KEY_EXIT && bKeyHeld) { // exit key held pressed // clear the live DTMF decoder if (gDTMF_RX_live[0] != 0) { - memset(gDTMF_RX_live, 0, sizeof(gDTMF_RX_live)); + DTMF_clear_input_box_memory(); gDTMF_RX_live_timeout = 0; gUpdateDisplay = true; } diff --git a/App/app/breakout.c b/App/app/breakout.c index cbbf4c3f..560fb090 100644 --- a/App/app/breakout.c +++ b/App/app/breakout.c @@ -25,9 +25,8 @@ static uint8_t blockAnim = 0; static bool isInitialized = false; bool isPaused = false; -bool isBeep = false; -uint8_t levelCountBreackout = 1; +uint8_t levelCountBreakout = 1; uint16_t tone = 0; uint16_t score = 0; @@ -42,115 +41,7 @@ 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, -}; +static const uint8_t BRICK_ANIM_PATTERNS[4] = {0b00110001, 0b00101001, 0b00100101, 0b00100011}; // Initialise seed void srand_custom(uint32_t seed) { @@ -172,7 +63,7 @@ int randInt(int min, int max) { void reset(void) { ballCount = BALL_NUMBER; - levelCountBreackout = 1; + levelCountBreakout = 1; score = 0; } @@ -191,10 +82,10 @@ void playBeep(uint16_t tone) void drawScore() { // Clean status line - memset(gStatusLine, 0, sizeof(gStatusLine)); + UI_StatusClear(); // Level - sprintf(str, "Level %02u", levelCountBreackout); + sprintf(str, "Level %02u", levelCountBreakout); GUI_DisplaySmallest(str, 0, 1, true, true); // Ball @@ -206,6 +97,12 @@ void drawScore() GUI_DisplaySmallest(str, 88, 1, true, true); } +// Render the ball +void renderBall(bool state) { + UI_DrawRectangleBuffer(gFrameBuffer, ball.x, ball.y, ball.x + ball.w - 1, ball.y + ball.h - 1, state); + UI_DrawLineBuffer(gFrameBuffer, ball.x - 1, ball.y + 1, ball.x + ball.w, ball.y + 1, state); +} + // Init ball void initBall() { ball.x = 62; @@ -215,21 +112,25 @@ void initBall() { 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); + renderBall(true); +} + +// Calculate the direction of the bounced ball +void directionBall(int16_t x, uint8_t w, int8_t num) { + ball.dx = map(x + w - ball.x, 0, w, num, -num); + ball.dy *= -1; } // 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); + renderBall(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.dx = randInt(-3, 3); ball.dy = 1; } else if (ball.x <= 2) // Left @@ -243,9 +144,7 @@ void drawBall() { // 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; + directionBall(racket.x, racket.w, 3); tone = 400; } } @@ -253,7 +152,6 @@ void drawBall() { ballCount--; UI_DisplayClear(); drawScore(); - isBeep = true; tone = 800; if (ballCount < 0) { reset(); @@ -261,15 +159,13 @@ void drawBall() { drawWall(); isPaused = true; - UI_PrintStringSmallBold("GAME", 32, 0, 4); - UI_PrintStringSmallBold("OVER", 66, 0, 4); + UI_PrintStringSmallBold("GAME OVER", 0, LCD_WIDTH - 1, 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); + renderBall(true); } // Init wall @@ -289,7 +185,6 @@ void initWall() { 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++; @@ -302,6 +197,11 @@ void drawWall() { for (i = 0; i < BRICK_NUMBER; i++) { if (brick[i].destroy == false) { + uint8_t *fb_ptr = gFrameBuffer[brick[i].y / 8] + brick[i].x; + + fb_ptr[0] = 0b00011110; + fb_ptr[14] = 0b00011110; + if ((ball.x + 1 >= brick[i].x && ball.x - 1 <= brick[i].x + brick[i].w) && ((ball.y + 1 >= brick[i].y && @@ -309,32 +209,37 @@ void drawWall() { 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; + directionBall(brick[i].x, brick[i].w, 2); BK4819_ToggleGpioOut(BK4819_GPIO6_PIN2_GREEN, true); - memcpy(gFrameBuffer[brick[i].y / 8] + brick[i].x, BITMAP_blockOn, sizeof(BITMAP_blockOn)); + memset(fb_ptr + 1, 0b00111111, 13); ST7565_BlitLine(brick[i].y / 8); playBeep(600); - memcpy(gFrameBuffer[brick[i].y / 8] + brick[i].x, BITMAP_blockEmpty, sizeof(BITMAP_blockEmpty)); + memset(fb_ptr + 0, 0b00000000, 15); ST7565_BlitLine(brick[i].y / 8); BK4819_ToggleGpioOut(BK4819_GPIO6_PIN2_GREEN, false); if (score % BRICK_NUMBER == 0) { - levelCountBreackout++; + levelCountBreakout++; 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])); + } else { + for(uint8_t k = 0; k < 13; k++) { + fb_ptr[k + 1] = BRICK_ANIM_PATTERNS[(blockAnim + k) % 4]; + } } } } } +// Render the racket shape +void renderRacket(int x, bool state) { + UI_DrawRectangleBuffer(gFrameBuffer, x + 1, racket.y, x + racket.w - 2, racket.y + racket.h, state); + UI_DrawLineBuffer(gFrameBuffer, x, racket.y + 1, x + racket.w - 1, racket.y + 1, state); +} + // Init racket void initRacket() { racket.w = 24; @@ -343,18 +248,15 @@ void initRacket() { 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); + renderRacket(racket.x, 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); + renderRacket(racket.p, 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); + renderRacket(racket.x, true); } } @@ -382,7 +284,7 @@ static void OnKeyDown(uint8_t key) kbd.counter = 0; if(isPaused) { - UI_PrintStringSmallBold("PAUSE", 0, 128, 4); + UI_PrintStringSmallBold("PAUSE", 0, LCD_WIDTH - 1, 4); } break; case KEY_EXIT: @@ -416,17 +318,13 @@ static bool HandleUserInput() if (kbd.current == KEY_INVALID) return true; - // Movement keys: dispatch on every tick while held - if (kbd.current == KEY_UP || kbd.current == KEY_DOWN || - kbd.current == KEY_4 || kbd.current == KEY_0) - { - OnKeyDown(kbd.current); - return true; - } - - // Action keys (MENU, EXIT): dispatch only on rising edge - if (kbd.current != kbd.prev) - { + if ( + // Movement keys: dispatch on every tick while held + (kbd.current == KEY_UP || kbd.current == KEY_DOWN || + kbd.current == KEY_4 || kbd.current == KEY_0) || + // Action keys (MENU, EXIT): dispatch only on rising edge + (kbd.current != kbd.prev) + ){ OnKeyDown(kbd.current); } @@ -441,62 +339,62 @@ static void Tick() // APP_RunBreakout void APP_RunBreakout(void) { - static uint8_t swap = 0; + static uint8_t swap = 0; - // Init seed - srand_custom(BK4819_ReadRegister(BK4819_REG_67) & 0x01FF * gBatteryVoltageAverage * gEeprom.VfoInfo[0].pRX->Frequency); + // 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 led + BK4819_ToggleGpioOut(BK4819_GPIO6_PIN2_GREEN, false); - // Finish the brightness fade if it is in progress - BACKLIGHT_UpdateTickless(); + // Finish the brightness fade if it is in progress + BACKLIGHT_UpdateTickless(); - // Init game - UI_DisplayClear(); - reset(); - initWall(); - initRacket(); - initBall(); - memset(gStatusLine, 0, sizeof(gStatusLine)); - isInitialized = true; + // Init game + UI_DisplayClear(); + reset(); + initWall(); + initRacket(); + initBall(); + UI_StatusClear(); + isInitialized = true; - while(isInitialized) + while(isInitialized) + { + Tick(); + if(!isPaused) { - Tick(); - if(!isPaused) + if(swap == 0) { - 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... - } + blockAnim = (blockAnim + 1) % 4; } + + swap = (swap + 1) % 4; - ST7565_BlitStatusLine(); // Blank status line - ST7565_BlitFullScreen(); - - #ifdef ENABLE_FEAT_F4HWN_SCREENSHOT - if(isPaused || swap == 0) - { - SCREENSHOT_Update(false); - } - #endif + drawScore(); + drawWall(); + drawRacket(); + drawBall(); + + if(tone != 0) + { + playBeep(tone); + tone = 0; + } + else + { + SYSTEM_DelayMs(40 - MIN(levelCountBreakout - 1, 20)); // Add more fun... + } } + + ST7565_BlitStatusLine(); // Blank status line + ST7565_BlitFullScreen(); + + #ifdef ENABLE_FEAT_F4HWN_SCREENSHOT + if(isPaused || swap == 0) + { + SCREENSHOT_Update(false); + } + #endif + } } \ No newline at end of file diff --git a/App/app/breakout.h b/App/app/breakout.h index afea94c1..3f71b194 100644 --- a/App/app/breakout.h +++ b/App/app/breakout.h @@ -49,7 +49,6 @@ typedef struct { 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; diff --git a/App/app/dtmf.c b/App/app/dtmf.c index 70d5fe6f..bfa88ea9 100644 --- a/App/app/dtmf.c +++ b/App/app/dtmf.c @@ -212,6 +212,10 @@ DTMF_CallMode_t DTMF_CheckGroupCall(const char *pMsg, const unsigned int size) } #endif +void DTMF_clear_input_box_memory() { + memset(gDTMF_RX_live, 0, sizeof(gDTMF_RX_live)); +} + void DTMF_clear_input_box(void) { memset(gDTMF_InputBox, 0, sizeof(gDTMF_InputBox)); diff --git a/App/app/dtmf.h b/App/app/dtmf.h index 0e513838..dba3235e 100644 --- a/App/app/dtmf.h +++ b/App/app/dtmf.h @@ -82,6 +82,7 @@ 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_memory(void); void DTMF_clear_input_box(void); void DTMF_Append(const char code); void DTMF_Reply(void); diff --git a/App/app/menu.c b/App/app/menu.c index 6f2f5b36..4de5b74d 100644 --- a/App/app/menu.c +++ b/App/app/menu.c @@ -800,7 +800,7 @@ void MENU_AcceptSetting(void) case MENU_D_LIVE_DEC: gSetting_live_DTMF_decoder = gSubMenuSelection; gDTMF_RX_live_timeout = 0; - memset(gDTMF_RX_live, 0, sizeof(gDTMF_RX_live)); + DTMF_clear_input_box_memory(); if (!gSetting_live_DTMF_decoder) BK4819_DisableDTMF(); gFlagReconfigureVfos = true; diff --git a/App/app/spectrum.c b/App/app/spectrum.c index bc150502..2bc82673 100644 --- a/App/app/spectrum.c +++ b/App/app/spectrum.c @@ -1574,6 +1574,11 @@ static void ShowChannelName(uint32_t f) static uint32_t channelF = 0; static char channelName[12]; + // Channel name starts at x=43 (fixed), leaving room for the dBm + // string on the left (max ~40 px) and battery indicator at x=116. + // Clear first so a shorter name doesn't leave stale pixels. + memset(&gStatusLine[43], 0, 116 - 43); + if (isListening) { if (f != channelF) { @@ -1593,19 +1598,9 @@ static void ShowChannelName(uint32_t f) } } if (channelName[0] != 0) { - // Channel name starts at x=43 (fixed), leaving room for the dBm - // string on the left (max ~40 px) and battery indicator at x=116. - // Clear first so a shorter name doesn't leave stale pixels. - memset(&gStatusLine[43], 0, 116 - 43); UI_PrintStringSmallBufferNormal(channelName, gStatusLine + 43); - } else { - memset(&gStatusLine[43], 0, 116 - 43); } } - else - { - memset(&gStatusLine[43], 0, 116 - 43); - } ST7565_BlitStatusLine(); } @@ -1948,7 +1943,7 @@ static void RenderFreqInput() { UI_PrintString(freqInputString, 2, 127, 0, 8); } static void RenderStatus() { - memset(gStatusLine, 0, sizeof(gStatusLine)); + UI_StatusClear(); DrawStatus(); ST7565_BlitStatusLine(); } diff --git a/App/functions.c b/App/functions.c index e68e6723..f4794f91 100644 --- a/App/functions.c +++ b/App/functions.c @@ -151,7 +151,7 @@ void FUNCTION_Transmit() // clear the DTMF RX live decoder buffer gDTMF_RX_live_timeout = 0; - memset(gDTMF_RX_live, 0, sizeof(gDTMF_RX_live)); + DTMF_clear_input_box_memory(); #if defined(ENABLE_FMRADIO) if (gFmRadioMode) diff --git a/App/ui/helper.c b/App/ui/helper.c index a0edd501..885ab769 100644 --- a/App/ui/helper.c +++ b/App/ui/helper.c @@ -406,3 +406,8 @@ void UI_DisplayClear() { memset(gFrameBuffer, 0, sizeof(gFrameBuffer)); } + +void UI_StatusClear() +{ + memset(gStatusLine, 0, sizeof(gStatusLine)); +} diff --git a/App/ui/helper.h b/App/ui/helper.h index 0002f2cb..c50653d0 100644 --- a/App/ui/helper.h +++ b/App/ui/helper.h @@ -45,5 +45,6 @@ void UI_DrawLineBuffer(uint8_t (*buffer)[128], int16_t x1, int16_t y1, int16_t x void UI_DrawRectangleBuffer(uint8_t (*buffer)[128], int16_t x1, int16_t y1, int16_t x2, int16_t y2, bool black); void UI_DisplayClear(); +void UI_StatusClear(); #endif diff --git a/App/ui/lock.c b/App/ui/lock.c index c787b236..20f3189b 100644 --- a/App/ui/lock.c +++ b/App/ui/lock.c @@ -34,7 +34,7 @@ static void Render(void) unsigned int i; char String[7]; - memset(gStatusLine, 0, sizeof(gStatusLine)); + UI_StatusClear(); UI_DisplayClear(); UI_PrintString("PASSWORD", 0, 127, 1, 10); @@ -80,16 +80,7 @@ void UI_DisplayLock(void) 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: + case KEY_0...KEY_9: INPUTBOX_Append(Key - KEY_0); if (gInputBoxIndex < 6) // 6 frequency digits diff --git a/App/ui/status.c b/App/ui/status.c index ca146871..a9518d8c 100644 --- a/App/ui/status.c +++ b/App/ui/status.c @@ -59,7 +59,7 @@ void UI_DisplayStatus() char str[8] = ""; gUpdateStatus = false; - memset(gStatusLine, 0, sizeof(gStatusLine)); + UI_StatusClear(); uint8_t *line = gStatusLine; unsigned int x = 0; diff --git a/App/ui/welcome.c b/App/ui/welcome.c index 3188484c..69520590 100644 --- a/App/ui/welcome.c +++ b/App/ui/welcome.c @@ -189,7 +189,7 @@ void UI_DrawQRCode(bool wiki, uint8_t origin_x, uint8_t origin_y) void UI_DisplayReleaseKeys(void) { - memset(gStatusLine, 0, sizeof(gStatusLine)); + UI_StatusClear(); #if defined(ENABLE_FEAT_F4HWN_CTR) || defined(ENABLE_FEAT_F4HWN_INV) ST7565_ContrastAndInv(); #endif @@ -209,7 +209,7 @@ void UI_DisplayWelcome(void) char WelcomeString2[16]; char WelcomeString3[32]; - memset(gStatusLine, 0, sizeof(gStatusLine)); + UI_StatusClear(); #if defined(ENABLE_FEAT_F4HWN_CTR) || defined(ENABLE_FEAT_F4HWN_INV) ST7565_ContrastAndInv(); @@ -222,11 +222,13 @@ void UI_DisplayWelcome(void) if (gEeprom.POWER_ON_DISPLAY_MODE == POWER_ON_DISPLAY_MODE_NONE || gEeprom.POWER_ON_DISPLAY_MODE == POWER_ON_DISPLAY_MODE_SOUND) { ST7565_FillScreen(0x00); + } #else if (gEeprom.POWER_ON_DISPLAY_MODE == POWER_ON_DISPLAY_MODE_NONE || gEeprom.POWER_ON_DISPLAY_MODE == POWER_ON_DISPLAY_MODE_FULL_SCREEN) { ST7565_FillScreen(0xFF); + } #endif - } else { + else { memset(WelcomeString0, 0, sizeof(WelcomeString0)); memset(WelcomeString1, 0, sizeof(WelcomeString1));