From cd4475add8bd37f286c6857b33c3c7630e6376a2 Mon Sep 17 00:00:00 2001 From: Dual Tachyon Date: Mon, 28 Aug 2023 18:24:16 +0100 Subject: [PATCH] Split the different screens into ui/. --- Makefile | 8 +- aircopy.c => app/aircopy.c | 2 +- aircopy.h => app/aircopy.h | 0 app/app.c | 3 +- app/menu.c | 3 +- battery.c | 1 + gui.c | 1111 +----------------------------------- gui.h | 71 --- helper.c | 3 +- misc.c | 1 + misc.h | 1 + ui/aircopy.c | 60 ++ ui/aircopy.h | 23 + ui/fmradio.c | 91 +++ ui/fmradio.h | 23 + ui/helper.c | 133 +++++ ui/helper.h | 30 + ui/main.c | 415 ++++++++++++++ ui/main.h | 23 + ui/menu.c | 495 ++++++++++++++++ ui/menu.h | 92 +++ ui/scanner.c | 79 +++ ui/scanner.h | 23 + 23 files changed, 1519 insertions(+), 1172 deletions(-) rename aircopy.c => app/aircopy.c (98%) rename aircopy.h => app/aircopy.h (100%) create mode 100644 ui/aircopy.c create mode 100644 ui/aircopy.h create mode 100644 ui/fmradio.c create mode 100644 ui/fmradio.h create mode 100644 ui/helper.c create mode 100644 ui/helper.h create mode 100644 ui/main.c create mode 100644 ui/main.h create mode 100644 ui/menu.c create mode 100644 ui/menu.h create mode 100644 ui/scanner.c create mode 100644 ui/scanner.h diff --git a/Makefile b/Makefile index fe69126..fdc8daf 100644 --- a/Makefile +++ b/Makefile @@ -34,11 +34,11 @@ OBJS += driver/systick.o OBJS += driver/uart.o # Main +OBJS += app/aircopy.o OBJS += app/app.o OBJS += app/generic.o OBJS += app/main.o OBJS += app/menu.o -OBJS += aircopy.o OBJS += audio.o OBJS += battery.o OBJS += bitmaps.o @@ -55,7 +55,13 @@ OBJS += misc.o OBJS += radio.o OBJS += scheduler.o OBJS += settings.o +OBJS += ui/aircopy.o +OBJS += ui/fmradio.o +OBJS += ui/helper.o OBJS += ui/inputbox.o +OBJS += ui/main.o +OBJS += ui/menu.o +OBJS += ui/scanner.o OBJS += main.o diff --git a/aircopy.c b/app/aircopy.c similarity index 98% rename from aircopy.c rename to app/aircopy.c index 66d59d8..92d075f 100644 --- a/aircopy.c +++ b/app/aircopy.c @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "aircopy.h" +#include "app/aircopy.h" #include "driver/bk4819.h" #include "driver/crc.h" #include "driver/eeprom.h" diff --git a/aircopy.h b/app/aircopy.h similarity index 100% rename from aircopy.h rename to app/aircopy.h diff --git a/app/app.c b/app/app.c index 9bbb289..9317b45 100644 --- a/app/app.c +++ b/app/app.c @@ -15,7 +15,7 @@ */ #include -#include "aircopy.h" +#include "app/aircopy.h" #include "app/app.h" #include "app/generic.h" #include "app/main.h" @@ -43,6 +43,7 @@ #include "settings.h" #include "sram-overlay.h" #include "ui/inputbox.h" +#include "ui/menu.h" static void APP_ProcessKey(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld); void FUN_000069f8(FUNCTION_Type_t Function); diff --git a/app/menu.c b/app/menu.c index 71ddaaa..03fc8be 100644 --- a/app/menu.c +++ b/app/menu.c @@ -12,6 +12,7 @@ #include "settings.h" #include "sram-overlay.h" #include "ui/inputbox.h" +#include "ui/menu.h" static const VOICE_ID_t MenuVoices[] = { VOICE_ID_SQUELCH, @@ -951,7 +952,7 @@ void MENU_Key_MENU(bool bKeyPressed, bool bKeyHeld) break; case 1: gAskForConfirmation = 2; - GUI_DisplayMenu(); + UI_DisplayMenu(); if (gMenuCursor == MENU_RESET) { AUDIO_SetVoiceID(0, VOICE_ID_CONFIRM); AUDIO_PlaySingleVoice(true); diff --git a/battery.c b/battery.c index b844e72..8b065fd 100644 --- a/battery.c +++ b/battery.c @@ -18,6 +18,7 @@ #include "driver/backlight.h" #include "gui.h" #include "misc.h" +#include "ui/menu.h" uint16_t gBatteryCalibration[6]; uint16_t gBatteryCurrentVoltage; diff --git a/gui.c b/gui.c index a778ad4..3817baf 100644 --- a/gui.c +++ b/gui.c @@ -15,165 +15,30 @@ */ #include -#include "aircopy.h" #include "audio.h" #include "battery.h" #include "bitmaps.h" -#include "dcs.h" #include "driver/eeprom.h" #include "driver/keyboard.h" #include "driver/st7565.h" -#include "dtmf.h" #include "external/printf/printf.h" -#include "font.h" #include "fm.h" #include "functions.h" #include "gui.h" #include "helper.h" #include "misc.h" #include "settings.h" +#include "ui/aircopy.h" +#include "ui/fmradio.h" +#include "ui/helper.h" #include "ui/inputbox.h" - -static const char MenuList[][7] = { - // 0x00 - "SQL", "STEP", "TXP", "R_DCS", - "R_CTCS", "T_DCS", "T_CTCS", "SFT-D", - // 0x08 - "OFFSET", "W/N", "SCR", "BCL", - "MEM-CH", "SAVE", "VOX", "ABR", - // 0x10 - "TDR", "WX", "BEEP", "TOT", - "VOICE", "SC-REV", "MDF", "AUTOLK", - // 0x18 - "S-ADD1", "S-ADD2", "STE", "RP-STE", - "MIC", "1-CALL", "S-LIST", "SLIST1", - // 0x20 - "SLIST2", "AL-MOD", "ANI-ID", "UPCODE", - "DWCODE", "D-ST", "D-RSP", "D-HOLD", - // 0x28 - "D-PRE", "PTT-ID", "D-DCD", "D-LIST", - "PONMSG", "ROGER", "VOL", "AM", - // 0x30 - "NOAA_S", "DEL-CH", "RESET", "350TX", - "F-LOCK", "200TX", "500TX", "350EN", - // 0x38 - "SCREN", -}; - -static const uint16_t gSubMenu_Step[] = { - 250, - 500, - 625, - 1000, - 1250, - 2500, - 833, -}; - -static const char gSubMenu_TXP[3][5] = { - "LOW", - "MID", - "HIGH", -}; - -static const char gSubMenu_SFT_D[3][4] = { - "OFF", - "+", - "-", -}; - -static const char gSubMenu_W_N[2][7] = { - "WIDE", - "NARROW", -}; - -static const char gSubMenu_OFF_ON[2][4] = { - "OFF", - "ON", -}; - -static const char gSubMenu_SAVE[5][4] = { - "OFF", - "1:1", - "1:2", - "1:3", - "1:4", -}; - -static const char gSubMenu_CHAN[3][7] = { - "OFF", - "CHAN_A", - "CHAN_B", -}; - -static const char gSubMenu_VOICE[3][4] = { - "OFF", - "CHI", - "ENG", -}; - -static const char gSubMenu_SC_REV[3][3] = { - "TO", - "CO", - "SE", -}; - -static const char gSubMenu_MDF[3][5] = { - "FREQ", - "CHAN", - "NAME", -}; - -static const char gSubMenu_AL_MOD[2][5] = { - "SITE", - "TONE", -}; - -static const char gSubMenu_D_RSP[4][6] = { - "NULL", - "RING", - "REPLY", - "BOTH", -}; - -static const char gSubMenu_PTT_ID[4][5] = { - "OFF", - "BOT", - "EOT", - "BOTH", -}; - -static const char gSubMenu_PONMSG[3][5] = { - "FULL", - "MSG", - "VOL", -}; - -static const char gSubMenu_ROGER[3][6] = { - "OFF", - "ROGER", - "MDC", -}; - -static const char gSubMenu_RESET[2][4] = { - "VFO", - "ALL", -}; - -static const char gSubMenu_F_LOCK[6][4] = { - "OFF", - "FCC", - "CE", - "GB", - "430", - "438", -}; +#include "ui/main.h" +#include "ui/menu.h" +#include "ui/scanner.h" GUI_DisplayType_t gScreenToDisplay; -bool gIsInSubMenu; volatile int8_t gStepDirection; GUI_DisplayType_t gRequestDisplayScreen; -uint8_t g_200003BA; uint8_t g_200003BB; bool gWasFKeyPressed; @@ -181,10 +46,6 @@ uint8_t gAskForConfirmation; bool gAskToSave; bool gAskToDelete; -uint8_t gMenuCursor; -int8_t gMenuScrollDirection; -uint32_t gSubMenuSelection; - void GUI_DisplayBatteryLevel(uint8_t BatteryLevel) { const uint8_t *pBitmap; @@ -236,30 +97,13 @@ void GUI_Welcome(void) EEPROM_ReadBuffer(0x0EB0, WelcomeString0, 16); EEPROM_ReadBuffer(0x0EC0, WelcomeString1, 16); } - GUI_PrintString(WelcomeString0, 0, 127, 1, 10, true); - GUI_PrintString(WelcomeString1, 0, 127, 3, 10, true); + UI_PrintString(WelcomeString0, 0, 127, 1, 10, true); + UI_PrintString(WelcomeString1, 0, 127, 3, 10, true); ST7565_BlitStatusLine(); ST7565_BlitFullScreen(); } } -void GUI_PrintString(const char *pString, uint8_t Start, uint8_t End, uint8_t Line, int Width, bool bCentered) -{ - uint32_t i, Length; - - Length = strlen(pString); - if (bCentered) { - Start += (((End - Start) - (Length * Width)) + 1) / 2; - } - for (i = 0; i < Length; i++) { - if (pString[i] - ' ' < 0x5F) { - uint8_t Index = pString[i] - ' '; - memcpy(gFrameBuffer[Line + 0] + (i * Width) + Start, &gFontBig[Index][0], 8); - memcpy(gFrameBuffer[Line + 1] + (i * Width) + Start, &gFontBig[Index][8], 8); - } - } -} - void GUI_PasswordScreen(void) { KEY_Code_t Key; @@ -342,7 +186,7 @@ void GUI_LockScreen(void) memset(gStatusLine, 0, sizeof(gStatusLine)); memset(gFrameBuffer, 0, sizeof(gFrameBuffer)); strcpy(String, "LOCK"); - GUI_PrintString(String, 0, 127, 1, 10, true); + UI_PrintString(String, 0, 127, 1, 10, true); for (i = 0; i < 6; i++) { if (gInputBox[i] == 10) { String[i] = '-'; @@ -351,7 +195,7 @@ void GUI_LockScreen(void) } } String[6] = 0; - GUI_PrintString(String, 0, 127, 3, 12, true); + UI_PrintString(String, 0, 127, 3, 12, true); ST7565_BlitStatusLine(); ST7565_BlitFullScreen(); } @@ -412,948 +256,23 @@ void GUI_DisplayStatusLine(void) // -static void GenerateChannelString(char *pString, uint8_t Channel) -{ - uint8_t i; - - if (gInputBoxIndex == 0) { - sprintf(pString, "CH-%02d", Channel + 1); - return; - } - - pString[0] = 'C'; - pString[1] = 'H'; - pString[2] = '-'; - - for (i = 0; i < 2; i++) { - if (gInputBox[i] == 10) { - pString[i + 3] = '-'; - } else { - pString[i + 3] = gInputBox[i] + '0'; - } - } - -} - -static void GenerateChannelStringEx(char *pString, bool bShowPrefix, uint8_t ChannelNumber) -{ - if (gInputBoxIndex) { - uint8_t i; - - for (i = 0; i < 3; i++) { - if (gInputBox[i] == 10) { - pString[i] = '-'; - } else { - pString[i] = gInputBox[i] + '0'; - } - } - return; - } - - if (bShowPrefix) { - sprintf(pString, "CH-%03d", ChannelNumber + 1); - } else { - if (ChannelNumber == 0xFF) { - strcpy(pString, "NULL"); - } else { - sprintf(pString, "%03d", ChannelNumber + 1); - } - } -} - -void GUI_DisplayFrequency(const char *pDigits, uint8_t X, uint8_t Y, bool bDisplayLeadingZero, bool Flag1) -{ - uint8_t *pFb0, *pFb1; - bool bCanDisplay; - uint8_t i; - - pFb0 = gFrameBuffer[Y] + X; - pFb1 = pFb0 + 128; - - bCanDisplay = false; - for (i = 0; i < 3; i++) { - const uint8_t Digit = pDigits[i]; - - if (bDisplayLeadingZero || bCanDisplay || Digit) { - bCanDisplay = true; - memcpy(pFb0 + (i * 13), gFontBigDigits[Digit] + 0, 13); - memcpy(pFb1 + (i * 13), gFontBigDigits[Digit] + 13, 13); - } else if (Flag1) { - pFb1 -= 6; - pFb0 -= 6; - } - } - - pFb1[0x27] = 0x60; - pFb1[0x28] = 0x60; - pFb1[0x29] = 0x60; - - for (i = 0; i < 3; i++) { - const uint8_t Digit = pDigits[i + 3]; - - memcpy(pFb0 + (i * 13) + 42, gFontBigDigits[Digit] + 0, 13); - memcpy(pFb1 + (i * 13) + 42, gFontBigDigits[Digit] + 13, 13); - } -} - -void GUI_DisplaySmallDigits(uint8_t Size, const char *pString, uint8_t x, uint8_t y) -{ - uint8_t i; - - for (i = 0; i < Size; i++) { - memcpy(gFrameBuffer[y] + (i * 7) + x, gFontSmallDigits[(uint8_t)pString[i]], 7); - } -} - -static void DisplayMain(void) -{ - char String[16]; - char String2[16]; - uint8_t i; - - memset(gFrameBuffer, 0, sizeof(gFrameBuffer)); - if (gEeprom.KEY_LOCK && gKeypadLocked) { - GUI_PrintString("Long Press #", 0, 127, 1, 8, true); - GUI_PrintString("To Unlock", 0, 127, 3, 8, true); - ST7565_BlitFullScreen(); - return; - } - - for (i = 0; i < 2; i++) { - uint8_t *pLine0; - uint8_t *pLine1; - uint8_t Line; - uint8_t Channel; - bool bIsSameVfo; - - if (i == 0) { - pLine0 = gFrameBuffer[0]; - pLine1 = gFrameBuffer[1]; - Line = 0; - } else { - pLine0 = gFrameBuffer[4]; - pLine1 = gFrameBuffer[5]; - Line = 4; - } - - Channel = gEeprom.TX_CHANNEL; - bIsSameVfo = !!(Channel == i); - - if (gEeprom.DUAL_WATCH != DUAL_WATCH_OFF && g_2000041F == 1) { - Channel = gEeprom.RX_CHANNEL; - } - - if (Channel != i) { - if (g_200003BC || g_200003BD || g_200003BA) { - if (g_200003BA == 0) { - if (g_200003BC == 1) { - if (g_CalloutAndDTMF_State == 2) { - strcpy(String, "CALL OUT(RSP)"); - } else { - strcpy(String, "CALL OUT"); - } - } else if (g_200003BC == 2) { - if (DTMF_FindContact(gDTMF_Contact0, String2)) { - sprintf(String, "CALL:%s", String2); - } else { - sprintf(String, "CALL:%s", gDTMF_Contact0); - } - } else if (g_200003BD == 1) { - if (g_CalloutAndDTMF_State == 1) { - strcpy(String, "DTMF TX(SUCC)"); - } else { - strcpy(String, "DTMF TX"); - } - } - } else { - sprintf(String, ">%s", g_20000D1C); - } - GUI_PrintString(String, 2, 127, i * 3, 8, false); - - memset(String, 0, sizeof(String)); - memset(String2, 0, sizeof(String2)); - - if (g_200003BA == 0) { - if (g_200003BC == 1) { - if (DTMF_FindContact(gDTMF_String, String2)) { - sprintf(String, ">%s", String2); - } else { - sprintf(String, ">%s", gDTMF_String); - } - } else if (g_200003BC == 2) { - if (DTMF_FindContact(gDTMF_Contact1, String2)) { - sprintf(String, ">%s", String2); - } else { - sprintf(String, ">%s", gDTMF_Contact1); - } - } else if (g_200003BD == 1) { - sprintf(String, ">%s", gDTMF_String); - } - } - GUI_PrintString(String, 2, 127, 2 + (i * 3), 8, false); - continue; - } else if (bIsSameVfo) { - memcpy(pLine0 + 2, BITMAP_VFO_Default, sizeof(BITMAP_VFO_Default)); - } - } else { - if (bIsSameVfo) { - memcpy(pLine0 + 2, BITMAP_VFO_Default, sizeof(BITMAP_VFO_Default)); - } else { - memcpy(pLine0 + 2, BITMAP_VFO_NotDefault, sizeof(BITMAP_VFO_NotDefault)); - } - } - - // 0x8EE2 - uint32_t SomeValue = 0; - - if (gCurrentFunction == FUNCTION_TRANSMIT) { - if (g_20000383 == 2) { - SomeValue = 2; - } else { - Channel = gEeprom.RX_CHANNEL; - if (gEeprom.CROSS_BAND_RX_TX != CROSS_BAND_OFF) { - Channel = gEeprom.TX_CHANNEL; - } - if (Channel == i) { - SomeValue = 1; - memcpy(pLine0 + 14, BITMAP_TX, sizeof(BITMAP_TX)); - } - } - } else { - SomeValue = 2; - if ((gCurrentFunction == FUNCTION_4 || gCurrentFunction == FUNCTION_2) && gEeprom.RX_CHANNEL == i) { - memcpy(pLine0 + 14, BITMAP_RX, sizeof(BITMAP_RX)); - } - } - - // 0x8F3C - if (gEeprom.ScreenChannel[i] < 200) { - memcpy(pLine1 + 2, BITMAP_M, sizeof(BITMAP_M)); - if (gInputBoxIndex == 0 || gEeprom.TX_CHANNEL != i) { - NUMBER_ToDigits(gEeprom.ScreenChannel[i] + 1, String); - } else { - memcpy(String + 5, gInputBox, 3); - } - GUI_DisplaySmallDigits(3, String + 5, 10, Line + 1); - } else if (gEeprom.ScreenChannel[i] < 207) { - char c; - - memcpy(pLine1 + 14, BITMAP_F, sizeof(BITMAP_F)); - c = gEeprom.ScreenChannel[i] - 199; - GUI_DisplaySmallDigits(1, &c, 22, Line + 1); - } else { - memcpy(pLine1 + 7, BITMAP_NarrowBand, sizeof(BITMAP_NarrowBand)); - if (gInputBoxIndex == 0 || gEeprom.TX_CHANNEL != i) { - NUMBER_ToDigits(gEeprom.ScreenChannel[i] - 206, String); - } else { - String[6] = gInputBox[0]; - String[7] = gInputBox[1]; - } - GUI_DisplaySmallDigits(2, String + 6, 15, Line + 1); - } - - // 0x8FEC - - uint8_t g371 = g_20000371[i]; - if (gCurrentFunction == FUNCTION_TRANSMIT && g_20000383 == 2) { - if (gEeprom.CROSS_BAND_RX_TX == CROSS_BAND_OFF) { - Channel = gEeprom.RX_CHANNEL; - } else { - Channel = gEeprom.TX_CHANNEL; - } - if (Channel == i) { - g371 = 5; - } - } - if (g371 != 0) { - uint8_t Width = 10; - - memset(String, 0, sizeof(String)); - switch (g371) { - case 1: - strcpy(String, "BUSY"); - Width = 15; - break; - case 2: - strcpy(String, "BAT LOW"); - break; - case 3: - strcpy(String, "DISABLE"); - break; - case 4: - strcpy(String, "TIMEOUT"); - break; - case 5: - strcpy(String, "ALARM"); - break; - case 6: - sprintf(String, "VOL HIGH"); - Width = 8; - break; - } - GUI_PrintString(String, 31, 111, i * 4, Width, true); - } else { - if (gInputBoxIndex && (gEeprom.ScreenChannel[i] - 200) < 7 && gEeprom.TX_CHANNEL == i) { - GUI_DisplayFrequency(gInputBox, 31, i * 4, true, false); - } else { - if (gEeprom.ScreenChannel[i] < 200) { - if (gEeprom.CHANNEL_DISPLAY_MODE == 2 && (gEeprom.VfoInfo[i].Name[0] == 0 || gEeprom.VfoInfo[i].Name[0] == 0xFF)) { - sprintf(String, "CH-%03d", gEeprom.ScreenChannel[i] + 1); - GUI_PrintString(String, 31, 112, i * 4, 8, true); - } else { - switch (gEeprom.CHANNEL_DISPLAY_MODE) { - case 0: - if (gCurrentFunction == FUNCTION_TRANSMIT) { - if (gEeprom.CROSS_BAND_RX_TX == CROSS_BAND_OFF) { - Channel = gEeprom.RX_CHANNEL; - } else { - Channel = gEeprom.TX_CHANNEL; - } - if (Channel == i) { - NUMBER_ToDigits(gEeprom.VfoInfo[i].pDCS_Reverse->Frequency, String); - } else { - NUMBER_ToDigits(gEeprom.VfoInfo[i].pDCS_Current->Frequency, String); - } - } else { - NUMBER_ToDigits(gEeprom.VfoInfo[i].pDCS_Current->Frequency, String); - } - GUI_DisplayFrequency(String, 31, i * 4, false, false); - if (gEeprom.ScreenChannel[i] < 200) { - const uint8_t Attributes = gMR_ChannelAttributes[gEeprom.ScreenChannel[i]]; - if (Attributes & MR_CH_SCANLIST1) { - memcpy(pLine0 + 113, BITMAP_ScanList, sizeof(BITMAP_ScanList)); - } - if (Attributes & MR_CH_SCANLIST2) { - memcpy(pLine0 + 120, BITMAP_ScanList, sizeof(BITMAP_ScanList)); - } - } - GUI_DisplaySmallDigits(2, String + 6, 112, Line + 1); - break; - case 1: - sprintf(String, "CH-%03d", gEeprom.ScreenChannel[i] + 1); - GUI_PrintString(String, 31, 112, i * 4, 8, true); - break; - case 2: - GUI_PrintString(gEeprom.VfoInfo[i].Name, 31, 112, i * 4, 8, true); - break; - } - } - } else { - if (gCurrentFunction == FUNCTION_TRANSMIT) { - if (gEeprom.CROSS_BAND_RX_TX == CROSS_BAND_OFF) { - Channel = gEeprom.RX_CHANNEL; - } else { - Channel = gEeprom.TX_CHANNEL; - } - if (Channel == i) { - NUMBER_ToDigits(gEeprom.VfoInfo[i].pDCS_Reverse->Frequency, String); - } else { - NUMBER_ToDigits(gEeprom.VfoInfo[i].pDCS_Current->Frequency, String); - } - } else { - NUMBER_ToDigits(gEeprom.VfoInfo[i].pDCS_Current->Frequency, String); - } - GUI_DisplayFrequency(String, 31, i * 4, false, false); - if (gEeprom.ScreenChannel[i] < 200) { - const uint8_t Attributes = gMR_ChannelAttributes[gEeprom.ScreenChannel[i]]; - if (Attributes & MR_CH_SCANLIST1) { - memcpy(pLine0 + 113, BITMAP_ScanList, sizeof(BITMAP_ScanList)); - } - if (Attributes & MR_CH_SCANLIST2) { - memcpy(pLine0 + 120, BITMAP_ScanList, sizeof(BITMAP_ScanList)); - } - } - GUI_DisplaySmallDigits(2, String + 6, 112, Line + 1); - } - } - } - - // 0x926E - uint8_t Level = 0; - - if (SomeValue == 1) { - if (gInfoCHAN_A->OUTPUT_POWER == OUTPUT_POWER_LOW) { - Level = 2; - } else if (gInfoCHAN_A->OUTPUT_POWER == OUTPUT_POWER_MID) { - Level = 4; - } else { - Level = 6; - } - } else if (SomeValue == 2) { - if (gVFO_RSSI_Level[i]) { - Level = gVFO_RSSI_Level[i]; - } - } - - // TODO: not quite how the original does it, but it's quite entangled in Ghidra. - if (Level) { - memcpy(pLine1 + 128 + 0, BITMAP_Antenna, sizeof(BITMAP_Antenna)); - memcpy(pLine1 + 128 + 5, BITMAP_AntennaLevel1, sizeof(BITMAP_AntennaLevel1)); - if (Level >= 2) { - memcpy(pLine1 + 128 + 8, BITMAP_AntennaLevel2, sizeof(BITMAP_AntennaLevel2)); - } - if (Level >= 3) { - memcpy(pLine1 + 128 + 11, BITMAP_AntennaLevel3, sizeof(BITMAP_AntennaLevel3)); - } - if (Level >= 4) { - memcpy(pLine1 + 128 + 14, BITMAP_AntennaLevel4, sizeof(BITMAP_AntennaLevel4)); - } - if (Level >= 5) { - memcpy(pLine1 + 128 + 17, BITMAP_AntennaLevel5, sizeof(BITMAP_AntennaLevel5)); - } - if (Level >= 6) { - memcpy(pLine1 + 128 + 20, BITMAP_AntennaLevel6, sizeof(BITMAP_AntennaLevel6)); - } - } - - // 0x931E - if (gEeprom.VfoInfo[i].IsAM == true) { - memcpy(pLine1 + 128 + 27, BITMAP_AM, sizeof(BITMAP_AM)); - } else { - const DCS_Info_t *pDCS; - - if (SomeValue == 1) { - pDCS = gEeprom.VfoInfo[i].pDCS_Reverse; - } else { - pDCS = gEeprom.VfoInfo[i].pDCS_Current; - } - switch (pDCS->CodeType) { - case CODE_TYPE_CONTINUOUS_TONE: - memcpy(pLine1 + 128 + 27, BITMAP_CT, sizeof(BITMAP_CT)); - break; - case CODE_TYPE_DIGITAL: - case CODE_TYPE_REVERSE_DIGITAL: - memcpy(pLine1 + 128 + 24, BITMAP_DCS, sizeof(BITMAP_DCS)); - break; - default: - break; - } - } - - // 0x936C - switch (gEeprom.VfoInfo[i].OUTPUT_POWER) { - case OUTPUT_POWER_LOW: - memcpy(pLine1 + 128 + 44, BITMAP_PowerLow, sizeof(BITMAP_PowerLow)); - break; - case OUTPUT_POWER_MID: - memcpy(pLine1 + 128 + 44, BITMAP_PowerMid, sizeof(BITMAP_PowerMid)); - break; - case OUTPUT_POWER_HIGH: - memcpy(pLine1 + 128 + 44, BITMAP_PowerHigh, sizeof(BITMAP_PowerHigh)); - break; - } - - if (gEeprom.VfoInfo[i].DCS[0].Frequency != gEeprom.VfoInfo[i].DCS[1].Frequency) { - if (gEeprom.VfoInfo[i].FREQUENCY_DEVIATION_SETTING == FREQUENCY_DEVIATION_ADD) { - memcpy(pLine1 + 128 + 54, BITMAP_Add, sizeof(BITMAP_Add)); - } - if (gEeprom.VfoInfo[i].FREQUENCY_DEVIATION_SETTING == FREQUENCY_DEVIATION_SUB) { - memcpy(pLine1 + 128 + 54, BITMAP_Sub, sizeof(BITMAP_Sub)); - } - - } - - if (gEeprom.VfoInfo[i].FrequencyReverse) { - memcpy(pLine1 + 128 + 64, BITMAP_ReverseMode, sizeof(BITMAP_ReverseMode)); - } - if (gEeprom.VfoInfo[i].CHANNEL_BANDWIDTH == BANDWIDTH_NARROW) { - memcpy(pLine1 + 128 + 74, BITMAP_NarrowBand, sizeof(BITMAP_NarrowBand)); - } - if (gEeprom.VfoInfo[i].DTMF_DECODING_ENABLE || gSetting_KILLED) { - memcpy(pLine1 + 128 + 84, BITMAP_DTMF, sizeof(BITMAP_DTMF)); - } - if (gEeprom.VfoInfo[i].SCRAMBLING_TYPE && gSetting_ScrambleEnable) { - memcpy(pLine1 + 128 + 110, BITMAP_Scramble, sizeof(BITMAP_Scramble)); - } - } - - ST7565_BlitFullScreen(); -} - -static void DisplayFM(void) -{ - uint8_t i; - char String[16]; - - memset(gFrameBuffer, 0, sizeof(gFrameBuffer)); - - memset(String, 0, sizeof(String)); - strcpy(String, "FM"); - - GUI_PrintString(String, 0, 127, 0, 12, true); - memset(String, 0, sizeof(String)); - - if (gAskToSave) { - strcpy(String, "SAVE?"); - } else if (gAskToDelete) { - strcpy(String, "DEL?"); - } else { - if (g_20000390 == 0) { - if (gEeprom.FM_IsChannelSelected == false) { - for (i = 0; i < 20; i++) { - if (gEeprom.FM_FrequencyToPlay == gFM_Channels[i]) { - sprintf(String, "VFO(CH%02d)", i + 1); - break; - } - } - if (i == 20) { - strcpy(String, "VFO"); - } - } else { - sprintf(String, "MR(CH%02d)", gEeprom.FM_CurrentChannel + 1); - } - } else { - if (gIs_A_Scan == false) { - strcpy(String, "M-SCAN"); - } else { - sprintf(String, "A-SCAN(%d)", gA_Scan_Channel + 1); - } - } - } - - GUI_PrintString(String, 0, 127, 2, 10, true); - memset(String, 0, sizeof(String)); - - if (gAskToSave || (gEeprom.FM_IsChannelSelected && gInputBoxIndex)) { - GenerateChannelString(String, gA_Scan_Channel); - } else if (gAskToDelete) { - if (gInputBoxIndex == 0) { - NUMBER_ToDigits(gEeprom.FM_FrequencyToPlay * 10000, String); - GUI_DisplayFrequency(String, 23, 4, false, true); - } else { - GUI_DisplayFrequency(gInputBox, 23, 4, true, false); - } - ST7565_BlitFullScreen(); - return; - } else { - sprintf(String, "CH-%02d", gEeprom.FM_CurrentChannel + 1); - } - - GUI_PrintString(String, 0, 127, 4, 10, true); - ST7565_BlitFullScreen(); -} - -void GUI_DisplayMenu(void) -{ - char String[16]; - char Contact[16]; - uint8_t i; - - memset(gFrameBuffer, 0, sizeof(gFrameBuffer)); - - for (i = 0; i < 3; i++) { - if (gMenuCursor || i) { - if ((gMenuListCount - 1) != gMenuCursor || (i != 2)) { - GUI_PrintString(MenuList[gMenuCursor + i - 1], 0, 127, i * 2, 8, false); - } - } - } - for (i = 0; i < 48; i++) { - gFrameBuffer[2][i] ^= 0xFF; - gFrameBuffer[3][i] ^= 0xFF; - } - for (i = 0; i < 7; i++) { - gFrameBuffer[i][48] = 0xFF; - gFrameBuffer[i][49] = 0xFF; - } - NUMBER_ToDigits(gMenuCursor + 1, String); - GUI_DisplaySmallDigits(2, String + 6, 33, 6); - if (gIsInSubMenu) { - memcpy(gFrameBuffer[0] + 50, BITMAP_CurrentIndicator, sizeof(BITMAP_CurrentIndicator)); - } - - memset(String, 0, sizeof(String)); - - switch (gMenuCursor) { - case MENU_SQL: - case MENU_MIC: - sprintf(String, "%d", gSubMenuSelection); - break; - - case MENU_STEP: - sprintf(String, "%.2fKHz", gSubMenu_Step[gSubMenuSelection] * 0.01); - break; - - case MENU_TXP: - strcpy(String, gSubMenu_TXP[gSubMenuSelection]); - break; - - case MENU_R_DCS: - case MENU_T_DCS: - if (gSubMenuSelection == 0) { - strcpy(String, "OFF"); - } else if (gSubMenuSelection < 105) { - sprintf(String, "D%03oN", DCS_Options[gSubMenuSelection - 1]); - } else { - sprintf(String, "D%03oI", DCS_Options[gSubMenuSelection - 105]); - } - break; - - case MENU_R_CTCS: - case MENU_T_CTCS: - if (gSubMenuSelection == 0) { - strcpy(String, "OFF"); - } else { - sprintf(String, "%.1fHz", CTCSS_Options[gSubMenuSelection] * 0.1); - } - break; - - case MENU_SFT_D: - strcpy(String, gSubMenu_SFT_D[gSubMenuSelection]); - break; - - case MENU_OFFSET: - if (!gIsInSubMenu || gInputBoxIndex == 0) { - sprintf(String, "%.5f", gSubMenuSelection * 1e-05); - break; - } - for (i = 0; i < 3; i++) { - if (gInputBox[i] == 10) { - String[i] = '-'; - } else { - String[i] = gInputBox[i] + '0'; - } - } - String[3] = '.'; - for (i = 3; i < 6; i++) { - if (gInputBox[i] == 10) { - String[i + 1] = '-'; - } else { - String[i + 1] = gInputBox[i] + '0'; - } - } - String[7] = 0x2d; - String[8] = '-'; - String[9] = 0; - String[10] = 0; - String[11] = 0; - break; - - case MENU_W_N: - strcpy(String, gSubMenu_W_N[gSubMenuSelection]); - break; - - case MENU_SCR: - case MENU_VOX: - case MENU_ABR: - if (gSubMenuSelection == 0) { - strcpy(String, "OFF"); - } else { - sprintf(String, "%d", gSubMenuSelection); - } - break; - - case MENU_BCL: - case MENU_BEEP: - case MENU_AUTOLK: - case MENU_S_ADD1: - case MENU_S_ADD2: - case MENU_STE: - case MENU_D_ST: - case MENU_D_DCD: - case MENU_AM: - case MENU_NOAA_S: - case MENU_350TX: - case MENU_200TX: - case MENU_500TX: - case MENU_350EN: - case MENU_SCREN: - strcpy(String, gSubMenu_OFF_ON[gSubMenuSelection]); - break; - - case MENU_MEM_CH: - case MENU_1_CALL: - case MENU_DEL_CH: - GenerateChannelStringEx( - String, - RADIO_CheckValidChannel((uint16_t)gSubMenuSelection, false, 0), - (uint8_t)gSubMenuSelection - ); - break; - - case MENU_SAVE: - strcpy(String, gSubMenu_SAVE[gSubMenuSelection]); - break; - - case MENU_TDR: - case MENU_WX: - strcpy(String, gSubMenu_CHAN[gSubMenuSelection]); - break; - - case MENU_TOT: - if (gSubMenuSelection == 0) { - strcpy(String, "OFF"); - } else { - sprintf(String, "%dmin", gSubMenuSelection); - } - break; - - case MENU_VOICE: - strcpy(String, gSubMenu_VOICE[gSubMenuSelection]); - break; - - case MENU_SC_REV: - strcpy(String, gSubMenu_SC_REV[gSubMenuSelection]); - break; - - case MENU_MDF: - strcpy(String, gSubMenu_MDF[gSubMenuSelection]); - break; - - case MENU_RP_STE: - if (gSubMenuSelection == 0) { - strcpy(String, "OFF"); - } else { - sprintf(String, "%d*100ms", gSubMenuSelection); - } - break; - - case MENU_S_LIST: - sprintf(String, "LIST%d", gSubMenuSelection); - break; - - case MENU_AL_MOD: - sprintf(String, gSubMenu_AL_MOD[gSubMenuSelection]); - break; - - case MENU_ANI_ID: - strcpy(String, gEeprom.ANI_DTMF_ID); - break; - - case MENU_UPCODE: - strcpy(String, gEeprom.DTMF_UP_CODE); - break; - - case MENU_DWCODE: - strcpy(String, gEeprom.DTMF_DOWN_CODE); - break; - - case MENU_D_RSP: - strcpy(String, gSubMenu_D_RSP[gSubMenuSelection]); - break; - - case MENU_D_HOLD: - sprintf(String, "%ds", gSubMenuSelection); - break; - - case MENU_D_PRE: - sprintf(String, "%d*10ms", gSubMenuSelection); - break; - - case MENU_PTT_ID: - strcpy(String, gSubMenu_PTT_ID[gSubMenuSelection]); - break; - - case MENU_D_LIST: - gIsDtmfContactValid = DTMF_GetContact((uint8_t)gSubMenuSelection - 1, Contact); - if (!gIsDtmfContactValid) { - // Ghidra being weird again... - memcpy(String, "NULL\0\0\0", 8); - } else { - memcpy(String, Contact, 8); - } - break; - - case MENU_PONMSG: - strcpy(String, gSubMenu_PONMSG[gSubMenuSelection]); - break; - - case MENU_ROGER: - strcpy(String, gSubMenu_ROGER[gSubMenuSelection]); - break; - - case MENU_VOL: - sprintf(String, "%.2fV", gBatteryVoltageAverage * 0.01); - break; - - case MENU_RESET: - strcpy(String, gSubMenu_RESET[gSubMenuSelection]); - break; - - case MENU_F_LOCK: - strcpy(String, gSubMenu_F_LOCK[gSubMenuSelection]); - break; - } - - GUI_PrintString(String, 50, 127, 2, 8, true); - - if (gMenuCursor == MENU_OFFSET) { - GUI_PrintString("MHz", 50, 127, 4, 8, true); - } - - if ((gMenuCursor == MENU_RESET || gMenuCursor == MENU_MEM_CH || gMenuCursor == MENU_DEL_CH) && gAskForConfirmation) { - if (gAskForConfirmation == 1) { - strcpy(String, "SURE?"); - } else { - strcpy(String, "WAIT!"); - } - GUI_PrintString(String, 50, 127, 4, 8, true); - } - - if ((gMenuCursor == MENU_R_CTCS || gMenuCursor == MENU_R_DCS) && g_20000381 != 0) { - GUI_PrintString("SCAN", 50, 127, 4, 8, true); - } - - if (gMenuCursor == MENU_UPCODE) { - if (strlen(gEeprom.DTMF_UP_CODE) > 8) { - GUI_PrintString(gEeprom.DTMF_UP_CODE + 8, 50, 127, 4, 8, true); - } - } - if (gMenuCursor == MENU_DWCODE) { - if (strlen(gEeprom.DTMF_DOWN_CODE) > 8) { - GUI_PrintString(gEeprom.DTMF_DOWN_CODE + 8, 50, 127, 4, 8, true); - } - } - if (gMenuCursor == MENU_D_LIST && gIsDtmfContactValid) { - Contact[11] = 0; - memcpy(&gDTMF_ID, Contact + 8, 4); - sprintf(String,"ID:%s", Contact + 8); - GUI_PrintString(String, 50, 127, 4, 8, true); - } - - if (gMenuCursor == MENU_R_CTCS || gMenuCursor == MENU_T_CTCS || - gMenuCursor == MENU_R_DCS || gMenuCursor == MENU_T_DCS || gMenuCursor == MENU_D_LIST) { - uint8_t Offset; - - NUMBER_ToDigits((uint8_t)gSubMenuSelection, String); - Offset = (gMenuCursor == MENU_D_LIST) ? 2 : 3; - GUI_DisplaySmallDigits(Offset, String + (8 - Offset), 105, 0); - } - - if (gMenuCursor != MENU_SLIST1 && gMenuCursor != MENU_SLIST2) { - goto Skip; - } - - i = gMenuCursor - MENU_SLIST1; - - if (gSubMenuSelection == 0xFF) { - sprintf(String,"NULL"); - } else { - GenerateChannelStringEx(String, true, (uint8_t)gSubMenuSelection); - } - - if (gSubMenuSelection == 0xFF || gEeprom.SCAN_LIST_ENABLED[i] != true) { - GUI_PrintString(String, 50, 127, 2, 8, 1); - } else { - GUI_PrintString(String, 50, 127, 0, 8, 1); - if (gEeprom.SCANLIST_PRIORITY_CH1[i] < 200) { - sprintf(String, "PRI1:%d", gEeprom.SCANLIST_PRIORITY_CH1[i] + 1); - GUI_PrintString(String, 50, 127, 2, 8, 1); - } - if (gEeprom.SCANLIST_PRIORITY_CH2[i] < 200) { - sprintf(String, "PRI2:%d", gEeprom.SCANLIST_PRIORITY_CH2[i] + 1); - GUI_PrintString(String, 50, 127, 4, 8, 1); - } - } - -Skip: - ST7565_BlitFullScreen(); -} - -static void DisplayScanner(void) -{ - char String[16]; - bool bCentered; - uint8_t Start; - - memset(gFrameBuffer, 0, sizeof(gFrameBuffer)); - memset(String, 0, sizeof(String)); - - if (g_20000458 == 1 || (gScanState != 0 && gScanState != 3)) { - sprintf(String, "FREQ:%.5f", gScanFrequency * 1e-05); - } else { - sprintf(String, "FREQ:**.*****"); - } - GUI_PrintString(String, 2, 127, 1, 8, 0); - memset(String, 0, sizeof(String)); - - if (gScanState < 2 || g_2000045C != 1) { - sprintf(String, "CTC:******"); - } else if (g_CxCSS_Type == 1) { - sprintf(String, "CTC:%.1fHz", CTCSS_Options[g_CxCSS_Index] * 0.1); - } else { - sprintf(String, "DCS:D%03oN", DCS_Options[g_CxCSS_Index]); - } - GUI_PrintString(String, 2, 127, 3, 8, 0); - memset(String, 0, sizeof(String)); - - if (g_20000461 == 2) { - strcpy(String, "SAVE?"); - Start = 0; - bCentered = 1; - } else { - if (g_20000461 == 1) { - strcpy(String, "SAVE:"); - GenerateChannelStringEx(String + 5, gShowChPrefix, gScanChannel); - } else if (gScanState < 2) { - strcpy(String, "SCAN"); - memset(String + 4, '.', (g_20000464 & 7) + 1); - } else { - if (gScanState == 2) { - strcpy(String, "SCAN CMP."); - } else { - strcpy(String, "SCAN FAIL."); - } - } - Start = 2; - bCentered = 0; - } - - GUI_PrintString(String, Start, 127, 5, 8, bCentered); - ST7565_BlitFullScreen(); -} - -static void DisplayAircopy(void) -{ - char String[16]; - - memset(gFrameBuffer, 0, sizeof(gFrameBuffer)); - - if (gAircopyState == AIRCOPY_READY) { - strcpy(String, "AIR COPY(RDY)"); - } else if (gAircopyState == AIRCOPY_TRANSFER) { - strcpy(String, "AIR COPY"); - } else { - strcpy(String, "AIR COPY(CMP)"); - } - GUI_PrintString(String, 2, 127, 0, 8, true); - - if (gInputBoxIndex == 0) { - NUMBER_ToDigits(gInfoCHAN_A->DCS[0].Frequency, String); - GUI_DisplayFrequency(String, 16, 2, 0, 0); - GUI_DisplaySmallDigits(2, String + 6, 97, 3); - } else { - GUI_DisplayFrequency(gInputBox, 16, 2, 1, 0); - } - - memset(String, 0, sizeof(String)); - - if (gAirCopyIsSendMode == 0) { - sprintf(String, "RCV:%d E:%d", gAirCopyBlockNumber, gErrorsDuringAirCopy); - } else if (gAirCopyIsSendMode == 1) { - sprintf(String, "SND:%d", gAirCopyBlockNumber); - } - GUI_PrintString(String, 2, 127, 4, 8, true); - ST7565_BlitFullScreen(); -} - void GUI_DisplayScreen(void) { switch (gScreenToDisplay) { case DISPLAY_MAIN: - DisplayMain(); + UI_DisplayMain(); break; case DISPLAY_FM: - DisplayFM(); + UI_DisplayFM(); break; case DISPLAY_MENU: - GUI_DisplayMenu(); + UI_DisplayMenu(); break; case DISPLAY_SCANNER: - DisplayScanner(); + UI_DisplayScanner(); break; case DISPLAY_AIRCOPY: - DisplayAircopy(); + UI_DisplayAircopy(); break; default: break; diff --git a/gui.h b/gui.h index 8e5369a..25c11e4 100644 --- a/gui.h +++ b/gui.h @@ -31,71 +31,9 @@ enum GUI_DisplayType_t { typedef enum GUI_DisplayType_t GUI_DisplayType_t; -enum { - MENU_SQL = 0, - MENU_STEP = 1, - MENU_TXP = 2, - MENU_R_DCS = 3, - MENU_R_CTCS = 4, - MENU_T_DCS = 5, - MENU_T_CTCS = 6, - MENU_SFT_D = 7, - MENU_OFFSET = 8, - MENU_W_N = 9, - MENU_SCR = 10, - MENU_BCL = 11, - MENU_MEM_CH = 12, - MENU_SAVE = 13, - MENU_VOX = 14, - MENU_ABR = 15, - MENU_TDR = 16, - MENU_WX = 17, - MENU_BEEP = 18, - MENU_TOT = 19, - MENU_VOICE = 20, - MENU_SC_REV = 21, - MENU_MDF = 22, - MENU_AUTOLK = 23, - MENU_S_ADD1 = 24, - MENU_S_ADD2 = 25, - MENU_STE = 26, - MENU_RP_STE = 27, - MENU_MIC = 28, - MENU_1_CALL = 29, - MENU_S_LIST = 30, - MENU_SLIST1 = 31, - MENU_SLIST2 = 32, - MENU_AL_MOD = 33, - MENU_ANI_ID = 34, - MENU_UPCODE = 35, - MENU_DWCODE = 36, - MENU_D_ST = 37, - MENU_D_RSP = 38, - MENU_D_HOLD = 39, - MENU_D_PRE = 40, - MENU_PTT_ID = 41, - MENU_D_DCD = 42, - MENU_D_LIST = 43, - MENU_PONMSG = 44, - MENU_ROGER = 45, - MENU_VOL = 46, - MENU_AM = 47, - MENU_NOAA_S = 48, - MENU_DEL_CH = 49, - MENU_RESET = 50, - MENU_350TX = 51, - MENU_F_LOCK = 52, - MENU_200TX = 53, - MENU_500TX = 54, - MENU_350EN = 55, - MENU_SCREN = 56, -}; - extern GUI_DisplayType_t gScreenToDisplay; -extern bool gIsInSubMenu; extern volatile int8_t gStepDirection; extern GUI_DisplayType_t gRequestDisplayScreen; -extern uint8_t g_200003BA; extern uint8_t g_200003BB; extern bool gWasFKeyPressed; @@ -103,21 +41,12 @@ extern uint8_t gAskForConfirmation; extern bool gAskToSave; extern bool gAskToDelete; -extern uint8_t gMenuCursor; -extern int8_t gMenuScrollDirection; -extern uint32_t gSubMenuSelection; - void GUI_DisplayBatteryLevel(uint8_t BatteryLevel); void GUI_Welcome(void); -void GUI_PrintString(const char *pString, uint8_t Start, uint8_t End, uint8_t Line, int Width, bool bCentered); void GUI_PasswordScreen(void); void GUI_LockScreen(void); void GUI_DisplayStatusLine(void); -void GUI_DisplayFrequency(const char *pDigits, uint8_t X, uint8_t Y, bool bDisplayLeadingZero, bool Flag1); -void GUI_DisplaySmallDigits(uint8_t Size, const char *pString, uint8_t x, uint8_t y); - -void GUI_DisplayMenu(void); void GUI_DisplayScreen(void); void GUI_SelectNextDisplay(GUI_DisplayType_t Display); diff --git a/helper.c b/helper.c index 7b53031..a6f4028 100644 --- a/helper.c +++ b/helper.c @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "aircopy.h" +#include "app/aircopy.h" #include "bsp/dp32g030/gpio.h" #include "driver/bk4819.h" #include "driver/keyboard.h" @@ -25,6 +25,7 @@ #include "misc.h" #include "radio.h" #include "settings.h" +#include "ui/menu.h" KEY_Code_t gKeyReading0; KEY_Code_t gKeyReading1; diff --git a/misc.c b/misc.c index 937e9b4..7736144 100644 --- a/misc.c +++ b/misc.c @@ -105,6 +105,7 @@ uint8_t gFlashLightState; uint8_t g_200003B4; uint16_t g_200003B6; uint16_t g_200003B8; +uint8_t g_200003BA; uint8_t g_200003BC; uint8_t g_200003BD; uint8_t g_200003BE; diff --git a/misc.h b/misc.h index c8589a2..959cf0c 100644 --- a/misc.h +++ b/misc.h @@ -114,6 +114,7 @@ extern uint8_t gFlashLightState; extern uint8_t g_200003B4; extern uint16_t g_200003B6; extern uint16_t g_200003B8; +extern uint8_t g_200003BA; extern uint8_t g_200003BC; extern uint8_t g_200003BD; extern uint8_t g_200003BE; diff --git a/ui/aircopy.c b/ui/aircopy.c new file mode 100644 index 0000000..755f95d --- /dev/null +++ b/ui/aircopy.c @@ -0,0 +1,60 @@ +/* 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 +#include "app/aircopy.h" +#include "driver/st7565.h" +#include "external/printf/printf.h" +#include "misc.h" +#include "radio.h" +#include "ui/aircopy.h" +#include "ui/helper.h" +#include "ui/inputbox.h" + +void UI_DisplayAircopy(void) +{ + char String[16]; + + memset(gFrameBuffer, 0, sizeof(gFrameBuffer)); + + if (gAircopyState == AIRCOPY_READY) { + strcpy(String, "AIR COPY(RDY)"); + } else if (gAircopyState == AIRCOPY_TRANSFER) { + strcpy(String, "AIR COPY"); + } else { + strcpy(String, "AIR COPY(CMP)"); + } + UI_PrintString(String, 2, 127, 0, 8, true); + + if (gInputBoxIndex == 0) { + NUMBER_ToDigits(gInfoCHAN_A->DCS[0].Frequency, String); + UI_DisplayFrequency(String, 16, 2, 0, 0); + UI_DisplaySmallDigits(2, String + 6, 97, 3); + } else { + UI_DisplayFrequency(gInputBox, 16, 2, 1, 0); + } + + memset(String, 0, sizeof(String)); + + if (gAirCopyIsSendMode == 0) { + sprintf(String, "RCV:%d E:%d", gAirCopyBlockNumber, gErrorsDuringAirCopy); + } else if (gAirCopyIsSendMode == 1) { + sprintf(String, "SND:%d", gAirCopyBlockNumber); + } + UI_PrintString(String, 2, 127, 4, 8, true); + ST7565_BlitFullScreen(); +} + diff --git a/ui/aircopy.h b/ui/aircopy.h new file mode 100644 index 0000000..5852066 --- /dev/null +++ b/ui/aircopy.h @@ -0,0 +1,23 @@ +/* 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 UI_AIRCOPY_H +#define UI_AIRCOPY_H + +void UI_DisplayAircopy(void); + +#endif + diff --git a/ui/fmradio.c b/ui/fmradio.c new file mode 100644 index 0000000..5f0e897 --- /dev/null +++ b/ui/fmradio.c @@ -0,0 +1,91 @@ + +/* 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 +#include "driver/st7565.h" +#include "external/printf/printf.h" +#include "fm.h" +#include "gui.h" +#include "misc.h" +#include "settings.h" +#include "ui/fmradio.h" +#include "ui/helper.h" +#include "ui/inputbox.h" + +void UI_DisplayFM(void) +{ + uint8_t i; + char String[16]; + + memset(gFrameBuffer, 0, sizeof(gFrameBuffer)); + + memset(String, 0, sizeof(String)); + strcpy(String, "FM"); + + UI_PrintString(String, 0, 127, 0, 12, true); + memset(String, 0, sizeof(String)); + + if (gAskToSave) { + strcpy(String, "SAVE?"); + } else if (gAskToDelete) { + strcpy(String, "DEL?"); + } else { + if (g_20000390 == 0) { + if (gEeprom.FM_IsChannelSelected == false) { + for (i = 0; i < 20; i++) { + if (gEeprom.FM_FrequencyToPlay == gFM_Channels[i]) { + sprintf(String, "VFO(CH%02d)", i + 1); + break; + } + } + if (i == 20) { + strcpy(String, "VFO"); + } + } else { + sprintf(String, "MR(CH%02d)", gEeprom.FM_CurrentChannel + 1); + } + } else { + if (gIs_A_Scan == false) { + strcpy(String, "M-SCAN"); + } else { + sprintf(String, "A-SCAN(%d)", gA_Scan_Channel + 1); + } + } + } + + UI_PrintString(String, 0, 127, 2, 10, true); + memset(String, 0, sizeof(String)); + + if (gAskToSave || (gEeprom.FM_IsChannelSelected && gInputBoxIndex)) { + UI_GenerateChannelString(String, gA_Scan_Channel); + } else if (gAskToDelete) { + if (gInputBoxIndex == 0) { + NUMBER_ToDigits(gEeprom.FM_FrequencyToPlay * 10000, String); + UI_DisplayFrequency(String, 23, 4, false, true); + } else { + UI_DisplayFrequency(gInputBox, 23, 4, true, false); + } + ST7565_BlitFullScreen(); + return; + } else { + sprintf(String, "CH-%02d", gEeprom.FM_CurrentChannel + 1); + } + + UI_PrintString(String, 0, 127, 4, 10, true); + ST7565_BlitFullScreen(); +} + diff --git a/ui/fmradio.h b/ui/fmradio.h new file mode 100644 index 0000000..8309e9e --- /dev/null +++ b/ui/fmradio.h @@ -0,0 +1,23 @@ +/* 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 UI_FM_H +#define UI_FM_H + +void UI_DisplayFM(void); + +#endif + diff --git a/ui/helper.c b/ui/helper.c new file mode 100644 index 0000000..4133bce --- /dev/null +++ b/ui/helper.c @@ -0,0 +1,133 @@ +/* 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 +#include "driver/st7565.h" +#include "external/printf/printf.h" +#include "font.h" +#include "ui/helper.h" +#include "ui/inputbox.h" + +void UI_GenerateChannelString(char *pString, uint8_t Channel) +{ + uint8_t i; + + if (gInputBoxIndex == 0) { + sprintf(pString, "CH-%02d", Channel + 1); + return; + } + + pString[0] = 'C'; + pString[1] = 'H'; + pString[2] = '-'; + + for (i = 0; i < 2; i++) { + if (gInputBox[i] == 10) { + pString[i + 3] = '-'; + } else { + pString[i + 3] = gInputBox[i] + '0'; + } + } + +} + +void UI_GenerateChannelStringEx(char *pString, bool bShowPrefix, uint8_t ChannelNumber) +{ + if (gInputBoxIndex) { + uint8_t i; + + for (i = 0; i < 3; i++) { + if (gInputBox[i] == 10) { + pString[i] = '-'; + } else { + pString[i] = gInputBox[i] + '0'; + } + } + return; + } + + if (bShowPrefix) { + sprintf(pString, "CH-%03d", ChannelNumber + 1); + } else { + if (ChannelNumber == 0xFF) { + strcpy(pString, "NULL"); + } else { + sprintf(pString, "%03d", ChannelNumber + 1); + } + } +} + +void UI_PrintString(const char *pString, uint8_t Start, uint8_t End, uint8_t Line, int Width, bool bCentered) +{ + uint32_t i, Length; + + Length = strlen(pString); + if (bCentered) { + Start += (((End - Start) - (Length * Width)) + 1) / 2; + } + for (i = 0; i < Length; i++) { + if (pString[i] - ' ' < 0x5F) { + uint8_t Index = pString[i] - ' '; + memcpy(gFrameBuffer[Line + 0] + (i * Width) + Start, &gFontBig[Index][0], 8); + memcpy(gFrameBuffer[Line + 1] + (i * Width) + Start, &gFontBig[Index][8], 8); + } + } +} + +void UI_DisplayFrequency(const char *pDigits, uint8_t X, uint8_t Y, bool bDisplayLeadingZero, bool bFlag) +{ + uint8_t *pFb0, *pFb1; + bool bCanDisplay; + uint8_t i; + + pFb0 = gFrameBuffer[Y] + X; + pFb1 = pFb0 + 128; + + bCanDisplay = false; + for (i = 0; i < 3; i++) { + const uint8_t Digit = pDigits[i]; + + if (bDisplayLeadingZero || bCanDisplay || Digit) { + bCanDisplay = true; + memcpy(pFb0 + (i * 13), gFontBigDigits[Digit] + 0, 13); + memcpy(pFb1 + (i * 13), gFontBigDigits[Digit] + 13, 13); + } else if (bFlag) { + pFb1 -= 6; + pFb0 -= 6; + } + } + + pFb1[0x27] = 0x60; + pFb1[0x28] = 0x60; + pFb1[0x29] = 0x60; + + for (i = 0; i < 3; i++) { + const uint8_t Digit = pDigits[i + 3]; + + memcpy(pFb0 + (i * 13) + 42, gFontBigDigits[Digit] + 0, 13); + memcpy(pFb1 + (i * 13) + 42, gFontBigDigits[Digit] + 13, 13); + } +} + +void UI_DisplaySmallDigits(uint8_t Size, const char *pString, uint8_t X, uint8_t Y) +{ + uint8_t i; + + for (i = 0; i < Size; i++) { + memcpy(gFrameBuffer[Y] + (i * 7) + X, gFontSmallDigits[(uint8_t)pString[i]], 7); + } +} + diff --git a/ui/helper.h b/ui/helper.h new file mode 100644 index 0000000..27b734a --- /dev/null +++ b/ui/helper.h @@ -0,0 +1,30 @@ +/* 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 UI_UI_H +#define UI_UI_H + +#include +#include + +void UI_GenerateChannelString(char *pString, uint8_t Channel); +void UI_GenerateChannelStringEx(char *pString, bool bShowPrefix, uint8_t ChannelNumber); +void UI_PrintString(const char *pString, uint8_t Start, uint8_t End, uint8_t Line, int Width, bool bCentered); +void UI_DisplayFrequency(const char *pDigits, uint8_t X, uint8_t Y, bool bDisplayLeadingZero, bool bFlag); +void UI_DisplaySmallDigits(uint8_t Size, const char *pString, uint8_t X, uint8_t Y); + +#endif + diff --git a/ui/main.c b/ui/main.c new file mode 100644 index 0000000..3cd489b --- /dev/null +++ b/ui/main.c @@ -0,0 +1,415 @@ +/* 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 +//#include "audio.h" +//#include "battery.h" +#include "bitmaps.h" +//#include "driver/eeprom.h" +//#include "driver/keyboard.h" +#include "driver/st7565.h" +#include "dtmf.h" +#include "external/printf/printf.h" +//#include "fm.h" +#include "functions.h" +//#include "gui.h" +//#include "helper.h" +#include "misc.h" +#include "settings.h" +//#include "ui/aircopy.h" +//#include "ui/fmradio.h" +#include "ui/helper.h" +#include "ui/inputbox.h" +#include "ui/main.h" +//#include "ui/menu.h" +//#include "ui/scanner.h" + +//GUI_DisplayType_t gScreenToDisplay; +//volatile int8_t gStepDirection; +//GUI_DisplayType_t gRequestDisplayScreen; +//uint8_t g_200003BA; +//uint8_t g_200003BB; +//bool gWasFKeyPressed; + +//uint8_t gAskForConfirmation; +//bool gAskToSave; +//bool gAskToDelete; + +void UI_DisplayMain(void) +{ + char String[16]; + char String2[16]; + uint8_t i; + + memset(gFrameBuffer, 0, sizeof(gFrameBuffer)); + if (gEeprom.KEY_LOCK && gKeypadLocked) { + UI_PrintString("Long Press #", 0, 127, 1, 8, true); + UI_PrintString("To Unlock", 0, 127, 3, 8, true); + ST7565_BlitFullScreen(); + return; + } + + for (i = 0; i < 2; i++) { + uint8_t *pLine0; + uint8_t *pLine1; + uint8_t Line; + uint8_t Channel; + bool bIsSameVfo; + + if (i == 0) { + pLine0 = gFrameBuffer[0]; + pLine1 = gFrameBuffer[1]; + Line = 0; + } else { + pLine0 = gFrameBuffer[4]; + pLine1 = gFrameBuffer[5]; + Line = 4; + } + + Channel = gEeprom.TX_CHANNEL; + bIsSameVfo = !!(Channel == i); + + if (gEeprom.DUAL_WATCH != DUAL_WATCH_OFF && g_2000041F == 1) { + Channel = gEeprom.RX_CHANNEL; + } + + if (Channel != i) { + if (g_200003BC || g_200003BD || g_200003BA) { + if (g_200003BA == 0) { + if (g_200003BC == 1) { + if (g_CalloutAndDTMF_State == 2) { + strcpy(String, "CALL OUT(RSP)"); + } else { + strcpy(String, "CALL OUT"); + } + } else if (g_200003BC == 2) { + if (DTMF_FindContact(gDTMF_Contact0, String2)) { + sprintf(String, "CALL:%s", String2); + } else { + sprintf(String, "CALL:%s", gDTMF_Contact0); + } + } else if (g_200003BD == 1) { + if (g_CalloutAndDTMF_State == 1) { + strcpy(String, "DTMF TX(SUCC)"); + } else { + strcpy(String, "DTMF TX"); + } + } + } else { + sprintf(String, ">%s", g_20000D1C); + } + UI_PrintString(String, 2, 127, i * 3, 8, false); + + memset(String, 0, sizeof(String)); + memset(String2, 0, sizeof(String2)); + + if (g_200003BA == 0) { + if (g_200003BC == 1) { + if (DTMF_FindContact(gDTMF_String, String2)) { + sprintf(String, ">%s", String2); + } else { + sprintf(String, ">%s", gDTMF_String); + } + } else if (g_200003BC == 2) { + if (DTMF_FindContact(gDTMF_Contact1, String2)) { + sprintf(String, ">%s", String2); + } else { + sprintf(String, ">%s", gDTMF_Contact1); + } + } else if (g_200003BD == 1) { + sprintf(String, ">%s", gDTMF_String); + } + } + UI_PrintString(String, 2, 127, 2 + (i * 3), 8, false); + continue; + } else if (bIsSameVfo) { + memcpy(pLine0 + 2, BITMAP_VFO_Default, sizeof(BITMAP_VFO_Default)); + } + } else { + if (bIsSameVfo) { + memcpy(pLine0 + 2, BITMAP_VFO_Default, sizeof(BITMAP_VFO_Default)); + } else { + memcpy(pLine0 + 2, BITMAP_VFO_NotDefault, sizeof(BITMAP_VFO_NotDefault)); + } + } + + // 0x8EE2 + uint32_t SomeValue = 0; + + if (gCurrentFunction == FUNCTION_TRANSMIT) { + if (g_20000383 == 2) { + SomeValue = 2; + } else { + Channel = gEeprom.RX_CHANNEL; + if (gEeprom.CROSS_BAND_RX_TX != CROSS_BAND_OFF) { + Channel = gEeprom.TX_CHANNEL; + } + if (Channel == i) { + SomeValue = 1; + memcpy(pLine0 + 14, BITMAP_TX, sizeof(BITMAP_TX)); + } + } + } else { + SomeValue = 2; + if ((gCurrentFunction == FUNCTION_4 || gCurrentFunction == FUNCTION_2) && gEeprom.RX_CHANNEL == i) { + memcpy(pLine0 + 14, BITMAP_RX, sizeof(BITMAP_RX)); + } + } + + // 0x8F3C + if (gEeprom.ScreenChannel[i] < 200) { + memcpy(pLine1 + 2, BITMAP_M, sizeof(BITMAP_M)); + if (gInputBoxIndex == 0 || gEeprom.TX_CHANNEL != i) { + NUMBER_ToDigits(gEeprom.ScreenChannel[i] + 1, String); + } else { + memcpy(String + 5, gInputBox, 3); + } + UI_DisplaySmallDigits(3, String + 5, 10, Line + 1); + } else if (gEeprom.ScreenChannel[i] < 207) { + char c; + + memcpy(pLine1 + 14, BITMAP_F, sizeof(BITMAP_F)); + c = gEeprom.ScreenChannel[i] - 199; + UI_DisplaySmallDigits(1, &c, 22, Line + 1); + } else { + memcpy(pLine1 + 7, BITMAP_NarrowBand, sizeof(BITMAP_NarrowBand)); + if (gInputBoxIndex == 0 || gEeprom.TX_CHANNEL != i) { + NUMBER_ToDigits(gEeprom.ScreenChannel[i] - 206, String); + } else { + String[6] = gInputBox[0]; + String[7] = gInputBox[1]; + } + UI_DisplaySmallDigits(2, String + 6, 15, Line + 1); + } + + // 0x8FEC + + uint8_t g371 = g_20000371[i]; + if (gCurrentFunction == FUNCTION_TRANSMIT && g_20000383 == 2) { + if (gEeprom.CROSS_BAND_RX_TX == CROSS_BAND_OFF) { + Channel = gEeprom.RX_CHANNEL; + } else { + Channel = gEeprom.TX_CHANNEL; + } + if (Channel == i) { + g371 = 5; + } + } + if (g371) { + uint8_t Width = 10; + + memset(String, 0, sizeof(String)); + switch (g371) { + case 1: + strcpy(String, "BUSY"); + Width = 15; + break; + case 2: + strcpy(String, "BAT LOW"); + break; + case 3: + strcpy(String, "DISABLE"); + break; + case 4: + strcpy(String, "TIMEOUT"); + break; + case 5: + strcpy(String, "ALARM"); + break; + case 6: + sprintf(String, "VOL HIGH"); + Width = 8; + break; + } + UI_PrintString(String, 31, 111, i * 4, Width, true); + } else { + if (gInputBoxIndex && (gEeprom.ScreenChannel[i] - 200) < 7 && gEeprom.TX_CHANNEL == i) { + UI_DisplayFrequency(gInputBox, 31, i * 4, true, false); + } else { + if (gEeprom.ScreenChannel[i] < 200) { + if (gEeprom.CHANNEL_DISPLAY_MODE == 2 && (gEeprom.VfoInfo[i].Name[0] == 0 || gEeprom.VfoInfo[i].Name[0] == 0xFF)) { + sprintf(String, "CH-%03d", gEeprom.ScreenChannel[i] + 1); + UI_PrintString(String, 31, 112, i * 4, 8, true); + } else { + switch (gEeprom.CHANNEL_DISPLAY_MODE) { + case 0: + if (gCurrentFunction == FUNCTION_TRANSMIT) { + if (gEeprom.CROSS_BAND_RX_TX == CROSS_BAND_OFF) { + Channel = gEeprom.RX_CHANNEL; + } else { + Channel = gEeprom.TX_CHANNEL; + } + if (Channel == i) { + NUMBER_ToDigits(gEeprom.VfoInfo[i].pDCS_Reverse->Frequency, String); + } else { + NUMBER_ToDigits(gEeprom.VfoInfo[i].pDCS_Current->Frequency, String); + } + } else { + NUMBER_ToDigits(gEeprom.VfoInfo[i].pDCS_Current->Frequency, String); + } + UI_DisplayFrequency(String, 31, i * 4, false, false); + if (gEeprom.ScreenChannel[i] < 200) { + const uint8_t Attributes = gMR_ChannelAttributes[gEeprom.ScreenChannel[i]]; + if (Attributes & MR_CH_SCANLIST1) { + memcpy(pLine0 + 113, BITMAP_ScanList, sizeof(BITMAP_ScanList)); + } + if (Attributes & MR_CH_SCANLIST2) { + memcpy(pLine0 + 120, BITMAP_ScanList, sizeof(BITMAP_ScanList)); + } + } + UI_DisplaySmallDigits(2, String + 6, 112, Line + 1); + break; + case 1: + sprintf(String, "CH-%03d", gEeprom.ScreenChannel[i] + 1); + UI_PrintString(String, 31, 112, i * 4, 8, true); + break; + case 2: + UI_PrintString(gEeprom.VfoInfo[i].Name, 31, 112, i * 4, 8, true); + break; + } + } + } else { + if (gCurrentFunction == FUNCTION_TRANSMIT) { + if (gEeprom.CROSS_BAND_RX_TX == CROSS_BAND_OFF) { + Channel = gEeprom.RX_CHANNEL; + } else { + Channel = gEeprom.TX_CHANNEL; + } + if (Channel == i) { + NUMBER_ToDigits(gEeprom.VfoInfo[i].pDCS_Reverse->Frequency, String); + } else { + NUMBER_ToDigits(gEeprom.VfoInfo[i].pDCS_Current->Frequency, String); + } + } else { + NUMBER_ToDigits(gEeprom.VfoInfo[i].pDCS_Current->Frequency, String); + } + UI_DisplayFrequency(String, 31, i * 4, false, false); + if (gEeprom.ScreenChannel[i] < 200) { + const uint8_t Attributes = gMR_ChannelAttributes[gEeprom.ScreenChannel[i]]; + if (Attributes & MR_CH_SCANLIST1) { + memcpy(pLine0 + 113, BITMAP_ScanList, sizeof(BITMAP_ScanList)); + } + if (Attributes & MR_CH_SCANLIST2) { + memcpy(pLine0 + 120, BITMAP_ScanList, sizeof(BITMAP_ScanList)); + } + } + UI_DisplaySmallDigits(2, String + 6, 112, Line + 1); + } + } + } + + // 0x926E + uint8_t Level = 0; + + if (SomeValue == 1) { + if (gInfoCHAN_A->OUTPUT_POWER == OUTPUT_POWER_LOW) { + Level = 2; + } else if (gInfoCHAN_A->OUTPUT_POWER == OUTPUT_POWER_MID) { + Level = 4; + } else { + Level = 6; + } + } else if (SomeValue == 2) { + if (gVFO_RSSI_Level[i]) { + Level = gVFO_RSSI_Level[i]; + } + } + + // TODO: not quite how the original does it, but it's quite entangled in Ghidra. + if (Level) { + memcpy(pLine1 + 128 + 0, BITMAP_Antenna, sizeof(BITMAP_Antenna)); + memcpy(pLine1 + 128 + 5, BITMAP_AntennaLevel1, sizeof(BITMAP_AntennaLevel1)); + if (Level >= 2) { + memcpy(pLine1 + 128 + 8, BITMAP_AntennaLevel2, sizeof(BITMAP_AntennaLevel2)); + } + if (Level >= 3) { + memcpy(pLine1 + 128 + 11, BITMAP_AntennaLevel3, sizeof(BITMAP_AntennaLevel3)); + } + if (Level >= 4) { + memcpy(pLine1 + 128 + 14, BITMAP_AntennaLevel4, sizeof(BITMAP_AntennaLevel4)); + } + if (Level >= 5) { + memcpy(pLine1 + 128 + 17, BITMAP_AntennaLevel5, sizeof(BITMAP_AntennaLevel5)); + } + if (Level >= 6) { + memcpy(pLine1 + 128 + 20, BITMAP_AntennaLevel6, sizeof(BITMAP_AntennaLevel6)); + } + } + + // 0x931E + if (gEeprom.VfoInfo[i].IsAM == true) { + memcpy(pLine1 + 128 + 27, BITMAP_AM, sizeof(BITMAP_AM)); + } else { + const DCS_Info_t *pDCS; + + if (SomeValue == 1) { + pDCS = gEeprom.VfoInfo[i].pDCS_Reverse; + } else { + pDCS = gEeprom.VfoInfo[i].pDCS_Current; + } + switch (pDCS->CodeType) { + case CODE_TYPE_CONTINUOUS_TONE: + memcpy(pLine1 + 128 + 27, BITMAP_CT, sizeof(BITMAP_CT)); + break; + case CODE_TYPE_DIGITAL: + case CODE_TYPE_REVERSE_DIGITAL: + memcpy(pLine1 + 128 + 24, BITMAP_DCS, sizeof(BITMAP_DCS)); + break; + default: + break; + } + } + + // 0x936C + switch (gEeprom.VfoInfo[i].OUTPUT_POWER) { + case OUTPUT_POWER_LOW: + memcpy(pLine1 + 128 + 44, BITMAP_PowerLow, sizeof(BITMAP_PowerLow)); + break; + case OUTPUT_POWER_MID: + memcpy(pLine1 + 128 + 44, BITMAP_PowerMid, sizeof(BITMAP_PowerMid)); + break; + case OUTPUT_POWER_HIGH: + memcpy(pLine1 + 128 + 44, BITMAP_PowerHigh, sizeof(BITMAP_PowerHigh)); + break; + } + + if (gEeprom.VfoInfo[i].DCS[0].Frequency != gEeprom.VfoInfo[i].DCS[1].Frequency) { + if (gEeprom.VfoInfo[i].FREQUENCY_DEVIATION_SETTING == FREQUENCY_DEVIATION_ADD) { + memcpy(pLine1 + 128 + 54, BITMAP_Add, sizeof(BITMAP_Add)); + } + if (gEeprom.VfoInfo[i].FREQUENCY_DEVIATION_SETTING == FREQUENCY_DEVIATION_SUB) { + memcpy(pLine1 + 128 + 54, BITMAP_Sub, sizeof(BITMAP_Sub)); + } + + } + + if (gEeprom.VfoInfo[i].FrequencyReverse) { + memcpy(pLine1 + 128 + 64, BITMAP_ReverseMode, sizeof(BITMAP_ReverseMode)); + } + if (gEeprom.VfoInfo[i].CHANNEL_BANDWIDTH == BANDWIDTH_NARROW) { + memcpy(pLine1 + 128 + 74, BITMAP_NarrowBand, sizeof(BITMAP_NarrowBand)); + } + if (gEeprom.VfoInfo[i].DTMF_DECODING_ENABLE || gSetting_KILLED) { + memcpy(pLine1 + 128 + 84, BITMAP_DTMF, sizeof(BITMAP_DTMF)); + } + if (gEeprom.VfoInfo[i].SCRAMBLING_TYPE && gSetting_ScrambleEnable) { + memcpy(pLine1 + 128 + 110, BITMAP_Scramble, sizeof(BITMAP_Scramble)); + } + } + + ST7565_BlitFullScreen(); +} + diff --git a/ui/main.h b/ui/main.h new file mode 100644 index 0000000..e839af5 --- /dev/null +++ b/ui/main.h @@ -0,0 +1,23 @@ +/* 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 UI_MAIN_H +#define UI_MAIN_H + +void UI_DisplayMain(void); + +#endif + diff --git a/ui/menu.c b/ui/menu.c new file mode 100644 index 0000000..8c5e43e --- /dev/null +++ b/ui/menu.c @@ -0,0 +1,495 @@ +/* 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 +//#include "app/aircopy.h" +//#include "audio.h" +#include "battery.h" +#include "bitmaps.h" +#include "dcs.h" +//#include "driver/eeprom.h" +//#include "driver/keyboard.h" +#include "driver/st7565.h" +#include "dtmf.h" +#include "external/printf/printf.h" +//#include "font.h" +//#include "fm.h" +//#include "functions.h" +#include "gui.h" +//#include "helper.h" +#include "misc.h" +#include "settings.h" +//#include "ui/aircopy.h" +//#include "ui/fmradio.h" +#include "ui/helper.h" +#include "ui/inputbox.h" +#include "ui/menu.h" + +static const char MenuList[][7] = { + // 0x00 + "SQL", "STEP", "TXP", "R_DCS", + "R_CTCS", "T_DCS", "T_CTCS", "SFT-D", + // 0x08 + "OFFSET", "W/N", "SCR", "BCL", + "MEM-CH", "SAVE", "VOX", "ABR", + // 0x10 + "TDR", "WX", "BEEP", "TOT", + "VOICE", "SC-REV", "MDF", "AUTOLK", + // 0x18 + "S-ADD1", "S-ADD2", "STE", "RP-STE", + "MIC", "1-CALL", "S-LIST", "SLIST1", + // 0x20 + "SLIST2", "AL-MOD", "ANI-ID", "UPCODE", + "DWCODE", "D-ST", "D-RSP", "D-HOLD", + // 0x28 + "D-PRE", "PTT-ID", "D-DCD", "D-LIST", + "PONMSG", "ROGER", "VOL", "AM", + // 0x30 + "NOAA_S", "DEL-CH", "RESET", "350TX", + "F-LOCK", "200TX", "500TX", "350EN", + // 0x38 + "SCREN", +}; + +static const uint16_t gSubMenu_Step[] = { + 250, + 500, + 625, + 1000, + 1250, + 2500, + 833, +}; + +static const char gSubMenu_TXP[3][5] = { + "LOW", + "MID", + "HIGH", +}; + +static const char gSubMenu_SFT_D[3][4] = { + "OFF", + "+", + "-", +}; + +static const char gSubMenu_W_N[2][7] = { + "WIDE", + "NARROW", +}; + +static const char gSubMenu_OFF_ON[2][4] = { + "OFF", + "ON", +}; + +static const char gSubMenu_SAVE[5][4] = { + "OFF", + "1:1", + "1:2", + "1:3", + "1:4", +}; + +static const char gSubMenu_CHAN[3][7] = { + "OFF", + "CHAN_A", + "CHAN_B", +}; + +static const char gSubMenu_VOICE[3][4] = { + "OFF", + "CHI", + "ENG", +}; + +static const char gSubMenu_SC_REV[3][3] = { + "TO", + "CO", + "SE", +}; + +static const char gSubMenu_MDF[3][5] = { + "FREQ", + "CHAN", + "NAME", +}; + +static const char gSubMenu_AL_MOD[2][5] = { + "SITE", + "TONE", +}; + +static const char gSubMenu_D_RSP[4][6] = { + "NULL", + "RING", + "REPLY", + "BOTH", +}; + +static const char gSubMenu_PTT_ID[4][5] = { + "OFF", + "BOT", + "EOT", + "BOTH", +}; + +static const char gSubMenu_PONMSG[3][5] = { + "FULL", + "MSG", + "VOL", +}; + +static const char gSubMenu_ROGER[3][6] = { + "OFF", + "ROGER", + "MDC", +}; + +static const char gSubMenu_RESET[2][4] = { + "VFO", + "ALL", +}; + +static const char gSubMenu_F_LOCK[6][4] = { + "OFF", + "FCC", + "CE", + "GB", + "430", + "438", +}; + +bool gIsInSubMenu; + +uint8_t gMenuCursor; +int8_t gMenuScrollDirection; +uint32_t gSubMenuSelection; + +void UI_DisplayMenu(void) +{ + char String[16]; + char Contact[16]; + uint8_t i; + + memset(gFrameBuffer, 0, sizeof(gFrameBuffer)); + + for (i = 0; i < 3; i++) { + if (gMenuCursor || i) { + if ((gMenuListCount - 1) != gMenuCursor || (i != 2)) { + UI_PrintString(MenuList[gMenuCursor + i - 1], 0, 127, i * 2, 8, false); + } + } + } + for (i = 0; i < 48; i++) { + gFrameBuffer[2][i] ^= 0xFF; + gFrameBuffer[3][i] ^= 0xFF; + } + for (i = 0; i < 7; i++) { + gFrameBuffer[i][48] = 0xFF; + gFrameBuffer[i][49] = 0xFF; + } + NUMBER_ToDigits(gMenuCursor + 1, String); + UI_DisplaySmallDigits(2, String + 6, 33, 6); + if (gIsInSubMenu) { + memcpy(gFrameBuffer[0] + 50, BITMAP_CurrentIndicator, sizeof(BITMAP_CurrentIndicator)); + } + + memset(String, 0, sizeof(String)); + + switch (gMenuCursor) { + case MENU_SQL: + case MENU_MIC: + sprintf(String, "%d", gSubMenuSelection); + break; + + case MENU_STEP: + sprintf(String, "%.2fKHz", gSubMenu_Step[gSubMenuSelection] * 0.01); + break; + + case MENU_TXP: + strcpy(String, gSubMenu_TXP[gSubMenuSelection]); + break; + + case MENU_R_DCS: + case MENU_T_DCS: + if (gSubMenuSelection == 0) { + strcpy(String, "OFF"); + } else if (gSubMenuSelection < 105) { + sprintf(String, "D%03oN", DCS_Options[gSubMenuSelection - 1]); + } else { + sprintf(String, "D%03oI", DCS_Options[gSubMenuSelection - 105]); + } + break; + + case MENU_R_CTCS: + case MENU_T_CTCS: + if (gSubMenuSelection == 0) { + strcpy(String, "OFF"); + } else { + sprintf(String, "%.1fHz", CTCSS_Options[gSubMenuSelection] * 0.1); + } + break; + + case MENU_SFT_D: + strcpy(String, gSubMenu_SFT_D[gSubMenuSelection]); + break; + + case MENU_OFFSET: + if (!gIsInSubMenu || gInputBoxIndex == 0) { + sprintf(String, "%.5f", gSubMenuSelection * 1e-05); + break; + } + for (i = 0; i < 3; i++) { + if (gInputBox[i] == 10) { + String[i] = '-'; + } else { + String[i] = gInputBox[i] + '0'; + } + } + String[3] = '.'; + for (i = 3; i < 6; i++) { + if (gInputBox[i] == 10) { + String[i + 1] = '-'; + } else { + String[i + 1] = gInputBox[i] + '0'; + } + } + String[7] = 0x2d; + String[8] = '-'; + String[9] = 0; + String[10] = 0; + String[11] = 0; + break; + + case MENU_W_N: + strcpy(String, gSubMenu_W_N[gSubMenuSelection]); + break; + + case MENU_SCR: + case MENU_VOX: + case MENU_ABR: + if (gSubMenuSelection == 0) { + strcpy(String, "OFF"); + } else { + sprintf(String, "%d", gSubMenuSelection); + } + break; + + case MENU_BCL: + case MENU_BEEP: + case MENU_AUTOLK: + case MENU_S_ADD1: + case MENU_S_ADD2: + case MENU_STE: + case MENU_D_ST: + case MENU_D_DCD: + case MENU_AM: + case MENU_NOAA_S: + case MENU_350TX: + case MENU_200TX: + case MENU_500TX: + case MENU_350EN: + case MENU_SCREN: + strcpy(String, gSubMenu_OFF_ON[gSubMenuSelection]); + break; + + case MENU_MEM_CH: + case MENU_1_CALL: + case MENU_DEL_CH: + UI_GenerateChannelStringEx( + String, + RADIO_CheckValidChannel((uint16_t)gSubMenuSelection, false, 0), + (uint8_t)gSubMenuSelection + ); + break; + + case MENU_SAVE: + strcpy(String, gSubMenu_SAVE[gSubMenuSelection]); + break; + + case MENU_TDR: + case MENU_WX: + strcpy(String, gSubMenu_CHAN[gSubMenuSelection]); + break; + + case MENU_TOT: + if (gSubMenuSelection == 0) { + strcpy(String, "OFF"); + } else { + sprintf(String, "%dmin", gSubMenuSelection); + } + break; + + case MENU_VOICE: + strcpy(String, gSubMenu_VOICE[gSubMenuSelection]); + break; + + case MENU_SC_REV: + strcpy(String, gSubMenu_SC_REV[gSubMenuSelection]); + break; + + case MENU_MDF: + strcpy(String, gSubMenu_MDF[gSubMenuSelection]); + break; + + case MENU_RP_STE: + if (gSubMenuSelection == 0) { + strcpy(String, "OFF"); + } else { + sprintf(String, "%d*100ms", gSubMenuSelection); + } + break; + + case MENU_S_LIST: + sprintf(String, "LIST%d", gSubMenuSelection); + break; + + case MENU_AL_MOD: + sprintf(String, gSubMenu_AL_MOD[gSubMenuSelection]); + break; + + case MENU_ANI_ID: + strcpy(String, gEeprom.ANI_DTMF_ID); + break; + + case MENU_UPCODE: + strcpy(String, gEeprom.DTMF_UP_CODE); + break; + + case MENU_DWCODE: + strcpy(String, gEeprom.DTMF_DOWN_CODE); + break; + + case MENU_D_RSP: + strcpy(String, gSubMenu_D_RSP[gSubMenuSelection]); + break; + + case MENU_D_HOLD: + sprintf(String, "%ds", gSubMenuSelection); + break; + + case MENU_D_PRE: + sprintf(String, "%d*10ms", gSubMenuSelection); + break; + + case MENU_PTT_ID: + strcpy(String, gSubMenu_PTT_ID[gSubMenuSelection]); + break; + + case MENU_D_LIST: + gIsDtmfContactValid = DTMF_GetContact((uint8_t)gSubMenuSelection - 1, Contact); + if (!gIsDtmfContactValid) { + // Ghidra being weird again... + memcpy(String, "NULL\0\0\0", 8); + } else { + memcpy(String, Contact, 8); + } + break; + + case MENU_PONMSG: + strcpy(String, gSubMenu_PONMSG[gSubMenuSelection]); + break; + + case MENU_ROGER: + strcpy(String, gSubMenu_ROGER[gSubMenuSelection]); + break; + + case MENU_VOL: + sprintf(String, "%.2fV", gBatteryVoltageAverage * 0.01); + break; + + case MENU_RESET: + strcpy(String, gSubMenu_RESET[gSubMenuSelection]); + break; + + case MENU_F_LOCK: + strcpy(String, gSubMenu_F_LOCK[gSubMenuSelection]); + break; + } + + UI_PrintString(String, 50, 127, 2, 8, true); + + if (gMenuCursor == MENU_OFFSET) { + UI_PrintString("MHz", 50, 127, 4, 8, true); + } + + if ((gMenuCursor == MENU_RESET || gMenuCursor == MENU_MEM_CH || gMenuCursor == MENU_DEL_CH) && gAskForConfirmation) { + if (gAskForConfirmation == 1) { + strcpy(String, "SURE?"); + } else { + strcpy(String, "WAIT!"); + } + UI_PrintString(String, 50, 127, 4, 8, true); + } + + if ((gMenuCursor == MENU_R_CTCS || gMenuCursor == MENU_R_DCS) && g_20000381) { + UI_PrintString("SCAN", 50, 127, 4, 8, true); + } + + if (gMenuCursor == MENU_UPCODE) { + if (strlen(gEeprom.DTMF_UP_CODE) > 8) { + UI_PrintString(gEeprom.DTMF_UP_CODE + 8, 50, 127, 4, 8, true); + } + } + if (gMenuCursor == MENU_DWCODE) { + if (strlen(gEeprom.DTMF_DOWN_CODE) > 8) { + UI_PrintString(gEeprom.DTMF_DOWN_CODE + 8, 50, 127, 4, 8, true); + } + } + if (gMenuCursor == MENU_D_LIST && gIsDtmfContactValid) { + Contact[11] = 0; + memcpy(&gDTMF_ID, Contact + 8, 4); + sprintf(String, "ID:%s", Contact + 8); + UI_PrintString(String, 50, 127, 4, 8, true); + } + + if (gMenuCursor == MENU_R_CTCS || gMenuCursor == MENU_T_CTCS || + gMenuCursor == MENU_R_DCS || gMenuCursor == MENU_T_DCS || gMenuCursor == MENU_D_LIST) { + uint8_t Offset; + + NUMBER_ToDigits((uint8_t)gSubMenuSelection, String); + Offset = (gMenuCursor == MENU_D_LIST) ? 2 : 3; + UI_DisplaySmallDigits(Offset, String + (8 - Offset), 105, 0); + } + + if (gMenuCursor == MENU_SLIST1 || gMenuCursor == MENU_SLIST2) { + i = gMenuCursor - MENU_SLIST1; + + if (gSubMenuSelection == 0xFF) { + sprintf(String, "NULL"); + } else { + UI_GenerateChannelStringEx(String, true, (uint8_t)gSubMenuSelection); + } + + if (gSubMenuSelection == 0xFF || gEeprom.SCAN_LIST_ENABLED[i] != true) { + UI_PrintString(String, 50, 127, 2, 8, 1); + } else { + UI_PrintString(String, 50, 127, 0, 8, 1); + if (gEeprom.SCANLIST_PRIORITY_CH1[i] < 200) { + sprintf(String, "PRI1:%d", gEeprom.SCANLIST_PRIORITY_CH1[i] + 1); + UI_PrintString(String, 50, 127, 2, 8, 1); + } + if (gEeprom.SCANLIST_PRIORITY_CH2[i] < 200) { + sprintf(String, "PRI2:%d", gEeprom.SCANLIST_PRIORITY_CH2[i] + 1); + UI_PrintString(String, 50, 127, 4, 8, 1); + } + } + } + + ST7565_BlitFullScreen(); +} + diff --git a/ui/menu.h b/ui/menu.h new file mode 100644 index 0000000..a8d0135 --- /dev/null +++ b/ui/menu.h @@ -0,0 +1,92 @@ +/* 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 UI_MENU_H +#define UI_MENU_H + +#include +#include + +enum { + MENU_SQL = 0, + MENU_STEP = 1, + MENU_TXP = 2, + MENU_R_DCS = 3, + MENU_R_CTCS = 4, + MENU_T_DCS = 5, + MENU_T_CTCS = 6, + MENU_SFT_D = 7, + MENU_OFFSET = 8, + MENU_W_N = 9, + MENU_SCR = 10, + MENU_BCL = 11, + MENU_MEM_CH = 12, + MENU_SAVE = 13, + MENU_VOX = 14, + MENU_ABR = 15, + MENU_TDR = 16, + MENU_WX = 17, + MENU_BEEP = 18, + MENU_TOT = 19, + MENU_VOICE = 20, + MENU_SC_REV = 21, + MENU_MDF = 22, + MENU_AUTOLK = 23, + MENU_S_ADD1 = 24, + MENU_S_ADD2 = 25, + MENU_STE = 26, + MENU_RP_STE = 27, + MENU_MIC = 28, + MENU_1_CALL = 29, + MENU_S_LIST = 30, + MENU_SLIST1 = 31, + MENU_SLIST2 = 32, + MENU_AL_MOD = 33, + MENU_ANI_ID = 34, + MENU_UPCODE = 35, + MENU_DWCODE = 36, + MENU_D_ST = 37, + MENU_D_RSP = 38, + MENU_D_HOLD = 39, + MENU_D_PRE = 40, + MENU_PTT_ID = 41, + MENU_D_DCD = 42, + MENU_D_LIST = 43, + MENU_PONMSG = 44, + MENU_ROGER = 45, + MENU_VOL = 46, + MENU_AM = 47, + MENU_NOAA_S = 48, + MENU_DEL_CH = 49, + MENU_RESET = 50, + MENU_350TX = 51, + MENU_F_LOCK = 52, + MENU_200TX = 53, + MENU_500TX = 54, + MENU_350EN = 55, + MENU_SCREN = 56, +}; + +extern bool gIsInSubMenu; + +extern uint8_t gMenuCursor; +extern int8_t gMenuScrollDirection; +extern uint32_t gSubMenuSelection; + +void UI_DisplayMenu(void); + +#endif + diff --git a/ui/scanner.c b/ui/scanner.c new file mode 100644 index 0000000..084fd75 --- /dev/null +++ b/ui/scanner.c @@ -0,0 +1,79 @@ +/* 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 +#include +#include "dcs.h" +#include "driver/st7565.h" +#include "external/printf/printf.h" +#include "gui.h" +#include "misc.h" +#include "ui/helper.h" +#include "ui/scanner.h" + +void UI_DisplayScanner(void) +{ + char String[16]; + bool bCentered; + uint8_t Start; + + memset(gFrameBuffer, 0, sizeof(gFrameBuffer)); + memset(String, 0, sizeof(String)); + + if (g_20000458 == 1 || (gScanState != 0 && gScanState != 3)) { + sprintf(String, "FREQ:%.5f", gScanFrequency * 1e-05); + } else { + sprintf(String, "FREQ:**.*****"); + } + UI_PrintString(String, 2, 127, 1, 8, 0); + memset(String, 0, sizeof(String)); + + if (gScanState < 2 || g_2000045C != 1) { + sprintf(String, "CTC:******"); + } else if (g_CxCSS_Type == 1) { + sprintf(String, "CTC:%.1fHz", CTCSS_Options[g_CxCSS_Index] * 0.1); + } else { + sprintf(String, "DCS:D%03oN", DCS_Options[g_CxCSS_Index]); + } + UI_PrintString(String, 2, 127, 3, 8, 0); + memset(String, 0, sizeof(String)); + + if (g_20000461 == 2) { + strcpy(String, "SAVE?"); + Start = 0; + bCentered = 1; + } else { + if (g_20000461 == 1) { + strcpy(String, "SAVE:"); + UI_GenerateChannelStringEx(String + 5, gShowChPrefix, gScanChannel); + } else if (gScanState < 2) { + strcpy(String, "SCAN"); + memset(String + 4, '.', (g_20000464 & 7) + 1); + } else { + if (gScanState == 2) { + strcpy(String, "SCAN CMP."); + } else { + strcpy(String, "SCAN FAIL."); + } + } + Start = 2; + bCentered = 0; + } + + UI_PrintString(String, Start, 127, 5, 8, bCentered); + ST7565_BlitFullScreen(); +} + diff --git a/ui/scanner.h b/ui/scanner.h new file mode 100644 index 0000000..ab04aff --- /dev/null +++ b/ui/scanner.h @@ -0,0 +1,23 @@ +/* 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 UI_SCANNER_H +#define UI_SCANNER_H + +void UI_DisplayScanner(void); + +#endif +