diff --git a/.gitignore b/.gitignore index 9083b1c..c754953 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ obj/ bin/ +src/external/ .vsconfig/ diff --git a/Makefile b/Makefile index 5121282..96851ba 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ SIZE = arm-none-eabi-size GIT_HASH := $(shell git rev-parse --short HEAD) ASFLAGS = -c -mcpu=cortex-m0 -# CFLAGS = -Os -Wall -Werror -mcpu=cortex-m0 -fno-delete-null-pointer-checks -std=c11 -MMD -ffunction-sections -fdata-sections +# CFLAGS = -Os -Wall -Wno-error -mcpu=cortex-m0 -fno-delete-null-pointer-checks -std=c11 -MMD -ffunction-sections -fdata-sections CFLAGS = -Os -Wall -Wno-error -mcpu=cortex-m0 -fno-builtin -fshort-enums -fno-delete-null-pointer-checks -std=c2x -MMD -flto=auto -Wextra # CFLAGS = -Os -Wall -Wno-error -mcpu=cortex-m0 -fno-builtin -fshort-enums -fno-delete-null-pointer-checks -std=c2x -MMD -ffunction-sections -fdata-sections -Wextra CFLAGS += -DPRINTF_INCLUDE_CONFIG_H @@ -76,4 +76,4 @@ $(BIN_DIR) $(OBJ_DIR) $(BIN_DIR): -include $(DEPS) clean: - rm -f $(TARGET).bin $(TARGET).packed.bin $(TARGET) $(OBJS) $(DEPS) + rm -f $(TARGET).bin $(TARGET).packed.bin $(TARGET) $(OBJ_DIR)/*.o $(OBJ_DIR)/*.d $(OBJ_DIR)/**/*.o $(OBJ_DIR)/**/*.d diff --git a/README.md b/README.md new file mode 100644 index 0000000..9f1daae --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# Reborn firmware + +Based on [https://github.com/DualTachyon/uv-k5-firmware](https://github.com/DualTachyon/uv-k5-firmware). + +[Telegram group](https://t.me/uvk5_spectrum_talk) + +[Donations](https://t.me/uvk5_spectrum_talk/6032/6035) + +## License + +To be clear, I don't like license preamble inside everu source file. + +So, license is Apache, main author is [Dual Tachyon](https://github.com/DualTachyon). + +I permit all type of copypasting/modifications. + diff --git a/src/apps/about.c b/src/apps/about.c index 96b4b3f..432e91a 100644 --- a/src/apps/about.c +++ b/src/apps/about.c @@ -1,82 +1,13 @@ #include "about.h" -#include "../driver/bk4819.h" -#include "../misc.h" -#include "../scheduler.h" #include "../ui/graphics.h" -#include "../ui/statusline.h" #include "apps.h" -const char *qr[] = { - "111111101111101011111101001111111", "100000101010001010101011101000001", - "101110100000011101101001001011101", "101110101011100001111010001011101", - "101110100010100011001000101011101", "100000100001110111011110001000001", - "111111101010101010101010101111111", "000000001100101111110000100000000", - "101101110110101111100101101001011", "000001010010110000110001001101111", - "110010100100110010000011000111001", "111000000110100111100001100101011", - "111000110101101110110011110111011", "001010001010011000111001110100110", - "100100100010001001110000101111100", "011101001011111100000110011001100", - "011110101111000010101111011010100", "101011000110010101001001001011011", - "000100110001011110100000000110110", "010110010101101010110000110010001", - "011100110000111110001100000101110", "111111011010100111100101001000101", - "000110101000011101100101011101111", "010001010011111100111010101011011", - "101111101111111001110010111110000", "000000001011110110010000100011010", - "111111101101001001011001101010000", "100000101100001000000111100011101", - "101110100100011000100111111110101", "101110101111110011000001100101001", - "101110101111111101000001111101100", "100000100100100001111000100110001", - "111111101101010001110101000011100", -}; - -void ABOUT_Init() { STATUSLINE_SetText("t.me/uvk5_spectrum_talk"); } - -void ABOUT_Deinit() { - BK4819_ToggleGpioOut(BK4819_GPIO0_PIN28_GREEN, false); - BK4819_ToggleGpioOut(BK4819_GPIO5_PIN1_RED, false); -} - -static uint32_t lastUpdate = 0; -static bool red = false; - -void ABOUT_Update() { - if (elapsedMilliseconds - lastUpdate >= 500) { - red = (elapsedMilliseconds / 500) % 3; - BK4819_ToggleGpioOut(BK4819_GPIO0_PIN28_GREEN, - (elapsedMilliseconds / 500) % 2); - BK4819_ToggleGpioOut(BK4819_GPIO5_PIN1_RED, red); - lastUpdate = elapsedMilliseconds; - gRedrawScreen = true; - } -} - void ABOUT_Render() { UI_ClearScreen(); - for (uint8_t y = 0; y < ARRAY_SIZE(qr); y++) { - for (uint8_t x = 0; x < strlen(qr[0]); x++) { - if (qr[y][x] == '1') { - DrawRect(x * 2, y * 1 + 9, 2, 1, C_FILL); - } - } - } - PrintMediumEx(68 + 6, 16, POS_L, C_FILL, "OSFW"); - PrintSmallEx(96 + 2, 14, POS_L, C_FILL, "REBORN"); - PrintMediumEx(LCD_WIDTH - 1, 16 + 6, POS_R, C_FILL, "FAGCI"); - PrintSmallEx(LCD_WIDTH - 29, 16 + 6, POS_R, C_FILL, "by"); - - PrintMediumBoldEx(32, 50, POS_C, C_FILL, "Happy"); - PrintMediumBoldEx(32, 60, POS_C, C_FILL, "2024!"); - - if (red) { - PutPixel(LCD_WIDTH - 32, 32 - 4, C_FILL); - PutPixel(LCD_WIDTH - 32 - 3, 32 - 1, C_FILL); - PutPixel(LCD_WIDTH - 32 + 3, 32 - 1, C_FILL); - PutPixel(LCD_WIDTH - 32, 32 + 2, C_FILL); - } - - PrintSmallEx(LCD_WIDTH - 32, 32 + 2, POS_C, C_FILL, "*"); - PrintSmallEx(LCD_WIDTH - 32, 32 + 6, POS_C, C_FILL, "c"); - PrintSmallEx(LCD_WIDTH - 32, 32 + 12, POS_C, C_FILL, "ris"); - PrintSmallEx(LCD_WIDTH - 32, 32 + 18, POS_C, C_FILL, "tmas"); - PrintSmallEx(LCD_WIDTH - 32, 32 + 24, POS_C, C_FILL, "tree is"); - PrintSmallEx(LCD_WIDTH - 32, 32 + 30, POS_C, C_FILL, "here"); + PrintMediumEx(LCD_XCENTER, LCD_YCENTER + 8, POS_C, C_FILL, "r3b0rn"); + PrintSmallEx(LCD_XCENTER, LCD_YCENTER + 14, POS_C, C_FILL, "by FAGCI"); + PrintSmallEx(LCD_XCENTER, LCD_YCENTER + 24, POS_C, C_FILL, + "t.me/uvk5_spectrum_talk"); } bool ABOUT_key(KEY_Code_t k, bool p, bool h) { diff --git a/src/apps/about.h b/src/apps/about.h index a1e6c8a..425d404 100644 --- a/src/apps/about.h +++ b/src/apps/about.h @@ -3,9 +3,6 @@ #include "../driver/keyboard.h" -void ABOUT_Init(); -void ABOUT_Deinit(); -void ABOUT_Update(); void ABOUT_Render(); bool ABOUT_key(KEY_Code_t k, bool p, bool h); diff --git a/src/apps/analyzer.c b/src/apps/analyzer.c index 35ff4ce..0a60340 100644 --- a/src/apps/analyzer.c +++ b/src/apps/analyzer.c @@ -92,7 +92,7 @@ void ANALYZER_init(void) { SVC_Toggle(SVC_LISTEN, false, 0); RADIO_ToggleRX(false); RADIO_LoadCurrentVFO(); - RADIO_ToggleBK1080(false); + // RADIO_ToggleBK1080(false); gMonitorMode = false; @@ -244,5 +244,5 @@ void ANALYZER_render(void) { PrintSmallEx(spectrumWidth / 2, LCD_HEIGHT - 1, POS_C, C_FILL, "%u.%05u", centerF / 100000, centerF % 100000); - lastRender = elapsedMilliseconds; + lastRender = Now(); } diff --git a/src/apps/antenna.c b/src/apps/antenna.c index 75e09dc..ca7e2f9 100644 --- a/src/apps/antenna.c +++ b/src/apps/antenna.c @@ -18,8 +18,6 @@ void ANTENNA_init(void) { f = GetScreenF(radio->rx.f); } -void ANTENNA_update(void) {} - bool ANTENNA_key(KEY_Code_t key, bool bKeyPressed, bool bKeyHeld) { if (!bKeyPressed && !bKeyHeld) { switch (key) { diff --git a/src/apps/antenna.h b/src/apps/antenna.h index dddd0e6..85ee7ca 100644 --- a/src/apps/antenna.h +++ b/src/apps/antenna.h @@ -6,7 +6,6 @@ #include void ANTENNA_init(); -void ANTENNA_update(); bool ANTENNA_key(KEY_Code_t key, bool bKeyPressed, bool bKeyHeld); void ANTENNA_render(); void ANTENNA_deinit(); diff --git a/src/apps/apps.c b/src/apps/apps.c index a3b7f78..7ecffe0 100644 --- a/src/apps/apps.c +++ b/src/apps/apps.c @@ -11,17 +11,15 @@ #include "fastscan.h" #include "finput.h" #include "lootlist.h" -#include "messenger.h" +#include "memview.h" #include "presetcfg.h" #include "presetlist.h" #include "reset.h" #include "savech.h" -#include "scanlists.h" #include "settings.h" +#include "si.h" #include "spectrumreborn.h" #include "still.h" -#include "taskman.h" -#include "test.h" #include "textinput.h" #include "vfo1.h" #include "vfo2.h" @@ -64,53 +62,52 @@ const AppType_t appsAvailableToRun[RUN_APPS_COUNT] = { APP_VFO1, // APP_STILL, // APP_VFO2, // + APP_SI, // APP_CH_SCANNER, // + APP_SAVECH, // APP_SPECTRUM, // APP_ANALYZER, // APP_FASTSCAN, // APP_LOOT_LIST, // - APP_SCANLISTS, // APP_PRESETS_LIST, // APP_ANT, // - APP_TASKMAN, // - APP_TEST, // + APP_MEMVIEW, // APP_ABOUT, // }; const App apps[APPS_COUNT] = { {"None"}, - {"Test", TEST_Init, TEST_Update, TEST_Render, TEST_key}, + {"EEPROM view", MEMVIEW_Init, MEMVIEW_Update, MEMVIEW_Render, MEMVIEW_key, + NULL}, {"Spectrum band", SPECTRUM_init, SPECTRUM_update, SPECTRUM_render, SPECTRUM_key, SPECTRUM_deinit}, {"Spectrum analyzer", ANALYZER_init, ANALYZER_update, ANALYZER_render, ANALYZER_key, ANALYZER_deinit}, {"CH Scan", CHSCANNER_init, CHSCANNER_update, CHSCANNER_render, CHSCANNER_key, CHSCANNER_deinit}, + {"Channels", SAVECH_init, SAVECH_update, SAVECH_render, SAVECH_key, NULL}, {"Freq catch", FASTSCAN_init, FASTSCAN_update, FASTSCAN_render, FASTSCAN_key, FASTSCAN_deinit}, {"1 VFO pro", STILL_init, STILL_update, STILL_render, STILL_key, STILL_deinit}, {"Frequency input", FINPUT_init, NULL, FINPUT_render, FINPUT_key, FINPUT_deinit}, - {"Run app", APPSLIST_init, NULL, APPSLIST_render, APPSLIST_key}, - {"Loot", LOOTLIST_init, NULL, LOOTLIST_render, LOOTLIST_key}, - {"Presets", PRESETLIST_init, NULL, PRESETLIST_render, PRESETLIST_key}, - {"Reset", RESET_Init, RESET_Update, RESET_Render, RESET_key}, - {"Text input", TEXTINPUT_init, TEXTINPUT_update, TEXTINPUT_render, - TEXTINPUT_key, TEXTINPUT_deinit}, - {"VFO config", VFOCFG_init, VFOCFG_update, VFOCFG_render, VFOCFG_key}, + {"Run app", APPSLIST_init, NULL, APPSLIST_render, APPSLIST_key, NULL}, + {"Loot", LOOTLIST_init, NULL, LOOTLIST_render, LOOTLIST_key, NULL}, + {"Presets", PRESETLIST_init, NULL, PRESETLIST_render, PRESETLIST_key, NULL}, + {"Reset", RESET_Init, RESET_Update, RESET_Render, RESET_key, NULL}, + {"Text input", TEXTINPUT_init, NULL, TEXTINPUT_render, TEXTINPUT_key, + TEXTINPUT_deinit}, + {"VFO config", VFOCFG_init, VFOCFG_update, VFOCFG_render, VFOCFG_key, NULL}, {"Preset config", PRESETCFG_init, PRESETCFG_update, PRESETCFG_render, - PRESETCFG_key}, - {"Scanlists", SCANLISTS_init, SCANLISTS_update, SCANLISTS_render, - SCANLISTS_key}, - {"Save to channel", SAVECH_init, SAVECH_update, SAVECH_render, SAVECH_key}, - {"Settings", SETTINGS_init, SETTINGS_update, SETTINGS_render, SETTINGS_key}, + PRESETCFG_key, NULL}, + {"Settings", SETTINGS_init, NULL, SETTINGS_render, SETTINGS_key, NULL}, {"1 VFO", VFO1_init, VFO1_update, VFO1_render, VFO1_key, VFO1_deinit}, {"2 VFO", VFO2_init, VFO2_update, VFO2_render, VFO2_key, VFO2_deinit}, - {"ABOUT", ABOUT_Init, ABOUT_Update, ABOUT_Render, ABOUT_key, ABOUT_Deinit}, - {"Antenna len", ANTENNA_init, ANTENNA_update, ANTENNA_render, ANTENNA_key, + {"SI47XX", SI_init, SI_update, SI_render, SI_key, SI_deinit}, + {"ABOUT", NULL, NULL, ABOUT_Render, ABOUT_key, NULL}, + {"Antenna len", ANTENNA_init, NULL, ANTENNA_render, ANTENNA_key, ANTENNA_deinit}, - {"Task manager", TASKMAN_Init, NULL, TASKMAN_Render, TASKMAN_Key}, }; bool APPS_key(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld) { @@ -148,7 +145,9 @@ void APPS_run(AppType_t app) { if (appsStack[stackIndex] == app) { return; } - APPS_deinit(); + if (app != APP_FINPUT && app != APP_TEXTINPUT) { + APPS_deinit(); + } pushApp(app); APPS_init(app); } @@ -166,7 +165,14 @@ bool APPS_exit(void) { return false; } APPS_deinit(); - popApp(); - APPS_init(APPS_Peek()); + AppType_t app = popApp(); + if (app != APP_FINPUT && app != APP_TEXTINPUT) { + APPS_init(APPS_Peek()); + } else { + gCurrentApp = APPS_Peek(); + + STATUSLINE_SetText("%s", apps[gCurrentApp].name); + gRedrawScreen = true; + } return true; } diff --git a/src/apps/apps.h b/src/apps/apps.h index 52c3ac7..5e7e456 100644 --- a/src/apps/apps.h +++ b/src/apps/apps.h @@ -3,15 +3,16 @@ #include "../driver/keyboard.h" -#define APPS_COUNT 23 +#define APPS_COUNT 22 #define RUN_APPS_COUNT 14 typedef enum { APP_NONE, - APP_TEST, + APP_MEMVIEW, APP_SPECTRUM, APP_ANALYZER, APP_CH_SCANNER, + APP_SAVECH, APP_FASTSCAN, APP_STILL, APP_FINPUT, @@ -22,14 +23,12 @@ typedef enum { APP_TEXTINPUT, APP_VFO_CFG, APP_PRESET_CFG, - APP_SCANLISTS, - APP_SAVECH, APP_SETTINGS, APP_VFO1, APP_VFO2, + APP_SI, APP_ABOUT, APP_ANT, - APP_TASKMAN, } AppType_t; typedef struct App { diff --git a/src/apps/appslist.c b/src/apps/appslist.c index 1e40e1e..409b4c6 100644 --- a/src/apps/appslist.c +++ b/src/apps/appslist.c @@ -36,7 +36,7 @@ static void setMenuIndexAndRun(uint16_t v) { } void APPSLIST_init(void) { gRedrawScreen = true; } -void APPSLIST_update(void) {} + bool APPSLIST_key(KEY_Code_t key, bool bKeyPressed, bool bKeyHeld) { if (!bKeyPressed && !bKeyHeld) { if (!gIsNumNavInput && key >= KEY_0 && key <= KEY_9) { @@ -59,8 +59,7 @@ bool APPSLIST_key(KEY_Code_t key, bool bKeyPressed, bool bKeyHeld) { return true; case KEY_MENU: APPS_exit(); - if (app == APP_PRESETS_LIST || app == APP_LOOT_LIST || - app == APP_SCANLISTS) { + if (app == APP_PRESETS_LIST || app == APP_LOOT_LIST || app == APP_SAVECH) { APPS_run(app); } else { APPS_runManual(app); diff --git a/src/apps/appslist.h b/src/apps/appslist.h index 2acba88..eb3478c 100644 --- a/src/apps/appslist.h +++ b/src/apps/appslist.h @@ -6,7 +6,6 @@ #include void APPSLIST_init(); -void APPSLIST_update(); bool APPSLIST_key(KEY_Code_t key, bool bKeyPressed, bool bKeyHeld); void APPSLIST_render(); diff --git a/src/apps/channelscanner.c b/src/apps/channelscanner.c index 426df00..a67f059 100644 --- a/src/apps/channelscanner.c +++ b/src/apps/channelscanner.c @@ -24,18 +24,20 @@ static void showItem(uint16_t i, uint16_t index, bool isCurrent) { if (isCurrent) { FillRect(0, y, LCD_WIDTH - 3, MENU_ITEM_H, C_FILL); } + if (item->blacklist) { + PrintMediumEx(2, y + 8, POS_L, C_INVERT, "X"); + } + if (gIsListening && item->f == currentChannel.rx.f) { + PrintSymbolsEx(LCD_WIDTH - 24, y + 8, POS_R, C_INVERT, "%c", SYM_BEEP); + } PrintMediumEx(8, y + 8, POS_L, C_INVERT, "%s", ch.name); PrintSmallEx(LCD_WIDTH - 5, y + 8, POS_R, C_INVERT, "R%u", item->rssi); // TODO: antenna } static void scanFn(bool forward) { - if (gIsListening) { - currentIndex = scanIndex; - } else { - IncDecI32(&scanIndex, 0, gScanlistSize, forward ? 1 : -1); - RADIO_TuneToPure(LOOT_Item(scanIndex)->f, true); - } + IncDecI32(&scanIndex, 0, gScanlistSize, forward ? 1 : -1); + RADIO_TuneToPure(LOOT_Item(scanIndex)->f, true); } void CHSCANNER_init(void) { @@ -52,9 +54,9 @@ void CHSCANNER_init(void) { loot->lastTimeOpen = 0; } - if (gScanlistSize) { + /* if (gScanlistSize) { RADIO_TuneToPure(LOOT_Item(scanIndex)->f, true); - } + } */ gScanFn = scanFn; SVC_Toggle(SVC_SCAN, true, 10); @@ -75,6 +77,29 @@ bool CHSCANNER_key(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld) { break; } } + if (bKeyHeld && bKeyPressed && !gRepeatHeld) { + switch (Key) { + case KEY_1: + case KEY_2: + case KEY_3: + case KEY_4: + case KEY_5: + case KEY_6: + case KEY_7: + case KEY_8: + gSettings.currentScanlist = Key - KEY_1; + CHSCANNER_init(); + currentIndex = 0; + return true; + case KEY_0: + gSettings.currentScanlist = 15; + CHSCANNER_init(); + currentIndex = 0; + return true; + default: + break; + } + } if (!bKeyPressed && !bKeyHeld) { switch (Key) { @@ -91,6 +116,9 @@ bool CHSCANNER_key(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld) { RADIO_SaveCurrentVFO(); APPS_run(APP_ANALYZER); return true; + case KEY_SIDE1: + LOOT_Item(currentIndex)->blacklist = !LOOT_Item(currentIndex)->blacklist; + return true; default: break; @@ -99,7 +127,11 @@ bool CHSCANNER_key(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld) { return false; } -void CHSCANNER_update(void) {} +void CHSCANNER_update(void) { + if (gIsListening && LOOT_Item(scanIndex)->f != currentChannel.rx.f) { + CHANNELS_Load(gScanlist[scanIndex], ¤tChannel); + } +} void CHSCANNER_render(void) { UI_ClearScreen(); @@ -111,10 +143,6 @@ void CHSCANNER_render(void) { } if (gIsListening) { - currentIndex = scanIndex; // HACK - if (LOOT_Item(scanIndex)->f != currentChannel.rx.f) { - CHANNELS_Load(gScanlist[scanIndex], ¤tChannel); - } PrintMediumBoldEx(LCD_XCENTER, MENU_Y + 7, POS_C, C_FILL, "%s", currentChannel.name); } else { diff --git a/src/apps/lootlist.c b/src/apps/lootlist.c index b2a8658..6900693 100644 --- a/src/apps/lootlist.c +++ b/src/apps/lootlist.c @@ -5,16 +5,12 @@ #include "../helper/channels.h" #include "../helper/lootlist.h" #include "../helper/measurements.h" -#include "../helper/presetlist.h" -#include "../misc.h" #include "../radio.h" #include "../scheduler.h" -#include "../ui/components.h" #include "../ui/graphics.h" #include "../ui/menu.h" #include "../ui/statusline.h" #include "apps.h" -#include static uint8_t menuIndex = 0; static const uint8_t MENU_ITEM_H_LARGER = 15; @@ -56,7 +52,6 @@ static void exportLootList(void) { } } UART_printf("--- >8 ---\n"); - UART_flush(); } static void getLootItem(uint16_t i, uint16_t index, bool isCurrent) { @@ -92,7 +87,7 @@ static void getLootItemShort(uint16_t i, uint16_t index, bool isCurrent) { uint32_t f = item->f; const uint8_t x = LCD_WIDTH - 6; const uint8_t y = MENU_Y + i * MENU_ITEM_H; - const uint32_t ago = (elapsedMilliseconds - item->lastTimeOpen) / 1000; + const uint32_t ago = (Now() - item->lastTimeOpen) / 1000; if (isCurrent) { FillRect(0, y, LCD_WIDTH - 3, MENU_ITEM_H, C_FILL); } @@ -164,8 +159,6 @@ static void saveAllToFreeChannels(void) { } } -void LOOTLIST_update(void) {} - bool LOOTLIST_key(KEY_Code_t key, bool bKeyPressed, bool bKeyHeld) { Loot *item = LOOT_Item(menuIndex); const uint8_t MENU_SIZE = LOOT_Size(); diff --git a/src/apps/lootlist.h b/src/apps/lootlist.h index 9c4dc69..d363d14 100644 --- a/src/apps/lootlist.h +++ b/src/apps/lootlist.h @@ -6,7 +6,6 @@ #include void LOOTLIST_init(); -void LOOTLIST_update(); bool LOOTLIST_key(KEY_Code_t key, bool bKeyPressed, bool bKeyHeld); void LOOTLIST_render(); diff --git a/src/apps/test.c b/src/apps/memview.c similarity index 51% rename from src/apps/test.c rename to src/apps/memview.c index 529b651..bb2c3e1 100644 --- a/src/apps/test.c +++ b/src/apps/memview.c @@ -1,4 +1,4 @@ -#include "test.h" +#include "memview.h" #include "../driver/eeprom.h" #include "../driver/st7565.h" #include "../helper/measurements.h" @@ -6,46 +6,57 @@ #include "../ui/graphics.h" #include "apps.h" -void TEST_Init(void) {} +static uint32_t page = 0; +static const uint8_t PAGE_SZ = 64; +static uint16_t pagesCount; -void TEST_Update(void) { gRedrawScreen = true; } +void MEMVIEW_Init(void) { pagesCount = SETTINGS_GetEEPROMSize() / PAGE_SZ; } -static uint32_t page = 0; -const uint8_t PAGE_SZ = 64; +void MEMVIEW_Update(void) {} -void TEST_Render(void) { - UI_ClearScreen(); +void MEMVIEW_Render(void) { uint8_t buf[64] = {0}; EEPROM_ReadBuffer(page * PAGE_SZ, buf, PAGE_SZ); + UI_ClearScreen(); for (uint8_t i = 0; i < PAGE_SZ; ++i) { uint32_t offset = i + page * PAGE_SZ; + uint8_t col = i % 8; + uint8_t row = i / 8; + uint8_t rowYBL = row * 6 + 8 + 5; + if (i % 8 == 0) { - PrintSmall(0, (i / 8) * 6 + 8 + 5, "%u", page * PAGE_SZ + i); + PrintSmall(0, rowYBL, "%u", page * PAGE_SZ + i); } - PrintSmall(16 + (i % 8) * 9, (i / 8) * 6 + 8 + 5, "%02x", buf[i]); - PrintSmall(88 + (i % 8) * 5, (i / 8) * 6 + 8 + 5, "%c", + PrintSmall(16 + col * 9, rowYBL, "%02x", buf[i]); + PrintSmall(88 + col * 5, rowYBL, "%c", buf[i] >= 32 && buf[i] < 128 ? buf[i] : '.'); if (offset == SETTINGS_OFFSET || offset == VFOS_OFFSET || offset == PRESETS_OFFSET || (offset >= PRESETS_OFFSET && (offset - PRESETS_OFFSET) % PRESET_SIZE == 0)) { - FillRect(16 + (i % 8) * 9 - 1, (i / 8) * 6 + 8, 9, 7, C_INVERT); + FillRect(16 + col * 9 - 1, row * 6 + 8, 9, 7, C_INVERT); } } } -bool TEST_key(KEY_Code_t k, bool p, bool h) { +bool MEMVIEW_key(KEY_Code_t k, bool p, bool h) { switch (k) { case KEY_EXIT: APPS_exit(); return true; case KEY_UP: - IncDec32(&page, 0, SETTINGS_GetEEPROMSize() / PAGE_SZ, -1); + IncDec32(&page, 0, pagesCount, -1); return true; case KEY_DOWN: - IncDec32(&page, 0, SETTINGS_GetEEPROMSize() / PAGE_SZ, 1); + IncDec32(&page, 0, pagesCount, 1); + return true; + case KEY_3: + IncDec32(&page, 0, pagesCount, -8196 / PAGE_SZ); + return true; + case KEY_9: + IncDec32(&page, 0, pagesCount, 8196 / PAGE_SZ); return true; case KEY_MENU: return false; diff --git a/src/apps/memview.h b/src/apps/memview.h new file mode 100644 index 0000000..1a9e6f4 --- /dev/null +++ b/src/apps/memview.h @@ -0,0 +1,11 @@ +#ifndef MEMVIEW_H +#define MEMVIEW_H + +#include "../driver/keyboard.h" + +void MEMVIEW_Init(); +void MEMVIEW_Update(); +void MEMVIEW_Render(); +bool MEMVIEW_key(KEY_Code_t k, bool p, bool h); + +#endif /* end of include guard: MEMVIEW_H */ diff --git a/src/apps/presetlist.c b/src/apps/presetlist.c index 56ce723..0bc17bd 100644 --- a/src/apps/presetlist.c +++ b/src/apps/presetlist.c @@ -9,7 +9,7 @@ static uint8_t menuIndex = 0; -static void getPresetText(int32_t i, char *name) { +static void getPresetText(uint16_t i, char *name) { Preset *item = PRESETS_Item(i); uint32_t fs = item->band.bounds.start; uint32_t fe = item->band.bounds.end; @@ -31,8 +31,6 @@ void PRESETLIST_init(void) { menuIndex = gSettings.activePreset; } -void PRESETLIST_update(void) {} - static void setMenuIndexAndRun(uint16_t v) { menuIndex = v - 1; RADIO_SelectPresetSave(menuIndex); diff --git a/src/apps/presetlist.h b/src/apps/presetlist.h index 41a251b..623b69e 100644 --- a/src/apps/presetlist.h +++ b/src/apps/presetlist.h @@ -6,7 +6,6 @@ #include void PRESETLIST_init(); -void PRESETLIST_update(); bool PRESETLIST_key(KEY_Code_t key, bool bKeyPressed, bool bKeyHeld); void PRESETLIST_render(); diff --git a/src/apps/reset.c b/src/apps/reset.c index 40b2e49..0e1d3ba 100644 --- a/src/apps/reset.c +++ b/src/apps/reset.c @@ -7,15 +7,16 @@ #include "../settings.h" #include "../ui/graphics.h" #include "ARMCM0.h" -#include "apps.h" #include +static uint32_t bytesMax = 0; +static uint32_t bytesWrote = 0; +static uint16_t channelsMax = 0; +static uint16_t channelsWrote = 0; static uint8_t presetsWrote = 0; static uint8_t vfosWrote = 0; -static uint16_t channelsWrote = 0; static bool settingsWrote = 0; static uint8_t buf[8]; -static uint16_t bytesWrote = 0; static EEPROMType eepromType; @@ -30,476 +31,6 @@ static VFO defaultVFOs[2] = { }, }; -static Preset - defaultPresets[] = - { - (Preset){ - .band = - { - .bounds = {1500000, 2999999}, - .name = "15-30", - .step = STEP_5_0kHz, - .modulation = MOD_AM, - .bw = BK4819_FILTER_BW_NARROW, - .gainIndex = 16, - .squelch = 3, - .squelchType = SQUELCH_RSSI_NOISE_GLITCH, - }, - .allowTx = false, - .lastUsedFreq = 2713500, - .powCalib = {0x8C, 0x8C, 0x8C}, - }, - (Preset){ - .band = - { - .bounds = {3000000, 6399999}, - .name = "30-64", - .step = STEP_5_0kHz, - .modulation = MOD_FM, - .bw = BK4819_FILTER_BW_NARROW, - .gainIndex = 16, - .squelch = 3, - .squelchType = SQUELCH_RSSI_NOISE_GLITCH, - }, - .allowTx = false, - .lastUsedFreq = 3000000, - .powCalib = {0x8C, 0x8C, 0x8C}, - }, - (Preset){ - .band = - { - .bounds = {6400000, 8799999}, - .name = "64-88", - .step = STEP_100_0kHz, - .modulation = MOD_WFM, - .bw = BK4819_FILTER_BW_NARROW, - .gainIndex = 16, - .squelch = 3, - .squelchType = SQUELCH_RSSI_NOISE_GLITCH, - }, - .allowTx = false, - .lastUsedFreq = 7100000, - .powCalib = {0x8C, 0x8C, 0x8C}, - }, - (Preset){ - .band = - { - .bounds = {8800000, 10799999}, - .name = "Bcast FM", - .step = STEP_100_0kHz, - .modulation = MOD_WFM, - .bw = BK4819_FILTER_BW_NARROW, - .gainIndex = 16, - .squelch = 3, - .squelchType = SQUELCH_RSSI_NOISE_GLITCH, - }, - .allowTx = false, - .lastUsedFreq = 10320000, - .powCalib = {0x8C, 0x8C, 0x8C}, - }, - (Preset){ - .band = - { - .bounds = {10800000, 11799999}, - .name = "108-118", - .step = STEP_12_5kHz, - .modulation = MOD_FM, - .bw = BK4819_FILTER_BW_WIDE, - .gainIndex = 16, - .squelch = 3, - .squelchType = SQUELCH_RSSI_NOISE_GLITCH, - }, - .allowTx = false, - .lastUsedFreq = 10800000, - .powCalib = {0x8C, 0x8C, 0x8C}, - }, - (Preset){ - .band = - { - .bounds = {11800000, 13499999}, - .name = "Air", - .step = STEP_12_5kHz, - .modulation = MOD_AM, - .bw = BK4819_FILTER_BW_NARROW, - .gainIndex = 16, - .squelch = 3, - .squelchType = SQUELCH_RSSI_NOISE_GLITCH, - }, - .allowTx = false, - .lastUsedFreq = 13170000, - .powCalib = {0x8C, 0x8C, 0x8C}, - }, - (Preset){ - .band = - { - .bounds = {13500000, 14399999}, - .name = "135-144", - .step = STEP_12_5kHz, - .modulation = MOD_FM, - .bw = BK4819_FILTER_BW_NARROW, - .gainIndex = 16, - .squelch = 3, - .squelchType = SQUELCH_RSSI_NOISE_GLITCH, - }, - .allowTx = false, - .lastUsedFreq = 13510000, - .powCalib = {0x8C, 0x8C, 0x8C}, - }, - (Preset){ - .band = - { - .bounds = {14400000, 14799999}, - .name = "2m HAM", - .step = STEP_25_0kHz, - .modulation = MOD_FM, - .bw = BK4819_FILTER_BW_WIDE, - .gainIndex = 16, - .squelch = 3, - .squelchType = SQUELCH_RSSI_NOISE_GLITCH, - }, - .allowTx = false, - .lastUsedFreq = 14550000, - .powCalib = {0x8C, 0x8C, 0x8C}, - }, - (Preset){ - .band = - { - .bounds = {14800000, 17399999}, - .name = "148-174", - .step = STEP_25_0kHz, - .modulation = MOD_FM, - .bw = BK4819_FILTER_BW_WIDE, - .gainIndex = 16, - .squelch = 3, - .squelchType = SQUELCH_RSSI_NOISE_GLITCH, - }, - .allowTx = false, - .lastUsedFreq = 15300000, - .powCalib = {0x8C, 0x8C, 0x8C}, - }, - (Preset){ - .band = - { - .bounds = {17400000, 22999999}, - .name = "174-230", - .step = STEP_25_0kHz, - .modulation = MOD_FM, - .bw = BK4819_FILTER_BW_WIDE, - .gainIndex = 16, - .squelch = 3, - .squelchType = SQUELCH_RSSI_NOISE_GLITCH, - }, - .allowTx = false, - .lastUsedFreq = 20575000, - .powCalib = {0x8C, 0x8C, 0x8C}, - }, - (Preset){ - .band = - { - .bounds = {23000000, 31999999}, - .name = "230-320", - .step = STEP_25_0kHz, - .modulation = MOD_FM, - .bw = BK4819_FILTER_BW_WIDE, - .gainIndex = 16, - .squelch = 3, - .squelchType = SQUELCH_RSSI_NOISE_GLITCH, - }, - .allowTx = false, - .lastUsedFreq = 25355000, - .powCalib = {0x8C, 0x8C, 0x8C}, - }, - (Preset){ - .band = - { - .bounds = {32000000, 39999999}, - .name = "320-400", - .step = STEP_25_0kHz, - .modulation = MOD_FM, - .bw = BK4819_FILTER_BW_WIDE, - .gainIndex = 16, - .squelch = 3, - .squelchType = SQUELCH_RSSI_NOISE_GLITCH, - }, - .allowTx = false, - .lastUsedFreq = 33605000, - .powCalib = {0x82, 0x82, 0x82}, - }, - (Preset){ - .band = - { - .bounds = {40000000, 43307499}, - .name = "400-433", - .step = STEP_25_0kHz, - .modulation = MOD_FM, - .bw = BK4819_FILTER_BW_WIDE, - .gainIndex = 16, - .squelch = 3, - .squelchType = SQUELCH_RSSI_NOISE_GLITCH, - }, - .allowTx = false, - .lastUsedFreq = 42230000, - .powCalib = {0x8C, 0x8C, 0x8C}, - }, - (Preset){ - .band = - { - .bounds = {43307500, 43479999}, - .name = "LPD", - .step = STEP_25_0kHz, - .modulation = MOD_FM, - .bw = BK4819_FILTER_BW_WIDE, - .gainIndex = 16, - .squelch = 3, - .squelchType = SQUELCH_RSSI_NOISE_GLITCH, - }, - .allowTx = true, - .lastUsedFreq = 43325000, - .powCalib = {0x8C, 0x8C, 0x8C}, - }, - (Preset){ - .band = - { - .bounds = {43480000, 44600624}, - .name = "435-446", - .step = STEP_25_0kHz, - .modulation = MOD_FM, - .bw = BK4819_FILTER_BW_WIDE, - .gainIndex = 16, - .squelch = 3, - .squelchType = SQUELCH_RSSI_NOISE_GLITCH, - }, - .allowTx = false, - .lastUsedFreq = 43700000, - .powCalib = {0x8C, 0x8C, 0x8C}, - }, - (Preset){ - .band = - { - .bounds = {44600625, 44619375}, - .name = "PMR", - .step = STEP_6_25kHz, - .modulation = MOD_FM, - .bw = BK4819_FILTER_BW_WIDE, - .gainIndex = 16, - .squelch = 3, - .squelchType = SQUELCH_RSSI_NOISE_GLITCH, - }, - .allowTx = true, - .lastUsedFreq = 44609375, - .powCalib = {0x8C, 0x8C, 0x8C}, - }, - (Preset){ - .band = - { - .bounds = {44620000, 46256249}, - .name = "446-462", - .step = STEP_25_0kHz, - .modulation = MOD_FM, - .bw = BK4819_FILTER_BW_WIDE, - .gainIndex = 16, - .squelch = 3, - .squelchType = SQUELCH_RSSI_NOISE_GLITCH, - }, - .allowTx = false, - .lastUsedFreq = 46060000, - .powCalib = {0x8C, 0x8C, 0x8C}, - }, - (Preset){ - .band = - { - .bounds = {46256250, 46273749}, - .name = "FRS/G462", - .step = STEP_12_5kHz, - .modulation = MOD_FM, - .bw = BK4819_FILTER_BW_WIDE, - .gainIndex = 16, - .squelch = 3, - .squelchType = SQUELCH_RSSI_NOISE_GLITCH, - }, - .allowTx = false, - .lastUsedFreq = 46256250, - .powCalib = {0x8C, 0x8C, 0x8C}, - }, - (Preset){ - .band = - { - .bounds = {46273750, 46756249}, - .name = "462-467", - .step = STEP_12_5kHz, - .modulation = MOD_FM, - .bw = BK4819_FILTER_BW_WIDE, - .gainIndex = 16, - .squelch = 3, - .squelchType = SQUELCH_RSSI_NOISE_GLITCH, - }, - .allowTx = false, - .lastUsedFreq = 46302500, - .powCalib = {0x8C, 0x8C, 0x8C}, - }, - (Preset){ - .band = - { - .bounds = {46756250, 46774999}, - .name = "FRS/G467", - .step = STEP_12_5kHz, - .modulation = MOD_FM, - .bw = BK4819_FILTER_BW_WIDE, - .gainIndex = 16, - .squelch = 3, - .squelchType = SQUELCH_RSSI_NOISE_GLITCH, - }, - .allowTx = false, - .lastUsedFreq = 46756250, - .powCalib = {0x8C, 0x8C, 0x8C}, - }, - (Preset){ - .band = - { - .bounds = {46775000, 46999999}, - .name = "468-470", - .step = STEP_25_0kHz, - .modulation = MOD_FM, - .bw = BK4819_FILTER_BW_WIDE, - .gainIndex = 16, - .squelch = 3, - .squelchType = SQUELCH_RSSI_NOISE_GLITCH, - }, - .allowTx = false, - .lastUsedFreq = 46980000, - .powCalib = {0x8C, 0x8C, 0x8C}, - }, - (Preset){ - .band = - { - .bounds = {47000000, 62000000}, - .name = "470-620", - .step = STEP_25_0kHz, - .modulation = MOD_FM, - .bw = BK4819_FILTER_BW_WIDE, - .gainIndex = 16, - .squelch = 3, - .squelchType = SQUELCH_RSSI_NOISE_GLITCH, - }, - .allowTx = false, - .lastUsedFreq = 50975000, - .powCalib = {0x8C, 0x8C, 0x8C}, - }, - (Preset){ - .band = - { - .bounds = {84000000, 86299999}, - .name = "840-863", - .step = STEP_25_0kHz, - .modulation = MOD_FM, - .bw = BK4819_FILTER_BW_WIDE, - .gainIndex = 16, - .squelch = 3, - .squelchType = SQUELCH_RSSI_NOISE_GLITCH, - }, - .allowTx = false, - .lastUsedFreq = 85500000, - .powCalib = {0x8C, 0x8C, 0x8C}, - }, - (Preset){ - .band = - { - .bounds = {86300000, 86999999}, - .name = "LORA", - .step = STEP_125_0kHz, - .modulation = MOD_FM, - .bw = BK4819_FILTER_BW_WIDE, - .gainIndex = 16, - .squelch = 3, - .squelchType = SQUELCH_RSSI_NOISE_GLITCH, - }, - .allowTx = false, - .lastUsedFreq = 86400000, - .powCalib = {0x8C, 0x8C, 0x8C}, - }, - (Preset){ - .band = - { - .bounds = {87000000, 88999999}, - .name = "870-890", - .step = STEP_25_0kHz, - .modulation = MOD_FM, - .bw = BK4819_FILTER_BW_WIDE, - .gainIndex = 16, - .squelch = 3, - .squelchType = SQUELCH_RSSI_NOISE_GLITCH, - }, - .allowTx = false, - .lastUsedFreq = 87000000, - .powCalib = {0x8C, 0x8C, 0x8C}, - }, - (Preset){ - .band = - { - .bounds = {89000000, 95999999}, - .name = "GSM-900", - .step = STEP_200_0kHz, - .modulation = MOD_FM, - .bw = BK4819_FILTER_BW_WIDE, - .gainIndex = 16, - .squelch = 3, - .squelchType = SQUELCH_RSSI_NOISE_GLITCH, - }, - .allowTx = false, - .lastUsedFreq = 89000000, - .powCalib = {0x8C, 0x8C, 0x8C}, - }, - (Preset){ - .band = - { - .bounds = {96000000, 125999999}, - .name = "960-1260", - .step = STEP_25_0kHz, - .modulation = MOD_FM, - .bw = BK4819_FILTER_BW_WIDE, - .gainIndex = 16, - .squelch = 3, - .squelchType = SQUELCH_RSSI_NOISE_GLITCH, - }, - .allowTx = false, - .lastUsedFreq = 96000000, - .powCalib = {0x8C, 0x8C, 0x8C}, - }, - (Preset){ - .band = - { - .bounds = {126000000, 129999999}, - .name = "23cm HAM", - .step = STEP_25_0kHz, - .modulation = MOD_FM, - .bw = BK4819_FILTER_BW_WIDE, - .gainIndex = 16, - .squelch = 3, - .squelchType = SQUELCH_RSSI_NOISE_GLITCH, - }, - .allowTx = false, - .lastUsedFreq = 129750000, - .powCalib = {0x8C, 0x8C, 0x8C}, - }, - (Preset){ - .band = - { - .bounds = {126000000, 134000000}, - .name = "1.3-1.34", - .step = STEP_25_0kHz, - .modulation = MOD_FM, - .bw = BK4819_FILTER_BW_WIDE, - .gainIndex = 16, - .squelch = 3, - .squelchType = SQUELCH_RSSI_NOISE_GLITCH, - }, - .allowTx = false, - .lastUsedFreq = 126000000, - .powCalib = {0x8C, 0x8C, 0x8C}, - }, -}; -// char (*__defpres)[sizeof(defaultPresets)/sizeof(Preset)] = 1; - void RESET_Init(void) { eepromType = gSettings.eepromType; presetsWrote = 0; @@ -508,6 +39,8 @@ void RESET_Init(void) { channelsWrote = 0; settingsWrote = false; memset(buf, 0xFF, sizeof(buf)); + channelsMax = CHANNELS_GetCountMax(); + bytesMax = SETTINGS_GetEEPROMSize(); } void RESET_Update(void) { @@ -522,7 +55,7 @@ void RESET_Update(void) { .backlight = BL_TIME_VALUES[3], .txTime = 0, .micGain = 15, - .currentScanlist = 1, + .currentScanlist = 15, .upconverter = UPCONVERTER_OFF, .roger = 0, .scanmode = 0, @@ -563,16 +96,11 @@ void RESET_Update(void) { PRESETS_SavePreset(presetsWrote, &defaultPresets[presetsWrote]); presetsWrote++; bytesWrote += PRESET_SIZE; - } else if (channelsWrote < CHANNELS_GetCountMax()) { - CH ch = { - .name = {0}, - .memoryBanks = 0, - }; - CHANNELS_Save(channelsWrote, &ch); + } else if (channelsWrote < channelsMax) { + CHANNELS_Delete(channelsWrote); channelsWrote++; - bytesWrote += sizeof(CH); + bytesWrote += CH_SIZE; } else { - SETTINGS_Save(); NVIC_SystemReset(); } @@ -580,15 +108,16 @@ void RESET_Update(void) { } void RESET_Render(void) { - uint8_t progressX = - ConvertDomain(bytesWrote, 0, SETTINGS_GetEEPROMSize(), 1, LCD_WIDTH - 2); + uint8_t progressX = ConvertDomain(bytesWrote, 0, bytesMax, 1, LCD_WIDTH - 2); uint8_t POS_Y = LCD_HEIGHT / 2; UI_ClearScreen(); DrawRect(0, POS_Y, LCD_WIDTH, 10, C_FILL); FillRect(1, POS_Y, progressX, 10, C_FILL); + PrintMedium(0, 16, "%u/%u", channelsWrote, channelsMax); + PrintMedium(0, 24, "%lu", bytesMax); PrintMediumEx(LCD_XCENTER, POS_Y + 8, POS_C, C_INVERT, "%u%", - bytesWrote * 100 / SETTINGS_GetEEPROMSize()); + bytesWrote * 100 / bytesMax); } bool RESET_key(KEY_Code_t k, bool p, bool h) { return true; } diff --git a/src/apps/savech.c b/src/apps/savech.c index ae0d4f9..ad017da 100644 --- a/src/apps/savech.c +++ b/src/apps/savech.c @@ -13,22 +13,56 @@ static uint16_t currentChannelIndex = 0; static uint16_t chCount = 0; static char tempName[9] = {0}; +static uint16_t chNum = 0; +static CH ch; -static void getChannelName(uint16_t i, char *name) { - CH ch; - CHANNELS_Load(i, &ch); - if (IsReadable(ch.name)) { - strncpy(name, ch.name, 9); +static void getChItem(uint16_t i, uint16_t index, bool isCurrent) { + CH _ch; + const uint8_t y = MENU_Y + i * MENU_ITEM_H; + CHANNELS_Load(index, &_ch); + if (isCurrent) { + FillRect(0, y, LCD_WIDTH - 3, MENU_ITEM_H, C_FILL); + } + if (IsReadable(_ch.name)) { + PrintMediumEx(8, y + 8, POS_L, C_INVERT, "%s", _ch.name); + } else { + PrintMediumEx(8, y + 8, POS_L, C_INVERT, "CH-%u", index + 1); + return; + } + char scanlistsStr[9] = ""; + for (uint8_t i = 0; i < 8; ++i) { + scanlistsStr[i] = _ch.memoryBanks & (1 << i) ? '1' + i : '-'; + } + PrintSmallEx(LCD_WIDTH - 1, y + 8, POS_R, C_INVERT, "%s", scanlistsStr); +} + +static void getScanlistItem(uint16_t i, uint16_t index, bool isCurrent) { + uint16_t chNum = gScanlist[index]; + CH _ch; + const uint8_t y = MENU_Y + i * MENU_ITEM_H; + CHANNELS_Load(chNum, &_ch); + if (isCurrent) { + FillRect(0, y, LCD_WIDTH - 3, MENU_ITEM_H, C_FILL); + } + if (IsReadable(_ch.name)) { + PrintMediumEx(8, y + 8, POS_L, C_INVERT, "%s", _ch.name); } else { - sprintf(name, "CH-%u", i + 1); + PrintMediumEx(8, y + 8, POS_L, C_INVERT, "CH-%u", index + 1); + return; + } + char scanlistsStr[9] = ""; + for (uint8_t i = 0; i < 8; ++i) { + scanlistsStr[i] = _ch.memoryBanks & (1 << i) ? '1' + i : '-'; } + PrintSmallEx(LCD_WIDTH - 1 - 3, y + 8, POS_R, C_INVERT, "%s", scanlistsStr); } static void saveNamed(void) { - CH ch; - VFO2CH(radio, gCurrentPreset, &ch); - strncpy(ch.name, tempName, 9); - CHANNELS_Save(currentChannelIndex, &ch); + CH _ch; + VFO2CH(radio, gCurrentPreset, &_ch); + _ch.memoryBanks = 1 << gSettings.currentScanlist; + strncpy(_ch.name, tempName, 9); + CHANNELS_Save(currentChannelIndex, &_ch); for (uint8_t i = 0; i < 2; ++i) { if (gVFO[i].channel >= 0 && gVFO[i].channel == currentChannelIndex) { RADIO_VfoLoadCH(i); @@ -36,8 +70,18 @@ static void saveNamed(void) { } } } +static void saveRenamed() { CHANNELS_Save(chNum, &ch); } + +void SAVECH_init(void) { + gRedrawScreen = true; + CHANNELS_LoadScanlist(gSettings.currentScanlist); + if (gSettings.currentScanlist == 15) { + chCount = CHANNELS_GetCountMax(); + } else { + chCount = gScanlistSize; + } +} -void SAVECH_init(void) { chCount = CHANNELS_GetCountMax(); } void SAVECH_update(void) {} static void save(void) { @@ -46,6 +90,7 @@ static void save(void) { radio->rx.f % 100000); gTextInputSize = 9; gTextInputCallback = saveNamed; + APPS_run(APP_TEXTINPUT); } static void setMenuIndexAndRun(uint16_t v) { @@ -53,52 +98,114 @@ static void setMenuIndexAndRun(uint16_t v) { save(); } +static void toggleScanlist(uint8_t n) { + CH _ch; + CHANNELS_Load(gScanlist[currentChannelIndex], &_ch); + _ch.memoryBanks ^= 1 << n; + CHANNELS_Save(gScanlist[currentChannelIndex], &_ch); +} + bool SAVECH_key(KEY_Code_t key, bool bKeyPressed, bool bKeyHeld) { + chNum = gScanlist[currentChannelIndex]; if (!bKeyPressed && !bKeyHeld) { - if (!gIsNumNavInput && key >= KEY_0 && key <= KEY_9) { + if (!gIsNumNavInput && key == KEY_STAR) { NUMNAV_Init(currentChannelIndex + 1, 1, chCount); gNumNavCallback = setMenuIndexAndRun; + return true; } if (gIsNumNavInput) { currentChannelIndex = NUMNAV_Input(key) - 1; return true; } } - CH ch; - switch (key) { - case KEY_UP: - IncDec16(¤tChannelIndex, 0, chCount, -1); - return true; - case KEY_DOWN: - IncDec16(¤tChannelIndex, 0, chCount, 1); - return true; - case KEY_MENU: - save(); - APPS_run(APP_TEXTINPUT); - return true; - case KEY_EXIT: - APPS_exit(); - return true; - case KEY_0: - CHANNELS_Delete(currentChannelIndex); - return true; - case KEY_PTT: - CHANNELS_Load(currentChannelIndex, &ch); - RADIO_TuneToSave(ch.rx.f); - APPS_run(APP_STILL); - return true; - default: - break; + if (bKeyPressed || (!bKeyPressed && !bKeyHeld)) { + switch (key) { + case KEY_UP: + IncDec16(¤tChannelIndex, 0, chCount, -1); + return true; + case KEY_DOWN: + IncDec16(¤tChannelIndex, 0, chCount, 1); + return true; + default: + break; + } + } + if (bKeyHeld && bKeyPressed && !gRepeatHeld) { + switch (key) { + case KEY_1: + case KEY_2: + case KEY_3: + case KEY_4: + case KEY_5: + case KEY_6: + case KEY_7: + case KEY_8: + CHANNELS_LoadScanlist(key - KEY_1); + chCount = gScanlistSize; + currentChannelIndex = 0; + return true; + case KEY_0: + CHANNELS_LoadScanlist(15); + chCount = CHANNELS_GetCountMax(); + currentChannelIndex = 0; + return true; + default: + break; + } + } + CH _ch; + if (!bKeyPressed && !bKeyHeld) { + switch (key) { + case KEY_1: + case KEY_2: + case KEY_3: + case KEY_4: + case KEY_5: + case KEY_6: + case KEY_7: + case KEY_8: + toggleScanlist(key - KEY_1); + return true; + case KEY_MENU: + save(); + return true; + case KEY_0: + CHANNELS_Delete(currentChannelIndex); + return true; + case KEY_PTT: + CHANNELS_Load(currentChannelIndex, &_ch); + RADIO_TuneToSave(_ch.rx.f); + APPS_run(APP_STILL); + return true; + case KEY_F: + CHANNELS_Load(chNum, &_ch); + gTextinputText = _ch.name; + gTextInputSize = 9; + gTextInputCallback = saveRenamed; + APPS_run(APP_TEXTINPUT); + return true; + case KEY_EXIT: + APPS_exit(); + return true; + default: + break; + } } return false; } void SAVECH_render(void) { UI_ClearScreen(); + if (gSettings.currentScanlist == 15) { + STATUSLINE_SetText(apps[APP_SAVECH].name); + UI_ShowMenuEx(getChItem, chCount, currentChannelIndex, + MENU_LINES_TO_SHOW + 1); + } else { + STATUSLINE_SetText("Current scanlist: %u", gSettings.currentScanlist + 1); + UI_ShowMenuEx(getScanlistItem, chCount, currentChannelIndex, + MENU_LINES_TO_SHOW + 1); + } if (gIsNumNavInput) { STATUSLINE_SetText("Select: %s", gNumNavInput); - } else { - STATUSLINE_SetText(apps[APP_SAVECH].name); } - UI_ShowMenu(getChannelName, chCount, currentChannelIndex); } diff --git a/src/apps/scanlists.c b/src/apps/scanlists.c deleted file mode 100644 index b534e43..0000000 --- a/src/apps/scanlists.c +++ /dev/null @@ -1,160 +0,0 @@ -#include "scanlists.h" -#include "../external/printf/printf.h" -#include "../helper/channels.h" -#include "../helper/measurements.h" -#include "../ui/graphics.h" -#include "../ui/menu.h" -#include "../ui/statusline.h" -#include "apps.h" -#include "textinput.h" -#include -#include - -static uint16_t count = 0; - -static uint16_t currentIndex = 0; -CH ch; -uint16_t chNum = 0; - -static void getChItem(uint16_t i, uint16_t index, bool isCurrent) { - CH ch; - const uint8_t y = MENU_Y + i * MENU_ITEM_H; - CHANNELS_Load(index, &ch); - if (isCurrent) { - FillRect(0, y, LCD_WIDTH - 3, MENU_ITEM_H, C_FILL); - } - if (IsReadable(ch.name)) { - PrintMediumEx(8, y + 8, POS_L, C_INVERT, "%s", ch.name); - } else { - PrintMediumEx(8, y + 8, POS_L, C_INVERT, "CH-%u", index + 1); - return; - } - char scanlistsStr[9] = ""; - for (uint8_t i = 0; i < 8; ++i) { - scanlistsStr[i] = ch.memoryBanks & (1 << i) ? '1' + i : '-'; - } - PrintSmallEx(LCD_WIDTH - 1, y + 8, POS_R, C_INVERT, "%s", scanlistsStr); -} - -static void getScanlistItem(uint16_t i, uint16_t index, bool isCurrent) { - uint16_t chNum = gScanlist[index]; - CH ch; - const uint8_t y = MENU_Y + i * MENU_ITEM_H; - CHANNELS_Load(chNum, &ch); - if (isCurrent) { - FillRect(0, y, LCD_WIDTH - 3, MENU_ITEM_H, C_FILL); - } - if (IsReadable(ch.name)) { - PrintMediumEx(8, y + 8, POS_L, C_INVERT, "%s", ch.name); - } else { - PrintMediumEx(8, y + 8, POS_L, C_INVERT, "CH-%u", index + 1); - return; - } - char scanlistsStr[9] = ""; - for (uint8_t i = 0; i < 8; ++i) { - scanlistsStr[i] = ch.memoryBanks & (1 << i) ? '1' + i : '-'; - } - PrintSmallEx(LCD_WIDTH - 1 - 3, y + 8, POS_R, C_INVERT, "%s", scanlistsStr); -} - -static void toggleScanlist(uint8_t n) { - CH ch; - CHANNELS_Load(gScanlist[currentIndex], &ch); - ch.memoryBanks ^= 1 << n; - CHANNELS_Save(gScanlist[currentIndex], &ch); -} - -void SCANLISTS_init() { - gRedrawScreen = true; - CHANNELS_LoadScanlist(gSettings.currentScanlist); - count = gScanlistSize; -} - -void SCANLISTS_update() {} - -static void saveRenamed() { CHANNELS_Save(chNum, &ch); } - -bool SCANLISTS_key(KEY_Code_t key, bool bKeyPressed, bool bKeyHeld) { - chNum = gScanlist[currentIndex]; - if (bKeyPressed || (!bKeyPressed && !bKeyHeld)) { - switch (key) { - case KEY_UP: - IncDec16(¤tIndex, 0, count, -1); - return true; - case KEY_DOWN: - IncDec16(¤tIndex, 0, count, 1); - return true; - default: - break; - } - } - if (bKeyHeld && bKeyPressed && !gRepeatHeld) { - switch (key) { - case KEY_1: - case KEY_2: - case KEY_3: - case KEY_4: - case KEY_5: - case KEY_6: - case KEY_7: - case KEY_8: - CHANNELS_LoadScanlist(key - KEY_1); - count = gScanlistSize; - currentIndex = 0; - return true; - case KEY_0: - CHANNELS_LoadScanlist(15); - count = gScanlistSize; - currentIndex = 0; - return true; - case KEY_UP: - IncDec16(¤tIndex, 0, count, -1); - return true; - case KEY_DOWN: - IncDec16(¤tIndex, 0, count, 1); - return true; - default: - break; - } - } - if (!bKeyPressed && !bKeyHeld) { - switch (key) { - case KEY_1: - case KEY_2: - case KEY_3: - case KEY_4: - case KEY_5: - case KEY_6: - case KEY_7: - case KEY_8: - toggleScanlist(key - KEY_1); - return true; - case KEY_EXIT: - APPS_exit(); - return true; - case KEY_F: - CHANNELS_Load(chNum, &ch); - gTextinputText = ch.name; - gTextInputSize = 9; - gTextInputCallback = saveRenamed; - APPS_run(APP_TEXTINPUT); - - return true; - default: - return false; - } - } - - return false; -} - -void SCANLISTS_render() { - UI_ClearScreen(); - if (gSettings.currentScanlist == 15) { - STATUSLINE_SetText("CH scanlists"); - UI_ShowMenuEx(getChItem, count, currentIndex, MENU_LINES_TO_SHOW + 1); - } else { - STATUSLINE_SetText("CH scanlist #%u", gSettings.currentScanlist + 1); - UI_ShowMenuEx(getScanlistItem, count, currentIndex, MENU_LINES_TO_SHOW + 1); - } -} diff --git a/src/apps/scanlists.h b/src/apps/scanlists.h deleted file mode 100644 index c5ed112..0000000 --- a/src/apps/scanlists.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef SCANLISTS_H -#define SCANLISTS_H - - -#include "../driver/keyboard.h" -#include -#include - -void SCANLISTS_init(); -void SCANLISTS_update(); -bool SCANLISTS_key(KEY_Code_t key, bool bKeyPressed, bool bKeyHeld); -void SCANLISTS_render(); - - -#endif /* end of include guard: SCANLISTS_H */ diff --git a/src/apps/settings.c b/src/apps/settings.c index 7aab28f..a9b90b1 100644 --- a/src/apps/settings.c +++ b/src/apps/settings.c @@ -47,10 +47,10 @@ static bool isSubMenu = false; static char Output[16]; -const char *fltBound[] = {"240MHz", "280MHz"}; +static const char *fltBound[] = {"240MHz", "280MHz"}; -const uint16_t BAT_CAL_MIN = 1900; -const uint16_t BAT_CAL_MAX = 2155; +static const uint16_t BAT_CAL_MIN = 1900; +// static const uint16_t BAT_CAL_MAX = 2155; static const MenuItem menu[] = { {"Upconverter", M_UPCONVERTER, ARRAY_SIZE(upConverterFreqNames)}, @@ -382,8 +382,6 @@ static void setInitialSubmenuIndex(void) { void SETTINGS_init(void) { gRedrawScreen = true; } -void SETTINGS_update(void) {} - static void setMenuIndexAndRun(uint16_t v) { menuIndex = v - 1; setInitialSubmenuIndex(); diff --git a/src/apps/settings.h b/src/apps/settings.h index 0e3ae36..8dfae70 100644 --- a/src/apps/settings.h +++ b/src/apps/settings.h @@ -6,7 +6,6 @@ #include void SETTINGS_init(); -void SETTINGS_update(); bool SETTINGS_key(KEY_Code_t key, bool bKeyPressed, bool bKeyHeld); void SETTINGS_render(); diff --git a/src/apps/si.c b/src/apps/si.c new file mode 100644 index 0000000..80f7585 --- /dev/null +++ b/src/apps/si.c @@ -0,0 +1,428 @@ +#include "si.h" +#include "../driver/bk4819.h" +#include "../driver/si473x.h" +#include "../helper/rds.h" +#include "../misc.h" +#include "../scheduler.h" +#include "../svc.h" +#include "../ui/graphics.h" +#include "apps.h" +#include "finput.h" +#include + +typedef enum { + FM_BT, + MW_BT, + SW_BT, + LW_BT, +} BandType; + +static const char SI47XX_BW_NAMES[5][8] = { + "6 kHz", "4 kHz", "3 kHz", "2 kHz", "1 kHz", +}; + +static const char SI47XX_SSB_BW_NAMES[6][8] = { + "1.2 kHz", "2.2 kHz", "3 kHz", "4 kHz", "0.5 kHz", "1 kHz", +}; + +static const char SI47XX_MODE_NAMES[5][4] = { + "FM", "AM", "LSB", "USB", "CW", +}; + +static SI47XX_FilterBW bw = SI47XX_BW_6_kHz; +static SI47XX_SsbFilterBW ssbBw = SI47XX_SSB_BW_3_kHz; +static int8_t currentBandIndex = -1; + +typedef struct // Band data +{ + const char *bandName; // Bandname + BandType bandType; // Band type (FM, MW or SW) + SI47XX_MODE prefmod; // Pref. modulation + uint16_t minimumFreq; // Minimum frequency of the band + uint16_t maximumFreq; // maximum frequency of the band + uint16_t currentFreq; // Default frequency or current frequency + uint8_t currentStep; // Default step (increment and decrement) + int lastBFO; // Last BFO per band + int lastmanuBFO; // Last Manual BFO per band using X-Tal + +} SIBand; + +SIBand bands[] = { + {"LW", LW_BT, SI47XX_AM, 148, 283, 198, 9, 0, 0}, // LW 1 + {"LW", LW_BT, SI47XX_AM, 100, 514, 198, 9, 0, 0}, // LW 1 + {"MW Bcast", MW_BT, SI47XX_AM, 526, 1606, 1395, 9, 0, 0}, // MW 2 + {"MW", MW_BT, SI47XX_AM, 514, 1800, 1395, 9, 0, 0}, // MW 2 + {"BACON Ham", LW_BT, SI47XX_AM, 280, 470, 284, 1, 0, 0}, // Ham 800M 3 + {"630M Ham", SW_BT, SI47XX_LSB, 470, 480, 475, 1, 0, 0}, // Ham 630M 4 + {"160M Ham", SW_BT, SI47XX_LSB, 1800, 2000, 1850, 1, 0, 0}, // Ham 160M 5 + {"120M Bcast", SW_BT, SI47XX_AM, 2300, 2495, 2400, 5, 0, 0}, // 120M 6 + {"120M", SW_BT, SI47XX_AM, 2000, 3200, 2400, 5, 0, 0}, // 120M 6 + {"90M Bcast", SW_BT, SI47XX_AM, 3200, 3400, 3300, 5, 0, 0}, // 90M 7 + {"90M", SW_BT, SI47XX_AM, 3200, 3500, 3300, 5, 0, 0}, // 90M 7 + {"80M Ham", SW_BT, SI47XX_LSB, 3500, 3900, 3630, 1, 0, 0}, // Ham 80M 8 + {"75M Bcast", SW_BT, SI47XX_AM, 3900, 4000, 3950, 5, 0, 0}, // 75M 9 + {"75M Bacst", SW_BT, SI47XX_AM, 4750, 5100, 3950, 5, 0, 0}, // 75M 9 + {"75M", SW_BT, SI47XX_AM, 3900, 5300, 3950, 5, 0, 0}, // 75M 9 + {"60M", SW_BT, SI47XX_USB, 5300, 5900, 5375, 1, 0, 0}, // Ham 60M 10 + {"49M Bcast", SW_BT, SI47XX_AM, 5850, 6350, 6000, 5, 0, 0}, // 49M 11 + {"49M", SW_BT, SI47XX_AM, 5900, 7000, 6000, 5, 0, 0}, // 49M 11 + {"41M Bcast", SW_BT, SI47XX_AM, 7200, 7500, 7210, 5, 0, 0}, // 41M 13 + {"40M Ham", SW_BT, SI47XX_LSB, 7000, 7500, 7074, 1, 0, 0}, // Ham 40M 12 + {"41M", SW_BT, SI47XX_AM, 7500, 9000, 7210, 5, 0, 0}, // 41M 13 + {"31M Bcast", SW_BT, SI47XX_AM, 9400, 9990, 9600, 5, 0, 0}, // 31M 14 + {"31M", SW_BT, SI47XX_AM, 9000, 10000, 9600, 5, 0, 0}, // 31M 14 + {"30M Ham", SW_BT, SI47XX_USB, 10000, 10200, 10099, 1, 0, + 0}, // Ham 30M 15 + {"25M Bcast", SW_BT, SI47XX_AM, 11600, 12100, 11700, 5, 0, + 0}, // 25M 16 + {"25M", SW_BT, SI47XX_AM, 10200, 13500, 11700, 5, 0, 0}, // 25M 16 + {"22M Bcast", SW_BT, SI47XX_AM, 13500, 13870, 13700, 5, 0, + 0}, // 22M 17 + {"22M", SW_BT, SI47XX_AM, 13500, 14000, 13700, 5, 0, 0}, // 22M 17 + {"20M Ham", SW_BT, SI47XX_USB, 14000, 14500, 14074, 1, 0, + 0}, // Ham 20M 18 + {"19M Bcast", SW_BT, SI47XX_AM, 15100, 15800, 15700, 5, 0, + 0}, // 19M 19 + {"17M Bcast", SW_BT, SI47XX_AM, 17480, 18050, 17600, 5, 0, + 0}, // 17M 20 + {"19M", SW_BT, SI47XX_AM, 14500, 17500, 15700, 5, 0, 0}, // 19M 19 + {"17M", SW_BT, SI47XX_AM, 17500, 18000, 17600, 5, 0, 0}, // 17M 20 + {"16M Ham", SW_BT, SI47XX_USB, 18000, 18500, 18100, 1, 0, + 0}, // Ham 16M 21 + {"15M Bcast", SW_BT, SI47XX_AM, 18900, 19020, 18950, 5, 0, + 0}, // 15M 22 + {"15M", SW_BT, SI47XX_AM, 18500, 21000, 18950, 5, 0, 0}, // 15M 22 + {"14M Ham", SW_BT, SI47XX_USB, 21000, 21450, 21074, 1, 0, + 0}, // Ham 14M 23 + {"14M Bcast", SW_BT, SI47XX_USB, 21450, 21850, 21074, 1, 0, + 0}, // Ham 14M 23 + {"13M", SW_BT, SI47XX_AM, 21500, 24000, 21500, 5, 0, 0}, // 13M 24 + {"12M Ham", SW_BT, SI47XX_USB, 24000, 25500, 24940, 1, 0, + 0}, // Ham 12M 25 + {"11M Bcast", SW_BT, SI47XX_AM, 25600, 26100, 25800, 5, 0, + 0}, // 11M 26 + {"11M", SW_BT, SI47XX_AM, 25500, 26100, 25800, 5, 0, 0}, // 11M 26 + {"CB", SW_BT, SI47XX_AM, 26100, 28000, 27200, 1, 0, 0}, // CB band 27 + {"10M Ham", SW_BT, SI47XX_USB, 28000, 29750, 28500, 1, 0, + 0}, // Ham 10M 28 + {"10M", SW_BT, SI47XX_USB, 28000, 30000, 28500, 1, 0, 0}, // Ham 10M 28 + {"SW", SW_BT, SI47XX_AM, 100, 30000, 15500, 5, 0, 0} // Whole SW 29 +}; +static const uint8_t BANDS_COUNT = ARRAY_SIZE(bands); + +static int8_t getCurrentBandIndex() { + for (int8_t i = 0; i < BANDS_COUNT; ++i) { + if (siCurrentFreq >= bands[i].minimumFreq && + siCurrentFreq <= bands[i].maximumFreq) { + return i; + } + } + return -1; +} + +static uint8_t att = 0; +static uint16_t divider = 1000; +static uint16_t step = 10; +static uint32_t lastUpdate = 0; +static uint32_t lastRdsUpdate = 0; +static uint32_t lastSeekUpdate = 0; +static DateTime dt; +static int16_t bfo = 0; +static bool showSNR = false; + +static void tune(uint32_t f) { + f /= divider; + if (si4732mode == SI47XX_FM) { + f -= f % 5; + } + SI47XX_ClearRDS(); + SI47XX_SetFreq(f); + currentBandIndex = getCurrentBandIndex(); +} + +void SI_init() { + SVC_Toggle(SVC_LISTEN, false, 0); + BK4819_Idle(); + SI47XX_PowerUp(); + + SI47XX_SetAutomaticGainControl(1, att); +} + +static bool hasRDS = false; +static bool seeking = false; + +void SI_update() { + if (si4732mode == SI47XX_FM && Now() - lastRdsUpdate >= 1000) { + hasRDS = SI47XX_GetRDS(); + lastRdsUpdate = Now(); + if (hasRDS) { + gRedrawScreen = true; + } + } + if (Now() - lastUpdate >= 1000) { + if (showSNR) { + RSQ_GET(); + } + lastUpdate = Now(); + gRedrawScreen = true; + } + if (seeking && Now() - lastSeekUpdate >= 100) { + bool valid = false; + siCurrentFreq = SI47XX_getFrequency(&valid); + if (valid) { + seeking = false; + } + lastSeekUpdate = Now(); + gRedrawScreen = true; + } +} + +static uint32_t lastFreqChange = 0; + +static void resetBFO() { + if (bfo != 0) { + bfo = 0; + SI47XX_SetBFO(bfo); + } +} + +bool SI_key(KEY_Code_t key, bool bKeyPressed, bool bKeyHeld) { + // up-down keys + if (bKeyPressed || (!bKeyPressed && !bKeyHeld)) { + switch (key) { + case KEY_UP: + if (Now() - lastFreqChange > 250) { + lastFreqChange = Now(); + tune((siCurrentFreq + step) * divider); + resetBFO(); + } + return true; + case KEY_DOWN: + if (Now() - lastFreqChange > 250) { + lastFreqChange = Now(); + tune((siCurrentFreq - step) * divider); + resetBFO(); + } + return true; + case KEY_SIDE1: + if (SI47XX_IsSSB()) { + if (bfo < INT16_MAX - 10) { + bfo += 10; + } + SI47XX_SetBFO(bfo); + } + return true; + case KEY_SIDE2: + if (SI47XX_IsSSB()) { + if (bfo > INT16_MIN + 10) { + bfo -= 10; + } + SI47XX_SetBFO(bfo); + } + return true; + case KEY_2: + if (att < 37) { + att++; + SI47XX_SetAutomaticGainControl(1, att); + } + return true; + case KEY_8: + if (att > 0) { + att--; + SI47XX_SetAutomaticGainControl(att > 0, att); + } + return true; + default: + break; + } + } + + // long held + if (bKeyHeld && bKeyPressed && !gRepeatHeld) { + switch (key) { + case KEY_STAR: + if (SI47XX_IsSSB()) { + return false; + } + if (si4732mode == SI47XX_FM) { + SI47XX_SetSeekFmSpacing(step); + } else { + SI47XX_SetSeekAmSpacing(step); + } + SI47XX_Seek(1, 1); + seeking = true; + return true; + default: + break; + } + } + + // Simple keypress + if (!bKeyPressed && !bKeyHeld) { + switch (key) { + case KEY_1: + if (step < 1000) { + if (step == 1 || step == 10 || step == 100 || step == 1000) { + step *= 5; + } else { + step *= 2; + } + } + return true; + case KEY_7: + if (step > 1) { + if (step == 1 || step == 10 || step == 100 || step == 1000) { + step /= 2; + } else { + step /= 5; + } + } + return true; + case KEY_6: + if (SI47XX_IsSSB()) { + if (ssbBw == SI47XX_SSB_BW_1_0_kHz) { + ssbBw = SI47XX_SSB_BW_1_2_kHz; + } else { + ssbBw++; + } + SI47XX_SetSsbBandwidth(ssbBw); + } else { + if (bw == SI47XX_BW_1_kHz) { + bw = SI47XX_BW_6_kHz; + } else { + bw++; + } + SI47XX_SetBandwidth(bw, true); + } + return true; + case KEY_4: + showSNR = !showSNR; + return true; + case KEY_5: + gFInputCallback = tune; + APPS_run(APP_FINPUT); + return true; + case KEY_0: + divider = 100; + if (si4732mode == SI47XX_FM) { + SI47XX_SwitchMode(SI47XX_AM); + SI47XX_SetBandwidth(bw, true); + tune(720000); + step = 5; + } else if (si4732mode == SI47XX_AM) { + SI47XX_SwitchMode(SI47XX_LSB); + SI47XX_SetSsbBandwidth(ssbBw); + tune(711300); + step = 1; + } else { + divider = 1000; + SI47XX_SwitchMode(SI47XX_FM); + tune(10000000); + step = 10; + } + resetBFO(); + return true; + case KEY_F: + if (SI47XX_IsSSB()) { + SI47XX_SwitchMode(si4732mode == SI47XX_LSB ? SI47XX_USB : SI47XX_LSB); + tune(siCurrentFreq * divider); // to apply SSB + return true; + } + return false; + case KEY_STAR: + BK4819_Idle(); + return true; + case KEY_EXIT: + APPS_exit(); + return true; + case KEY_SIDE1: + if (currentBandIndex > 0) { + currentBandIndex--; + tune(bands[currentBandIndex].currentFreq * divider); + } + return true; + case KEY_SIDE2: + if (currentBandIndex < BANDS_COUNT - 1) { + currentBandIndex++; + tune(bands[currentBandIndex].currentFreq * divider); + } + return true; + default: + break; + } + } + return false; +} + +void SI_render() { + UI_ClearScreen(); + const uint8_t BASE = 38; + + uint32_t f = siCurrentFreq * divider; + uint16_t fp1 = f / 100000; + uint16_t fp2 = f / 100 % 1000; + + // PrintSmallEx(0, 12, POS_L, C_FILL, "SNR: %u dB", rsqStatus.resp.SNR); + + PrintBiggestDigitsEx(LCD_WIDTH - 22, BASE, POS_R, C_FILL, "%3u.%03u", fp1, + fp2); + PrintSmallEx(LCD_WIDTH - 1, BASE - 6, POS_R, C_FILL, "%s", + SI47XX_MODE_NAMES[si4732mode]); + if (SI47XX_IsSSB()) { + PrintSmallEx(LCD_WIDTH - 1, BASE, POS_R, C_FILL, "%d", bfo); + } + + if (si4732mode == SI47XX_FM) { + if (rds.RDSSignal) { + PrintSmallEx(LCD_WIDTH - 1, 12, POS_R, C_FILL, "RDS"); + } + + char genre[17]; + const char wd[8][3] = {"SU", "MO", "TU", "WE", "TH", "FR", "SA", "SU"}; + SI47XX_GetProgramType(genre); + PrintSmallEx(LCD_XCENTER, 14, POS_C, C_FILL, "%s", genre); + + if (SI47XX_GetLocalDateTime(&dt)) { + PrintSmallEx(LCD_XCENTER, 22, POS_C, C_FILL, + "%02u.%02u.%04u, %s %02u:%02u", dt.day, dt.month, dt.year, + wd[dt.wday], dt.hour, dt.minute); + } + + PrintSmall(0, LCD_HEIGHT - 8, "%s", rds.radioText); + } + + if (si4732mode == SI47XX_FM) { + PrintSmallEx(LCD_XCENTER, BASE + 6, POS_C, C_FILL, "STP %u ATT %u", step, + att); + } else if (SI47XX_IsSSB()) { + PrintSmallEx(LCD_XCENTER, BASE + 6, POS_C, C_FILL, "STP %u ATT %u BW %s", + step, att, SI47XX_SSB_BW_NAMES[ssbBw]); + } else { + PrintSmallEx(LCD_XCENTER, BASE + 6, POS_C, C_FILL, "STP %u ATT %u BW %s", + step, att, SI47XX_BW_NAMES[bw]); + } + + if (si4732mode != SI47XX_FM) { + if (currentBandIndex >= 0) { + PrintSmallEx(LCD_XCENTER, LCD_HEIGHT - 2, POS_C, C_FILL, "%s %d - %dkHz", + bands[currentBandIndex].bandName, + bands[currentBandIndex].minimumFreq, + bands[currentBandIndex].maximumFreq); + } + } + + if (showSNR) { + uint8_t rssi = rsqStatus.resp.RSSI; + if (rssi > 64) { + rssi = 64; + } + FillRect(0, 8, rssi * 2, 2, C_FILL); + PrintSmall(0, 15, "SNR %u", rsqStatus.resp.SNR); + } +} + +void SI_deinit() { + SI47XX_PowerDown(); + BK4819_RX_TurnOn(); + SVC_Toggle(SVC_LISTEN, true, 10); +} diff --git a/src/apps/si.h b/src/apps/si.h new file mode 100644 index 0000000..af611ba --- /dev/null +++ b/src/apps/si.h @@ -0,0 +1,14 @@ +#ifndef APP_SI_H +#define APP_SI_H + +#include "../driver/keyboard.h" +#include +#include + +void SI_init(); +void SI_update(); +bool SI_key(KEY_Code_t key, bool bKeyPressed, bool bKeyHeld); +void SI_render(); +void SI_deinit(); + +#endif /* end of include guard: APP_SI_H */ diff --git a/src/apps/spectrumreborn.c b/src/apps/spectrumreborn.c index b327906..84e062e 100644 --- a/src/apps/spectrumreborn.c +++ b/src/apps/spectrumreborn.c @@ -1,7 +1,6 @@ #include "spectrumreborn.h" #include "../dcs.h" #include "../driver/st7565.h" -#include "../driver/uart.h" #include "../helper/lootlist.h" #include "../helper/presetlist.h" #include "../scheduler.h" @@ -43,7 +42,7 @@ static void startNewScan(bool reset) { gScanRedraw = stepsCount * gSettings.scanTimeout >= 500; gScanFn = scanFn; uint16_t t = gSettings.scanTimeout < 10 ? gSettings.scanTimeout : 10; - lastReady = elapsedMilliseconds; + lastReady = Now(); SVC_Toggle(SVC_SCAN, true, t); SVC_Toggle(SVC_LISTEN, true, t); @@ -64,9 +63,9 @@ static void scanFn(bool forward) { RADIO_NextPresetFreqEx(forward, gSettings.scanTimeout >= 10); if (PRESETS_GetChannel(gCurrentPreset, radio->rx.f) == stepsCount - 1) { - scanTime = elapsedMilliseconds - lastReady; + scanTime = Now() - lastReady; chPerSec = stepsCount * 1000 / scanTime; - lastReady = elapsedMilliseconds; + lastReady = Now(); gRedrawScreen = true; } @@ -219,5 +218,5 @@ void SPECTRUM_render(void) { SPECTRUM_HEIGHT); } - lastRender = elapsedMilliseconds; + lastRender = Now(); } diff --git a/src/apps/still.c b/src/apps/still.c index bae4386..2bfd008 100644 --- a/src/apps/still.c +++ b/src/apps/still.c @@ -1,5 +1,4 @@ #include "still.h" -#include "../driver/audio.h" #include "../driver/bk4819.h" #include "../driver/st7565.h" #include "../helper/lootlist.h" @@ -15,7 +14,7 @@ #include "finput.h" static uint8_t menuState = 0; -uint32_t lastUpdate = 0; +static uint32_t lastUpdate = 0; static char String[16]; @@ -76,9 +75,9 @@ void STILL_deinit(void) { RADIO_ToggleRX(false); } void STILL_update(void) { RADIO_UpdateMeasurementsEx(gCurrentLoot); - if (elapsedMilliseconds - lastUpdate >= 500) { + if (Now() - lastUpdate >= 500) { gRedrawScreen = true; - lastUpdate = elapsedMilliseconds; + lastUpdate = Now(); } } @@ -199,9 +198,9 @@ static void DrawRegs(void) { const uint8_t textX = offsetX + (CELL_WIDTH - 2) / 2; if (menuState == idx) { - FillRoundRect(offsetX, offsetY, CELL_WIDTH - 2, CELL_HEIGHT - 1, 3, true); + FillRect(offsetX, offsetY, CELL_WIDTH - 2, CELL_HEIGHT - 1, C_FILL); } else { - DrawRoundRect(offsetX, offsetY, CELL_WIDTH - 2, CELL_HEIGHT - 1, 3, true); + DrawRect(offsetX, offsetY, CELL_WIDTH - 2, CELL_HEIGHT - 1, C_FILL); } if (rs.num == BK4819_REG_13) { diff --git a/src/apps/test.h b/src/apps/test.h deleted file mode 100644 index 95f8c15..0000000 --- a/src/apps/test.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef TEST_H -#define TEST_H - -#include "../driver/keyboard.h" - -void TEST_Init(); -void TEST_Update(); -void TEST_Render(); -bool TEST_key(KEY_Code_t k, bool p, bool h); - -#endif /* end of include guard: TEST_H */ diff --git a/src/apps/textinput.c b/src/apps/textinput.c index 6cb2224..ee89aa7 100644 --- a/src/apps/textinput.c +++ b/src/apps/textinput.c @@ -79,15 +79,12 @@ static void backspace(void) { void TEXTINPUT_init(void) { strncpy(inputField, gTextinputText, 15); inputIndex = strlen(inputField); - TaskAdd("Coursor blink", blink, 250, true, 100); + TaskAdd("Cursor blnk", blink, 250, true, 100); } void TEXTINPUT_deinit(void) { TaskRemove(blink); } -void TEXTINPUT_update(void) {} - bool TEXTINPUT_key(KEY_Code_t key, bool bKeyPressed, bool bKeyHeld) { - // up-down keys if (bKeyPressed || (!bKeyPressed && !bKeyHeld)) { switch (key) { diff --git a/src/apps/textinput.h b/src/apps/textinput.h index 60f39dc..48148d6 100644 --- a/src/apps/textinput.h +++ b/src/apps/textinput.h @@ -6,7 +6,6 @@ #include void TEXTINPUT_init(); -void TEXTINPUT_update(); bool TEXTINPUT_key(KEY_Code_t key, bool bKeyPressed, bool bKeyHeld); void TEXTINPUT_render(); void TEXTINPUT_deinit(); diff --git a/src/apps/vfo1.c b/src/apps/vfo1.c index 0050fa9..3001175 100644 --- a/src/apps/vfo1.c +++ b/src/apps/vfo1.c @@ -19,9 +19,9 @@ void VFO1_init(void) { void VFO1_deinit(void) {} void VFO1_update(void) { - if (elapsedMilliseconds - lastUpdate >= 500) { + if (Now() - lastUpdate >= 500) { gRedrawScreen = true; - lastUpdate = elapsedMilliseconds; + lastUpdate = Now(); } } diff --git a/src/apps/vfo2.c b/src/apps/vfo2.c index 7db5c3d..4ee734c 100644 --- a/src/apps/vfo2.c +++ b/src/apps/vfo2.c @@ -28,9 +28,9 @@ void VFO2_init(void) { void VFO2_deinit(void) {} void VFO2_update(void) { - if (elapsedMilliseconds - lastRender >= 500) { + if (Now() - lastRender >= 500) { gRedrawScreen = true; - lastRender = elapsedMilliseconds; + lastRender = Now(); } } @@ -215,9 +215,7 @@ static void render2VFOPart(uint8_t i) { PrintSmallEx(LCD_WIDTH, bl - 9, POS_R, C_FILL, mod); } - uint32_t est = loot->lastTimeOpen - ? (elapsedMilliseconds - loot->lastTimeOpen) / 1000 - : 0; + uint32_t est = loot->lastTimeOpen ? (Now() - loot->lastTimeOpen) / 1000 : 0; if (loot->ct != 0xFF) { PrintSmallEx(0, bl + 6, POS_L, C_FILL, "CT:%u.%uHz", CTCSS_Options[loot->ct] / 10, CTCSS_Options[loot->ct] % 10); diff --git a/src/apps/vfocfg.c b/src/apps/vfocfg.c index 5d1cf0a..34db25d 100644 --- a/src/apps/vfocfg.c +++ b/src/apps/vfocfg.c @@ -106,14 +106,14 @@ static void setTXOffset(uint32_t f) { void VFOCFG_init(void) { gRedrawScreen = true; - for (uint8_t i = 0; i < MENU_SIZE; ++i) { + /* for (uint8_t i = 0; i < MENU_SIZE; ++i) { if (menu[i].type == M_MODULATION) { menu[i].size = RADIO_IsBK1080Range(radio->rx.f) ? ARRAY_SIZE(modulationTypeOptions) : ARRAY_SIZE(modulationTypeOptions) - 1; break; } - } + } */ } void VFOCFG_update(void) {} diff --git a/src/board.c b/src/board.c index d9557ac..c167b2e 100644 --- a/src/board.c +++ b/src/board.c @@ -18,20 +18,15 @@ #include "board.h" #include "driver/adc.h" #include "driver/backlight.h" -#include "driver/bk1080.h" +// #include "driver/bk1080.h" #include "driver/bk4819.h" #include "driver/crc.h" -#include "driver/eeprom.h" #include "driver/gpio.h" #include "driver/st7565.h" -#include "driver/system.h" -#include "helper/battery.h" #include "inc/dp32g030/gpio.h" #include "inc/dp32g030/portcon.h" #include "inc/dp32g030/saradc.h" #include "inc/dp32g030/syscon.h" -#include "misc.h" -#include void BOARD_GPIO_Init(void) { GPIOA->DIR |= 0 @@ -433,7 +428,8 @@ void BOARD_Init(void) { BOARD_GPIO_Init(); BOARD_ADC_Init(); ST7565_Init(); - BK1080_Init(0, false); + // BK1080_Init(0, false); BK4819_Init(); BACKLIGHT_Init(); + CRC_Init(); } diff --git a/src/driver/audio.c b/src/driver/audio.c index 3a65bfc..3d9f3c6 100644 --- a/src/driver/audio.c +++ b/src/driver/audio.c @@ -1,28 +1,10 @@ -/* 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 "audio.h" -#include "driver/bk4819.h" -#include "driver/gpio.h" -#include "driver/system.h" -#include "driver/systick.h" -#include "inc/dp32g030/gpio.h" -#include "misc.h" +#include "../inc/dp32g030/gpio.h" +#include "bk4819.h" +#include "gpio.h" +#include "system.h" -bool speakerOn = false; +static bool speakerOn = false; void AUDIO_ToggleSpeaker(bool on) { speakerOn = on; @@ -38,7 +20,6 @@ void AUDIO_PlayTone(uint32_t frequency, uint16_t duration) { uint16_t ToneConfig = BK4819_ReadRegister(BK4819_REG_71); AUDIO_ToggleSpeaker(false); - // BK4819_RX_TurnOn(); SYSTEM_DelayMs(20); BK4819_PlayTone(frequency, true); diff --git a/src/driver/audio.h b/src/driver/audio.h index a47f9af..48f68be 100644 --- a/src/driver/audio.h +++ b/src/driver/audio.h @@ -1,19 +1,3 @@ -/* Copyright 2023 Dual Tachyon - * https://github.com/DualTachyon - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - #ifndef AUDIO_H #define AUDIO_H diff --git a/src/driver/bk4819.c b/src/driver/bk4819.c index 4232698..bd41007 100644 --- a/src/driver/bk4819.c +++ b/src/driver/bk4819.c @@ -18,7 +18,6 @@ #include "../driver/gpio.h" #include "../driver/system.h" #include "../driver/systick.h" -#include "../driver/uart.h" #include "../inc/dp32g030/gpio.h" #include "../inc/dp32g030/portcon.h" #include "../misc.h" @@ -38,27 +37,8 @@ static uint8_t modTypeCurrent = 255; bool gRxIdleMode; -const uint8_t DTMF_COEFFS[] = {111, 107, 103, 98, 80, 71, 58, 44, - 65, 55, 37, 23, 228, 203, 181, 159}; - -/* const uint8_t SQ[2][6][11] = { - { - {0, 10, 44, 52, 58, 66, 72, 80, 88, 94, 102}, - {0, 5, 38, 46, 54, 62, 68, 76, 84, 92, 100}, - {255, 90, 53, 48, 44, 40, 36, 32, 28, 24, 20}, - {255, 100, 56, 52, 47, 43, 39, 35, 31, 27, 23}, - {255, 90, 32, 24, 20, 17, 14, 11, 8, 3, 2}, - {255, 100, 30, 21, 17, 14, 11, 8, 5, 5, 4}, - }, - { - {0, 36, 77, 82, 88, 94, 100, 106, 112, 118, 123}, - {0, 40, 70, 76, 82, 88, 94, 102, 108, 114, 120}, - {255, 65, 58, 52, 46, 41, 37, 33, 28, 24, 22}, - {255, 70, 65, 57, 51, 45, 41, 37, 32, 28, 25}, - {255, 90, 32, 23, 18, 15, 10, 9, 8, 7, 4}, - {255, 100, 60, 45, 30, 20, 15, 13, 12, 11, 8}, - }, -}; */ +static const uint8_t DTMF_COEFFS[] = {111, 107, 103, 98, 80, 71, 58, 44, + 65, 55, 37, 23, 228, 203, 181, 159}; const uint8_t SQ[2][6][11] = { { @@ -103,6 +83,8 @@ const Gain gainTable[19] = { {0x3E0, 0}, // }; +void BK4819_Idle(void) { BK4819_WriteRegister(BK4819_REG_30, 0x0000); } + void BK4819_Init(void) { GPIO_SetBit(&GPIOC->DATA, GPIOC_PIN_BK4819_SCN); GPIO_SetBit(&GPIOC->DATA, GPIOC_PIN_BK4819_SCL); @@ -225,24 +207,11 @@ void BK4819_WriteRegister(BK4819_REGISTER_t Register, uint16_t Data) { } void BK4819_SetAGC(bool useDefault) { - // QS BK4819_WriteRegister(BK4819_REG_13, 0x03BE); BK4819_WriteRegister(BK4819_REG_12, 0x037B); BK4819_WriteRegister(BK4819_REG_11, 0x027B); BK4819_WriteRegister(BK4819_REG_10, 0x007A); - // BK - /* BK4819_WriteRegister(BK4819_REG_13, 0x03DE); - BK4819_WriteRegister(BK4819_REG_12, 0x037B); - BK4819_WriteRegister(BK4819_REG_11, 0x025A); - BK4819_WriteRegister(BK4819_REG_10, 0x0038); */ - - // 1o11 - /* BK4819_WriteRegister(BK4819_REG_12, 0x0393); - BK4819_WriteRegister(BK4819_REG_11, 0x01B5); - BK4819_WriteRegister(BK4819_REG_10, 0x0145); - BK4819_WriteRegister(BK4819_REG_14, 0x0019); */ - uint8_t Lo = 0; // 0-1 - auto, 2 - low, 3 high uint8_t low = 48; // 1dB / LSB 56 uint8_t high = 80; // 1dB / LSB 84 @@ -349,27 +318,15 @@ void BK4819_EnableVox(uint16_t VoxEnableThreshold, } void BK4819_SetFilterBandwidth(BK4819_FilterBandwidth_t Bandwidth) { - /* if (BK4819_ReadRegister(BK4819_REG_43) != - BWRegValues[Bandwidth]) { // TODO: maybe slow */ BK4819_WriteRegister(BK4819_REG_43, BWRegValues[Bandwidth]); - // } } -void BK4819_SetupPowerAmplifier(uint16_t Bias, uint32_t Frequency) { - uint8_t Gain; +void BK4819_SetupPowerAmplifier(uint8_t Bias, uint32_t Frequency) { + uint8_t Gain = Frequency < VHF_UHF_BOUND2 ? 0x08 : 0x22; if (Bias > 255) { Bias = 255; } - if (Frequency < VHF_UHF_BOUND2) { - // Gain 1 = 1 - // Gain 2 = 0 - Gain = 0x08U; - } else { - // Gain 1 = 4 - // Gain 2 = 2 - Gain = 0x22U; - } // Enable PACTLoutput BK4819_WriteRegister(BK4819_REG_36, (Bias << 8) | 0x80U | Gain); } @@ -443,14 +400,34 @@ void BK4819_SetModulation(ModulationType type) { return; } modTypeCurrent = type; - const uint16_t modTypeReg47Values[] = {BK4819_AF_FM, BK4819_AF_AM, - BK4819_AF_USB, BK4819_AF_BYPASS, - BK4819_AF_RAW, BK4819_AF_FM}; + const uint16_t modTypeReg47Values[] = { + BK4819_AF_FM, BK4819_AF_AM, BK4819_AF_USB, BK4819_AF_BYPASS, + BK4819_AF_RAW, BK4819_AF_FM, BK4819_AF_BEEP}; BK4819_SetAF(modTypeReg47Values[type]); BK4819_SetRegValue(afDacGainRegSpec, 0xF); BK4819_SetAGC(type != MOD_AM); BK4819_WriteRegister(0x3D, type == MOD_USB ? 0 : 0x2AAB); - BK4819_SetRegValue(afcDisableRegSpec, type == MOD_AM || type == MOD_USB || type == MOD_BYP); + BK4819_SetRegValue(afcDisableRegSpec, + type == MOD_AM || type == MOD_USB || type == MOD_BYP); + RegisterSpec xtalMode = {"XTAL F Mode Select", 0x3C, 6, 0b11, 1}; + RegisterSpec rfFltBW = {"RF filt BW", 0x43, 12, 0b111, 1}; + RegisterSpec rfFltBWw = {"RFfiltBWweak", 0x43, 9, 0b111, 1}; + RegisterSpec bwMode = {"BW Mode Selection", 0x43, 4, 0b11, 1}; + RegisterSpec ifF = {"IF step1x", 0x3D, 0, 0xFFFF, 1}; + if (type == MOD_WFM) { + BK4819_SetRegValue(xtalMode, 0); + BK4819_SetRegValue(afDacGainRegSpec, 0x8); + BK4819_SetRegValue(rfFltBW, 7); + BK4819_SetRegValue(rfFltBWw, 7); + BK4819_SetRegValue(bwMode, 3); + BK4819_SetRegValue(ifF, 14223); + } else { + BK4819_SetRegValue(xtalMode, 2); + BK4819_SetRegValue(rfFltBW, 7); + BK4819_SetRegValue(rfFltBWw, 7); + BK4819_SetRegValue(bwMode, 3); + BK4819_SetRegValue(ifF, 10923); + } } void BK4819_RX_TurnOn(void) { @@ -470,7 +447,7 @@ void BK4819_RX_TurnOn(void) { BK4819_WriteRegister(BK4819_REG_37, 0x1F0F); // Turn off everything - BK4819_WriteRegister(BK4819_REG_30, 0); + BK4819_Idle(); // Enable VCO Calibration // Enable RX Link @@ -489,15 +466,13 @@ void BK4819_DisableFilter(void) { } void BK4819_SelectFilter(uint32_t f) { - Filter filterNeeded = f < SETTINGS_GetFilterBound() ? FILTER_VHF : FILTER_UHF; + Filter filter = f < SETTINGS_GetFilterBound() ? FILTER_VHF : FILTER_UHF; - if (selectedFilter == filterNeeded) { - return; + if (selectedFilter != filter) { + selectedFilter = filter; + BK4819_ToggleGpioOut(BK4819_GPIO4_PIN32_VHF_LNA, filter == FILTER_VHF); + BK4819_ToggleGpioOut(BK4819_GPIO3_PIN31_UHF_LNA, filter == FILTER_UHF); } - - selectedFilter = filterNeeded; - BK4819_ToggleGpioOut(BK4819_GPIO4_PIN32_VHF_LNA, filterNeeded == FILTER_VHF); - BK4819_ToggleGpioOut(BK4819_GPIO3_PIN31_UHF_LNA, filterNeeded == FILTER_UHF); } void BK4819_DisableScramble(void) { @@ -549,7 +524,7 @@ void BK4819_PlayTone(uint16_t Frequency, bool bTuningGainSwitch) { } BK4819_WriteRegister(BK4819_REG_70, ToneConfig); - BK4819_WriteRegister(BK4819_REG_30, 0); + BK4819_Idle(); BK4819_WriteRegister(BK4819_REG_30, 0 | BK4819_REG_30_ENABLE_AF_DAC | BK4819_REG_30_ENABLE_DISC_MODE | BK4819_REG_30_ENABLE_TX_DSP); @@ -562,7 +537,7 @@ void BK4819_EnterTxMute(void) { BK4819_WriteRegister(BK4819_REG_50, 0xBB20); } void BK4819_ExitTxMute(void) { BK4819_WriteRegister(BK4819_REG_50, 0x3B20); } void BK4819_Sleep(void) { - BK4819_WriteRegister(BK4819_REG_30, 0); + BK4819_Idle(); BK4819_WriteRegister(BK4819_REG_37, 0x1D00); } @@ -570,7 +545,7 @@ void BK4819_TurnsOffTones_TurnsOnRX(void) { BK4819_WriteRegister(BK4819_REG_70, 0); BK4819_SetAF(BK4819_AF_MUTE); BK4819_ExitTxMute(); - BK4819_WriteRegister(BK4819_REG_30, 0); + BK4819_Idle(); BK4819_WriteRegister( BK4819_REG_30, 0 | BK4819_REG_30_ENABLE_VCO_CALIB | BK4819_REG_30_ENABLE_RX_LINK | @@ -578,7 +553,6 @@ void BK4819_TurnsOffTones_TurnsOnRX(void) { BK4819_REG_30_ENABLE_PLL_VCO | BK4819_REG_30_ENABLE_RX_DSP); } - void BK4819_ResetFSK(void) { BK4819_WriteRegister(BK4819_REG_3F, 0x0000); // Disable interrupts BK4819_WriteRegister(BK4819_REG_59, @@ -587,23 +561,21 @@ void BK4819_ResetFSK(void) { BK4819_Idle(); } -void BK4819_FskClearFifo(void){ - const uint16_t fsk_reg59 = BK4819_ReadRegister(BK4819_REG_59); - BK4819_WriteRegister(BK4819_REG_59, (1u << 15) | (1u << 14) | fsk_reg59); +void BK4819_FskClearFifo(void) { + const uint16_t fsk_reg59 = BK4819_ReadRegister(BK4819_REG_59); + BK4819_WriteRegister(BK4819_REG_59, (1u << 15) | (1u << 14) | fsk_reg59); } -void BK4819_FskEnableRx(void){ - const uint16_t fsk_reg59 = BK4819_ReadRegister(BK4819_REG_59); - BK4819_WriteRegister(BK4819_REG_59, (1u << 12) | fsk_reg59); +void BK4819_FskEnableRx(void) { + const uint16_t fsk_reg59 = BK4819_ReadRegister(BK4819_REG_59); + BK4819_WriteRegister(BK4819_REG_59, (1u << 12) | fsk_reg59); } -void BK4819_FskEnableTx(void){ - const uint16_t fsk_reg59 = BK4819_ReadRegister(BK4819_REG_59); - BK4819_WriteRegister(BK4819_REG_59, (1u << 11) | fsk_reg59); +void BK4819_FskEnableTx(void) { + const uint16_t fsk_reg59 = BK4819_ReadRegister(BK4819_REG_59); + BK4819_WriteRegister(BK4819_REG_59, (1u << 11) | fsk_reg59); } -void BK4819_Idle(void) { BK4819_WriteRegister(BK4819_REG_30, 0x0000); } - void BK4819_ExitBypass(void) { BK4819_SetAF(BK4819_AF_MUTE); BK4819_WriteRegister(BK4819_REG_7E, 0x302E); @@ -618,7 +590,7 @@ void BK4819_PrepareTransmit(void) { void BK4819_TxOn_Beep(void) { BK4819_WriteRegister(BK4819_REG_37, 0x1D0F); BK4819_WriteRegister(BK4819_REG_52, 0x028F); - BK4819_WriteRegister(BK4819_REG_30, 0x0000); + BK4819_Idle(); BK4819_WriteRegister(BK4819_REG_30, 0xC1FE); } @@ -1002,7 +974,7 @@ void BK4819_PlayRogerMDC(void) { } void BK4819_Enable_AfDac_DiscMode_TxDsp(void) { - BK4819_WriteRegister(BK4819_REG_30, 0x0000); + BK4819_Idle(); BK4819_WriteRegister(BK4819_REG_30, 0x0302); } @@ -1041,11 +1013,11 @@ void BK4819_TuneTo(uint32_t f, bool precise) { BK4819_SelectFilter(f); BK4819_SetFrequency(f); uint16_t reg = BK4819_ReadRegister(BK4819_REG_30); - if(precise) { - BK4819_WriteRegister(BK4819_REG_30, 0); - } else { - BK4819_WriteRegister(BK4819_REG_30, reg & ~BK4819_REG_30_ENABLE_VCO_CALIB); - } + if (precise) { + BK4819_Idle(); + } else { + BK4819_WriteRegister(BK4819_REG_30, reg & ~BK4819_REG_30_ENABLE_VCO_CALIB); + } BK4819_WriteRegister(BK4819_REG_30, reg); } @@ -1069,10 +1041,3 @@ void BK4819_SetGain(uint8_t gainIndex) { BK4819_WriteRegister(BK4819_REG_13, gainTable[gainIndex].regValue | 6 | (3 << 3)); } - -void BK4819_HandleInterrupts(void (*handler)(uint16_t intStatus)) { - while (BK4819_ReadRegister(BK4819_REG_0C) & 1u) { - BK4819_WriteRegister(BK4819_REG_02, 0); - handler(BK4819_ReadRegister(BK4819_REG_02)); - } -} diff --git a/src/driver/bk4819.h b/src/driver/bk4819.h index 11d3427..c195bdd 100644 --- a/src/driver/bk4819.h +++ b/src/driver/bk4819.h @@ -38,11 +38,12 @@ enum BK4819_AF_Type_t { BK4819_AF_FM, BK4819_AF_ALAM, // tone BK4819_AF_BEEP, // for tx - BK4819_AF_RAW, // (ssb without if filter = raw in sdr sharp) - BK4819_AF_USB, // (or ssb = lsb and usb at the same time) + BK4819_AF_RAW, // (ssb without if filter = raw in sdr sharp) + BK4819_AF_USB, // (or ssb = lsb and usb at the same time) BK4819_AF_CTCO, // ctcss/dcs (fm with narrow filters for ctcss/dcs) BK4819_AF_AM, - BK4819_AF_FSKO, // fsk out test with special fsk filters (need reg58 fsk on to give sound on speaker ) + BK4819_AF_FSKO, // fsk out test with special fsk filters (need reg58 fsk on to + // give sound on speaker ) BK4819_AF_BYPASS, // (fm without filter = discriminator output) }; @@ -112,7 +113,7 @@ void BK4819_SetCTCSSFrequency(uint32_t BaudRate); void BK4819_SetTailDetection(const uint32_t freq_10Hz); void BK4819_EnableVox(uint16_t Vox1Threshold, uint16_t Vox0Threshold); void BK4819_SetFilterBandwidth(BK4819_FilterBandwidth_t Bandwidth); -void BK4819_SetupPowerAmplifier(uint16_t Bias, uint32_t Frequency); +void BK4819_SetupPowerAmplifier(uint8_t Bias, uint32_t Frequency); void BK4819_SetFrequency(uint32_t Frequency); uint32_t BK4819_GetFrequency(void); void BK4819_SetupSquelch(uint8_t SquelchOpenRSSIThresh, @@ -210,6 +211,5 @@ void BK4819_SetModulation(ModulationType type); bool BK4819_IsSquelchOpen(); void BK4819_ResetRSSI(); void BK4819_SetGain(uint8_t gainIndex); -void BK4819_HandleInterrupts(void (*handler)(uint16_t intStatus)); #endif diff --git a/src/driver/eeprom.c b/src/driver/eeprom.c index 4b0758e..4872fbe 100644 --- a/src/driver/eeprom.c +++ b/src/driver/eeprom.c @@ -1,78 +1,58 @@ #include "../driver/eeprom.h" #include "../driver/i2c.h" #include "../driver/system.h" +// #include "../external/CMSIS_5/Device/ARM/ARMCM0/Include/ARMCM0.h" #include "../settings.h" #include #include bool gEepromWrite = false; -bool gEepromRead = false; -void EEPROM_ReadBuffer(uint32_t address, void *pBuffer, uint8_t size) { +void EEPROM_ReadBuffer(uint32_t address, void *pBuffer, uint16_t size) { + // __disable_irq(); uint8_t IIC_ADD = (uint8_t)(0xA0 | ((address / 0x10000) << 1)); - if (gSettings.eepromType == EEPROM_M24M02) { - if (address >= 0x40000) { - IIC_ADD = (uint8_t)(0xA8 | (((address - 0x40000) / 0x10000) << 1)); - address -= 0x40000; - } - } - I2C_Start(); - I2C_Write(IIC_ADD); I2C_Write((address >> 8) & 0xFF); I2C_Write(address & 0xFF); - I2C_Start(); - I2C_Write(IIC_ADD + 1); - I2C_ReadBuffer(pBuffer, size); - I2C_Stop(); - - gEepromRead = true; + // __enable_irq(); } -// static uint8_t tmpBuffer[256]; -void EEPROM_WriteBuffer(uint32_t address, void *pBuffer, uint8_t size) { +static uint8_t tmpBuffer[128]; +void EEPROM_WriteBuffer(uint32_t address, void *pBuffer, uint16_t size) { if (pBuffer == NULL) { return; } const uint8_t PAGE_SIZE = SETTINGS_GetPageSize(); while (size) { - uint32_t pageNum = address / PAGE_SIZE; - uint32_t rest = (pageNum + 1) * PAGE_SIZE - address; - - // TODO: assume that size < PAGE_SIZE - uint8_t n = rest > size ? size : (uint8_t)rest; + uint16_t i = address % PAGE_SIZE; + uint16_t rest = PAGE_SIZE - i; + uint16_t n = size < rest ? size : rest; - /* EEPROM_ReadBuffer(address, tmpBuffer, n); - if (memcmp(buf, tmpBuffer, n) != 0) { */ - uint8_t IIC_ADD = (uint8_t)(0xA0 | ((address / 0x10000) << 1)); + EEPROM_ReadBuffer(address, tmpBuffer, n); + if (memcmp(pBuffer, tmpBuffer, n) != 0) { + uint8_t IIC_ADD = (uint8_t)(0xA0 | ((address / 0x10000) << 1)); - if (gSettings.eepromType == EEPROM_M24M02) { - if (address >= 0x40000) { - IIC_ADD = (uint8_t)(0xA8 | (((address - 0x40000) / 0x10000) << 1)); - } - } - - I2C_Start(); - I2C_Write(IIC_ADD); - I2C_Write((address >> 8) & 0xFF); - I2C_Write(address & 0xFF); + I2C_Start(); + I2C_Write(IIC_ADD); + I2C_Write((address >> 8) & 0xFF); + I2C_Write(address & 0xFF); - I2C_WriteBuffer(pBuffer, n); + I2C_WriteBuffer(pBuffer, n); - I2C_Stop(); - SYSTEM_DelayMs(10); + I2C_Stop(); + SYSTEM_DelayMs(10); + } pBuffer += n; address += n; size -= n; - // } gEepromWrite = true; } } diff --git a/src/driver/eeprom.h b/src/driver/eeprom.h index e3313de..288abee 100644 --- a/src/driver/eeprom.h +++ b/src/driver/eeprom.h @@ -4,10 +4,9 @@ #include #include -extern bool gEepromRead; extern bool gEepromWrite; -void EEPROM_ReadBuffer(uint32_t Address, void *pBuffer, uint8_t Size); -void EEPROM_WriteBuffer(uint32_t Address, void *pBuffer, uint8_t Size); +void EEPROM_ReadBuffer(uint32_t Address, void *pBuffer, uint16_t Size); +void EEPROM_WriteBuffer(uint32_t Address, void *pBuffer, uint16_t Size); #endif diff --git a/src/driver/i2c.c b/src/driver/i2c.c index a42e709..20d3f63 100644 --- a/src/driver/i2c.c +++ b/src/driver/i2c.c @@ -1,19 +1,3 @@ -/* 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 "i2c.h" #include "../inc/dp32g030/gpio.h" #include "../inc/dp32g030/portcon.h" @@ -150,8 +134,9 @@ int I2C_ReadBuffer(void *pBuffer, uint8_t Size) { int I2C_WriteBuffer(const void *pBuffer, uint8_t Size) { const uint8_t *pData = (const uint8_t *)pBuffer; + uint8_t i; - for (uint8_t i = 0; i < Size; i++) { + for (i = 0; i < Size; i++) { if (I2C_Write(*pData++) < 0) { return -1; } diff --git a/src/driver/i2c.h b/src/driver/i2c.h index 18688d0..7a9bcb2 100644 --- a/src/driver/i2c.h +++ b/src/driver/i2c.h @@ -1,19 +1,3 @@ -/* Copyright 2023 Dual Tachyon - * https://github.com/DualTachyon - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - #ifndef DRIVER_I2C_H #define DRIVER_I2C_H @@ -32,6 +16,6 @@ uint8_t I2C_Read(bool bFinal); int I2C_Write(uint8_t Data); int I2C_ReadBuffer(void *pBuffer, uint8_t Size); -int I2C_WriteBuffer(const void *pBuffer, uint8_t size); +int I2C_WriteBuffer(const void *pBuffer, uint8_t Size); #endif diff --git a/src/driver/si473x.c b/src/driver/si473x.c new file mode 100644 index 0000000..e8ca344 --- /dev/null +++ b/src/driver/si473x.c @@ -0,0 +1,352 @@ +#include "si473x.h" +#include "../inc/dp32g030/gpio.h" +#include "../settings.h" +#include "audio.h" +#include "eeprom.h" +#include "gpio.h" +#include "i2c.h" +#include "system.h" +#include "systick.h" + +static const uint8_t SI47XX_I2C_ADDR = 0x22; + +#define RST_HIGH GPIO_ClearBit(&GPIOB->DATA, GPIOB_PIN_BK1080) +#define RST_LOW GPIO_SetBit(&GPIOB->DATA, GPIOB_PIN_BK1080) + +RSQStatus rsqStatus; +SsbMode currentSsbMode; + +SI47XX_MODE si4732mode = SI47XX_FM; +uint16_t siCurrentFreq = 10320; + +void SI47XX_ReadBuffer(uint8_t *buf, uint8_t size) { + I2C_Start(); + I2C_Write(SI47XX_I2C_ADDR + 1); + I2C_ReadBuffer(buf, size); + I2C_Stop(); +} + +void SI47XX_WriteBuffer(uint8_t *buf, uint8_t size) { + I2C_Start(); + I2C_Write(SI47XX_I2C_ADDR); + I2C_WriteBuffer(buf, size); + I2C_Stop(); +} + +bool SI47XX_IsSSB() { + return si4732mode == SI47XX_USB || si4732mode == SI47XX_LSB; +} + +void waitToSend() { + uint8_t tmp = 0; + SI47XX_ReadBuffer((uint8_t *)&tmp, 1); + while (!(tmp & STATUS_CTS)) { + SYSTICK_DelayUs(1); + SI47XX_ReadBuffer((uint8_t *)&tmp, 1); + } +} + +bool SI47XX_downloadPatch() { + uint8_t buf[248]; + const uint8_t PAGE_SIZE = SETTINGS_GetPageSize(); + const uint32_t EEPROM_SIZE = SETTINGS_GetEEPROMSize(); + const uint32_t PATCH_START = EEPROM_SIZE - PATCH_SIZE; + for (uint16_t offset = 0; offset < PATCH_SIZE; offset += 248) { + uint32_t eepromN = PATCH_SIZE - offset > 248 ? 248 : PATCH_SIZE - offset; + EEPROM_ReadBuffer(PATCH_START + offset, buf, eepromN); + + for (uint8_t i = 0; i < eepromN; i += 8) { + waitToSend(); + SI47XX_WriteBuffer(buf + i, 8); + } + } + // SYSTEM_DelayMs(250); + return true; +} + +void sendProperty(uint16_t prop, uint16_t parameter) { + waitToSend(); + uint8_t tmp[6] = {CMD_SET_PROPERTY, 0, prop >> 8, prop & 0xff, parameter >> 8, + parameter & 0xff}; + SI47XX_WriteBuffer(tmp, 6); + SYSTEM_DelayMs(10); // irrespective of CTS coming up earlier than that +} + +uint16_t getProperty(uint16_t prop, bool *valid) { + uint8_t response[4] = {0}; + uint8_t tmp[4] = {CMD_GET_PROPERTY, 0, prop >> 8, prop & 0xff}; + waitToSend(); + SI47XX_WriteBuffer(tmp, 4); + SI47XX_ReadBuffer(response, 4); + + if (valid) { + *valid = !(response[0] & STATUS_ERR); + } + + return (response[2] << 8) | response[3]; +} + +void RSQ_GET() { + uint8_t cmd[2] = {CMD_FM_RSQ_STATUS, 0x01}; + if (si4732mode != SI47XX_FM) { + cmd[0] = CMD_AM_RSQ_STATUS; + } + + waitToSend(); + SI47XX_WriteBuffer(cmd, 2); + SI47XX_ReadBuffer(rsqStatus.raw, si4732mode == SI47XX_FM ? 8 : 6); +} + +void setVolume(uint8_t volume) { + if (volume < 0) + volume = 0; + if (volume > 63) + volume = 63; + sendProperty(PROP_RX_VOLUME, volume); +} + +void setAvcAmMaxGain(uint8_t gain) { + if (gain < 12 || gain > 90) + return; + sendProperty(PROP_AM_AUTOMATIC_VOLUME_CONTROL_MAX_GAIN, gain * 340); +} + +void enableRDS(void) { + // Enable and configure RDS reception + if (si4732mode == SI47XX_FM) { + sendProperty(PROP_FM_RDS_INT_SOURCE, FLG_RDSRECV); + // Set the FIFO high-watermark to 12 RDS blocks, which is safe even for + // old chips, yet large enough to improve performance. + sendProperty(PROP_FM_RDS_INT_FIFO_COUNT, 12); + sendProperty( + PROP_FM_RDS_CONFIG, + ((FLG_BLETHA_35 | FLG_BLETHB_35 | FLG_BLETHC_35 | FLG_BLETHD_35) << 8) | + FLG_RDSEN); + }; +} + +void SI47XX_SetAutomaticGainControl(uint8_t AGCDIS, uint8_t AGCIDX) { + SI47XX_AgcOverrride agc; + + uint8_t cmd; + + if (si4732mode == SI47XX_FM) + cmd = CMD_FM_AGC_OVERRIDE; + else + cmd = CMD_AM_AGC_OVERRIDE; // both for AM and SSB + + agc.arg.DUMMY = 0; // ARG1: bits 7:1 Always write to 0; + agc.arg.AGCDIS = AGCDIS; + agc.arg.AGCIDX = AGCIDX; + + waitToSend(); + + uint8_t cmd2[] = {cmd, agc.raw[0], agc.raw[1]}; + SI47XX_WriteBuffer(cmd2, 3); +} + +void SI47XX_PowerUp() { + RST_HIGH; + uint8_t cmd[3] = {CMD_POWER_UP, FLG_XOSCEN | FUNC_FM, OUT_ANALOG}; + if (si4732mode == SI47XX_AM) { + cmd[1] = FLG_XOSCEN | FUNC_AM; + } + waitToSend(); + SI47XX_WriteBuffer(cmd, 3); + SYSTEM_DelayMs(500); + + AUDIO_ToggleSpeaker(true); + setVolume(63); + + if (si4732mode == SI47XX_FM) { + enableRDS(); + } else if (si4732mode == SI47XX_AM) { + SI47XX_SetAutomaticGainControl(1, 0); + sendProperty(PROP_AM_SOFT_MUTE_MAX_ATTENUATION, 0); + sendProperty(PROP_AM_AUTOMATIC_VOLUME_CONTROL_MAX_GAIN, 0x7800); + SI47XX_SetSeekAmLimits(1800, 30000); + } + SI47XX_SetFreq(siCurrentFreq); +} + +void SI47XX_SsbSetup(SI47XX_SsbFilterBW AUDIOBW, uint8_t SBCUTFLT, + uint8_t AVC_DIVIDER, uint8_t AVCEN, uint8_t SMUTESEL, + uint8_t DSP_AFCDIS) { + currentSsbMode.param.SBCUTFLT = SBCUTFLT; + currentSsbMode.param.AVC_DIVIDER = AVC_DIVIDER; + currentSsbMode.param.AVCEN = AVCEN; + currentSsbMode.param.SMUTESEL = SMUTESEL; + currentSsbMode.param.DSP_AFCDIS = DSP_AFCDIS; + currentSsbMode.param.AUDIOBW = AUDIOBW; + sendProperty(PROP_SSB_MODE, + (currentSsbMode.raw[1] << 8) | currentSsbMode.raw[0]); +} + +void SI47XX_PatchPowerUp() { + RST_HIGH; + uint8_t cmd[3] = {CMD_POWER_UP, 0b00110001, OUT_ANALOG}; + waitToSend(); + SI47XX_WriteBuffer(cmd, 3); + SYSTEM_DelayMs(550); + + SI47XX_downloadPatch(); + + SI47XX_SsbSetup(2, 1, 0, 1, 0, 1); + + AUDIO_ToggleSpeaker(true); + setVolume(63); + + SI47XX_SetFreq(siCurrentFreq); + sendProperty(PROP_SSB_SOFT_MUTE_MAX_ATTENUATION, 0); + sendProperty(PROP_AM_AUTOMATIC_VOLUME_CONTROL_MAX_GAIN, 0x7800); +} + +void SI47XX_SetSsbBandwidth(SI47XX_SsbFilterBW bw) { + SI47XX_SsbSetup(bw, 1, 0, 1, 0, 1); +} + +void SI47XX_Seek(bool up, bool wrap) { + uint8_t seekOpt = (up ? FLG_SEEKUP : 0) | (wrap ? FLG_WRAP : 0); + uint8_t cmd[6] = {CMD_FM_SEEK_START, seekOpt, 0x00, 0x00, 0x00, 0x00}; + + if (si4732mode == SI47XX_AM) { + cmd[0] = CMD_AM_SEEK_START; + cmd[5] = (siCurrentFreq > 1800) ? 1 : 0; + } + + waitToSend(); + SI47XX_WriteBuffer(cmd, si4732mode == SI47XX_FM ? 2 : 6); +} + +uint16_t SI47XX_getFrequency(bool *valid) { + uint8_t response[4] = {0}; + uint8_t cmd[1] = {CMD_FM_TUNE_STATUS}; + + if (si4732mode == SI47XX_AM) { + cmd[0] = CMD_AM_TUNE_STATUS; + } + + waitToSend(); + SI47XX_WriteBuffer(cmd, 1); + SI47XX_ReadBuffer(response, 4); + + if (valid) { + *valid = (response[1] & STATUS_VALID); + } + + return (response[2] << 8) | response[3]; +} + +void SI47XX_PowerDown() { + AUDIO_ToggleSpeaker(false); + uint8_t cmd[1] = {CMD_POWER_DOWN}; + + waitToSend(); + SI47XX_WriteBuffer(cmd, 1); + SYSTICK_Delay250ns(10); + RST_LOW; +} + +void SI47XX_SwitchMode(SI47XX_MODE mode) { + if (si4732mode != mode) { + bool wasSSB = SI47XX_IsSSB(); + si4732mode = mode; + if (mode == SI47XX_USB || mode == SI47XX_LSB) { + if (!wasSSB) { + SI47XX_PowerDown(); + SI47XX_PatchPowerUp(); + } + } else { + SI47XX_PowerDown(); + SI47XX_PowerUp(); + } + } +} + +void SI47XX_SetFreq(uint16_t freq) { + uint8_t hb = (freq >> 8) & 0xFF; + uint8_t lb = freq & 0xFF; + + bool isSW = freq > 1800; + + uint8_t size = 4; + uint8_t cmd[6] = {CMD_FM_TUNE_FREQ, 0x00, hb, lb, 0, 0}; + + if (si4732mode == SI47XX_FM || si4732mode == SI47XX_AM) { + cmd[1] = 0x01; // FAST + } + + if (si4732mode == SI47XX_AM) { + cmd[0] = CMD_AM_TUNE_FREQ; + size = 5; + } + + if (SI47XX_IsSSB()) { + cmd[0] = CMD_AM_TUNE_FREQ; // same as AM 0x40 + if (si4732mode == SI47XX_USB) { + cmd[1] = 0b10000000; + } else { + cmd[1] = 0b01000000; + } + size = 6; + } + + if (si4732mode != SI47XX_FM) { + if (isSW) { + cmd[5] = 1; + } + } + + waitToSend(); + SI47XX_WriteBuffer(cmd, size); + siCurrentFreq = freq; + + SYSTEM_DelayMs(30); + // RSQ_GET(); +} + +void SI47XX_SetAMFrontendAGC(uint8_t minGainIdx, uint8_t attnBackup) { + sendProperty(PROP_AM_FRONTEND_AGC_CONTROL, minGainIdx << 8 | attnBackup); +} + +void SI47XX_SetBandwidth(SI47XX_FilterBW AMCHFLT, bool AMPLFLT) { + SI47XX_BW_Config cfg = {0}; + cfg.param.AMCHFLT = AMCHFLT; + cfg.param.AMPLFLT = AMPLFLT; + sendProperty(PROP_AM_CHANNEL_FILTER, (cfg.raw[1] << 8) | cfg.raw[0]); +} + +void SI47XX_ReadRDS(uint8_t buf[13]) { + uint8_t cmd[2] = {CMD_FM_RDS_STATUS, RDS_STATUS_ARG1_CLEAR_INT}; + waitToSend(); + SI47XX_WriteBuffer(cmd, 2); + SI47XX_ReadBuffer(buf, 13); +} + +void SI47XX_SetSeekFmLimits(uint16_t bottom, uint16_t top) { + sendProperty(PROP_FM_SEEK_BAND_BOTTOM, bottom); + sendProperty(PROP_FM_SEEK_BAND_TOP, top); +} + +void SI47XX_SetSeekAmLimits(uint16_t bottom, uint16_t top) { + sendProperty(PROP_AM_SEEK_BAND_BOTTOM, bottom); + sendProperty(PROP_AM_SEEK_BAND_TOP, top); +} + +void SI47XX_SetSeekFmSpacing(uint16_t spacing) { + sendProperty(PROP_FM_SEEK_FREQ_SPACING, spacing); +} + +void SI47XX_SetSeekAmSpacing(uint16_t spacing) { + sendProperty(PROP_AM_SEEK_FREQ_SPACING, spacing); +} + +void SI47XX_SetSeekFmRssiThreshold(uint16_t value) { + sendProperty(PROP_FM_SEEK_TUNE_RSSI_THRESHOLD, value); +} + +void SI47XX_SetSeekAmRssiThreshold(uint16_t value) { + sendProperty(PROP_AM_SEEK_TUNE_RSSI_THRESHOLD, value); +} + +void SI47XX_SetBFO(int16_t bfo) { sendProperty(PROP_SSB_BFO, bfo); } diff --git a/src/driver/si473x.h b/src/driver/si473x.h new file mode 100644 index 0000000..a4cba95 --- /dev/null +++ b/src/driver/si473x.h @@ -0,0 +1,579 @@ +#ifndef SI473X_H +#define SI473X_H + +#include +#include + +typedef enum { + SI47XX_FM, + SI47XX_AM, + SI47XX_LSB, + SI47XX_USB, + SI47XX_CW, +} SI47XX_MODE; + +typedef enum { + SI47XX_BW_6_kHz, + SI47XX_BW_4_kHz, + SI47XX_BW_3_kHz, + SI47XX_BW_2_kHz, + SI47XX_BW_1_kHz, + SI47XX_BW_1_8_kHz, + SI47XX_BW_2_5_kHz, +} SI47XX_FilterBW; + +typedef enum { + SI47XX_SSB_BW_1_2_kHz, + SI47XX_SSB_BW_2_2_kHz, + SI47XX_SSB_BW_3_kHz, + SI47XX_SSB_BW_4_kHz, + SI47XX_SSB_BW_0_5_kHz, + SI47XX_SSB_BW_1_0_kHz, +} SI47XX_SsbFilterBW; + +typedef enum { + CMD_POWER_UP = 0x01, + CMD_GET_REV = 0x10, + CMD_POWER_DOWN = 0x11, + CMD_SET_PROPERTY = 0x12, + CMD_GET_PROPERTY = 0x13, + CMD_GET_INT_STATUS = 0x14, + CMD_PATCH_ARGS = 0x15, + CMD_PATCH_DATA = 0x16, + CMD_FM_TUNE_FREQ = 0x20, + CMD_FM_SEEK_START = 0x21, + CMD_FM_TUNE_STATUS = 0x22, + CMD_FM_RSQ_STATUS = 0x23, + CMD_FM_RDS_STATUS = 0x24, + CMD_FM_AGC_STATUS = 0x27, + CMD_FM_AGC_OVERRIDE = 0x28, + CMD_TX_TUNE_FREQ = 0x30, + CMD_TX_TUNE_POWER = 0x31, + CMD_TX_TUNE_MEASURE = 0x32, + CMD_TX_TUNE_STATUS = 0x33, + CMD_TX_ASQ_STATUS = 0x34, + CMD_TX_RDS_BUF = 0x35, + CMD_TX_RDS_PS = 0x36, + CMD_AM_TUNE_FREQ = 0x40, + CMD_AM_SEEK_START = 0x41, + CMD_AM_TUNE_STATUS = 0x42, + CMD_AM_RSQ_STATUS = 0x43, + CMD_AM_AGC_STATUS = 0x47, + CMD_AM_AGC_OVERRIDE = 0x48, + CMD_WB_TUNE_FREQ = 0x50, + CMD_WB_TUNE_STATUS = 0x52, + CMD_WB_RSQ_STATUS = 0x53, + CMD_WB_SAME_STATUS = 0x54, + CMD_WB_ASQ_STATUS = 0x55, + CMD_WB_AGC_STATUS = 0x57, + CMD_WB_AGC_OVERRIDE = 0x58, + CMD_AUX_ASRC_START = 0x61, + CMD_AUX_ASQ_STATUS = 0x65, + CMD_GPIO_CTL = 0x80, + CMD_GPIO_SET = 0x81, +} SI47XX_Commands; + +typedef enum { + FLG_CTSIEN = 0x80, + FLG_GPO2IEN = 0x40, + FLG_PATCH = 0x20, + FLG_XOSCEN = 0x10, + FLG_FREEZE = 0x02, + FLG_FAST = 0x01, + FLG_SEEKUP = 0x08, + FLG_WRAP = 0x04, + FLG_CANCEL = 0x02, + FLG_INTACK = 0x01, + FLG_STATUSONLY = 0x04, + FLG_MTFIFO = 0x02, + FLG_GPO3OEN = 0x08, + FLG_GPO2OEN = 0x04, + FLG_GPO1OEN = 0x02, + FLG_GPO3LEVEL = 0x08, + FLG_GPO2LEVEL = 0x04, + FLG_GPO1LEVEL = 0x02, + FLG_BLETHA_0 = 0x00, + FLG_BLETHA_12 = 0x40, + FLG_BLETHA_35 = 0x80, + FLG_BLETHA_U = FLG_BLETHA_12 | FLG_BLETHA_35, + FLG_BLETHB_0 = FLG_BLETHA_0, + FLG_BLETHB_12 = 0x10, + FLG_BLETHB_35 = 0x20, + FLG_BLETHB_U = FLG_BLETHB_12 | FLG_BLETHB_35, + FLG_BLETHC_0 = FLG_BLETHA_0, + FLG_BLETHC_12 = 0x04, + FLG_BLETHC_35 = 0x08, + FLG_BLETHC_U = FLG_BLETHC_12 | FLG_BLETHC_35, + FLG_BLETHD_0 = FLG_BLETHA_0, + FLG_BLETHD_12 = 0x01, + FLG_BLETHD_35 = 0x02, + FLG_BLETHD_U = FLG_BLETHD_12 | FLG_BLETHD_35, + FLG_RDSEN = 0x01, + FLG_DEEMPH_NONE = 0x00, + FLG_DEEMPH_50 = 0x01, + FLG_DEEMPH_75 = 0x02, + FLG_RSQREP = 0x08, + FLG_RDSREP = 0x04, + FLG_STCREP = 0x01, + FLG_ERRIEN = 0x40, + FLG_RSQIEN = 0x08, + FLG_RDSIEN = 0x04, + FLG_STCIEN = 0x01, + FLG_RDSNEWBLOCKB = 0x20, + FLG_RDSNEWBLOCKA = 0x10, + FLG_RDSSYNCFOUND = 0x04, + FLG_RDSSYNCLOST = 0x02, + FLG_RDSRECV = 0x01, + FLG_GRPLOST = 0x04, + FLG_RDSSYNC = 0x01, + FLG_AMPLFLT = 0x01, + FLG_AMCHFLT_6KHZ = 0x00, + FLG_AMCHFLT_4KHZ = 0x01, + FLG_AMCHFLT_3KHZ = 0x02, + FLG_AMCHFLT_2KHZ = 0x03, + FLG_AMCHFLT_1KHZ = 0x04, + FLG_AMCHFLT_1KHZ8 = 0x05, + FLG_AMCHFLT_2KHZ5 = 0x06, +} SI47XX_Flags; + +// Define Si4735 Function modes +typedef enum { + FUNC_FM = 0x00, + FUNC_AM = 0x01, + FUNC_VER = 0x0F, +} SI47XX_FunctionModes; + +// Define Si4735 Output modes +typedef enum { + OUT_RDS = 0x00, // RDS only + OUT_ANALOG = 0x05, + OUT_DIGITAL1 = 0x0B, // DCLK, LOUT/DFS, ROUT/DIO + OUT_DIGITAL2 = 0xB0, // DCLK, DFS, DIO + OUT_BOTH = OUT_ANALOG | OUT_DIGITAL2, +} SI47XX_OutputModes; + +typedef union { + struct { + uint8_t AUDIOBW : 4; //!< 0 = 1.2kHz (default); 1=2.2kHz; 2=3kHz; 3=4kHz; + //!< 4=500Hz; 5=1kHz + uint8_t SBCUTFLT : 4; //!< SSB side band cutoff filter for band passand low + //!< pass filter + uint8_t AVC_DIVIDER : 4; //!< set 0 for SSB mode; set 3 for SYNC mode; + uint8_t AVCEN : 1; //!< SSB Automatic Volume Control (AVC) enable; + //!< 0=disable; 1=enable (default); + uint8_t SMUTESEL : 1; //!< SSB Soft-mute Based on RSSI or SNR + uint8_t DUMMY1 : 1; //!< Always write 0; + uint8_t + DSP_AFCDIS : 1; //!< 0=SYNC MODE, AFC enable; 1=SSB MODE, AFC disable. + } param; + uint8_t raw[2]; +} SsbMode; + +// Define Si47xx Status flag masks (bits the chip fed us) +typedef enum { + STATUS_CTS = 0x80, + STATUS_ERR = 0x40, + STATUS_RSQINT = 0x08, + STATUS_RDSINT = 0x04, + STATUS_ASQINT = 0x02, + STATUS_STCINT = 0x01, + STATUS_BLTF = 0x80, + STATUS_AFCRL = 0x02, + STATUS_VALID = 0x01, + STATUS_BLENDINT = 0x80, + STATUS_MULTHINT = 0x20, + STATUS_MULTLINT = 0x10, + STATUS_SNRHINT = 0x08, + STATUS_SNRLINT = 0x04, + STATUS_RSSIHINT = 0x02, + STATUS_RSSILINT = 0x01, + STATUS_SMUTE = 0x08, + STATUS_PILOT = 0x80, + STATUS_OVERMOD = 0x04, + STATUS_IALH = 0x02, + STATUS_IALL = 0x01, +} SI47XX_StatusFlagMasks; + +// Define Si47xx Property codes +typedef enum { + PROP_GPO_IEN = (uint16_t)0x0001, + PROP_DIGITAL_INPUT_FORMAT = 0x0101, + PROP_DIGITAL_OUTPUT_FORMAT = 0x0102, + PROP_DIGITAL_INPUT_SAMPLE_RATE = 0x0103, + PROP_DIGITAL_OUTPUT_SAMPLE_RATE = 0x0104, + PROP_REFCLK_FREQ = 0x0201, + PROP_REFCLK_PRESCALE = 0x0202, + PROP_FM_DEEMPHASIS = 0x1100, + PROP_FM_CHANNEL_FILTER = 0x1102, + PROP_FM_BLEND_STEREO_THRESHOLD = 0x1105, + PROP_FM_BLEND_MONO_THRESHOLD = 0x1106, + PROP_FM_ANTENNA_INPUT = 0x1107, + PROP_FM_MAX_TUNE_ERROR = 0x1108, + PROP_FM_RSQ_INT_SOURCE = 0x1200, + PROP_FM_RSQ_SNR_HI_THRESHOLD = 0x1201, + PROP_FM_RSQ_SNR_LO_THRESHOLD = 0x1202, + PROP_FM_RSQ_RSSI_HI_THRESHOLD = 0x1203, + PROP_FM_RSQ_RSSI_LO_THRESHOLD = 0x1204, + PROP_FM_RSQ_MULTIPATH_HI_THRESHOLD = 0x1205, + PROP_FM_RSQ_MULTIPATH_LO_THRESHOLD = 0x1206, + PROP_FM_RSQ_BLEND_THRESHOLD = 0x1207, + PROP_FM_SOFT_MUTE_RATE = 0x1300, + PROP_FM_SOFT_MUTE_SLOPE = 0x1301, + PROP_FM_SOFT_MUTE_MAX_ATTENUATION = 0x1302, + PROP_FM_SOFT_MUTE_SNR_THRESHOLD = 0x1303, + PROP_FM_SOFT_MUTE_RELEASE_RATE = 0x1304, + PROP_FM_SOFT_MUTE_ATTACK_RATE = 0x1305, + PROP_FM_SEEK_BAND_BOTTOM = 0x1400, + PROP_FM_SEEK_BAND_TOP = 0x1401, + PROP_FM_SEEK_FREQ_SPACING = 0x1402, + PROP_FM_SEEK_TUNE_SNR_THRESHOLD = 0x1403, + PROP_FM_SEEK_TUNE_RSSI_THRESHOLD = 0x1404, + PROP_FM_RDS_INT_SOURCE = 0x1500, + PROP_FM_RDS_INT_FIFO_COUNT = 0x1501, + PROP_FM_RDS_CONFIG = 0x1502, + PROP_FM_RDS_CONFIDENCE = 0x1503, + PROP_FM_AGC_ATTACK_RATE = 0x1700, + PROP_FM_AGC_RELEASE_RATE = 0x1701, + PROP_FM_BLEND_RSSI_STEREO_THRESHOLD = 0x1800, + PROP_FM_BLEND_RSSI_MONO_THRESHOLD = 0x1801, + PROP_FM_BLEND_RSSI_ATTACK_RATE = 0x1802, + PROP_FM_BLEND_RSSI_RELEASE_RATE = 0x1803, + PROP_FM_BLEND_SNR_STEREO_THRESHOLD = 0x1804, + PROP_FM_BLEND_SNR_MONO_THRESHOLD = 0x1805, + PROP_FM_BLEND_SNR_ATTACK_RATE = 0x1806, + PROP_FM_BLEND_SNR_RELEASE_RATE = 0x1807, + PROP_FM_BLEND_MULTIPATH_STEREO_THRESHOLD = 0x1808, + PROP_FM_BLEND_MULTIPATH_MONO_THRESHOLD = 0x1809, + PROP_FM_BLEND_MULTIPATH_ATTACK_RATE = 0x180A, + PROP_FM_BLEND_MULTIPATH_RELEASE_RATE = 0x180B, + PROP_FM_BLEND_MAX_STEREO_SEPARATION = 0x180C, + PROP_FM_NB_DETECT_THRESHOLD = 0x1900, + PROP_FM_NB_INTERVAL = 0x1901, + PROP_FM_NB_RATE = 0x1902, + PROP_FM_NB_IIR_FILTER = 0x1903, + PROP_FM_NB_DELAY = 0x1904, + PROP_FM_HICUT_SNR_HIGH_THRESHOLD = 0x1A00, + PROP_FM_HICUT_SNR_LOW_THRESHOLD = 0x1A01, + PROP_FM_HICUT_ATTACK_RATE = 0x1A02, + PROP_FM_HICUT_RELEASE_RATE = 0x1A03, + PROP_FM_HICUT_MULTIPATH_TRIGGER_THRESHOLD = 0x1A04, + PROP_FM_HICUT_MULTIPATH_END_THRESHOLD = 0x1A05, + PROP_FM_HICUT_CUTOFF_FREQUENCY = 0x1A06, + PROP_TX_COMPONENT_ENABLE = 0x2100, + PROP_TX_AUDIO_DEVIATION = 0x2101, + PROP_TX_PILOT_DEVIATION = 0x2102, + PROP_TX_RDS_DEVIATION = 0x2103, + PROP_TX_LINE_INPUT_LEVEL = 0x2104, + PROP_TX_LINE_INPUT_MUTE = 0x2105, + PROP_TX_PREEMPHASIS = 0x2106, + PROP_TX_PILOT_FREQUENCY = 0x2107, + PROP_TX_ACOMP_ENABLE = 0x2200, + PROP_TX_ACOMP_THRESHOLD = 0x2201, + PROP_TX_ACOMP_ATTACK_TIME = 0x2202, + PROP_TX_ACOMP_RELEASE_TIME = 0x2203, + PROP_TX_ACOMP_GAIN = 0x2204, + PROP_TX_LIMITER_RELEASE_TIME = 0x2205, + PROP_TX_ASQ_INTERRUPT_SOURCE = 0x2300, + PROP_TX_ASQ_LEVEL_LOW = 0x2301, + PROP_TX_ASQ_DURATION_LOW = 0x2302, + PROP_TX_ASQ_LEVEL_HIGH = 0x2303, + PROP_TX_ASQ_DURATION_HIGH = 0x2304, + PROP_TX_RDS_INTERRUPT_SOURCE = 0x2C00, + PROP_TX_RDS_PI = 0x2C01, + PROP_TX_RDS_PS_MIX = 0x2C02, + PROP_TX_RDS_PS_MISC = 0x2C03, + PROP_TX_RDS_PS_REPEAT_COUNT = 0x2C04, + PROP_TX_RDS_PS_MESSAGE_COUNT = 0x2C05, + PROP_TX_RDS_PS_AF = 0x2C06, + PROP_TX_RDS_FIFO_SIZE = 0x2C07, + PROP_AM_DEEMPHASIS = 0x3100, + PROP_AM_CHANNEL_FILTER = 0x3102, + PROP_AM_AUTOMATIC_VOLUME_CONTROL_MAX_GAIN = 0x3103, + PROP_AM_MODE_AFC_SW_PULL_IN_RANGE = 0x3104, + PROP_AM_MODE_AFC_SW_LOCK_IN_RANGE = 0x3105, + PROP_AM_RSQ_INTERRUPTS = 0x3200, + PROP_AM_RSQ_SNR_HIGH_THRESHOLD = 0x3201, + PROP_AM_RSQ_SNR_LOW_THRESHOLD = 0x3202, + PROP_AM_RSQ_RSSI_HIGH_THRESHOLD = 0x3203, + PROP_AM_RSQ_RSSI_LOW_THRESHOLD = 0x3204, + PROP_AM_SOFT_MUTE_RATE = 0x3300, + PROP_AM_SOFT_MUTE_SLOPE = 0x3301, + PROP_AM_SOFT_MUTE_MAX_ATTENUATION = 0x3302, + PROP_AM_SOFT_MUTE_SNR_THRESHOLD = 0x3303, + PROP_AM_SOFT_MUTE_RELEASE_RATE = 0x3304, + PROP_AM_SOFT_MUTE_ATTACK_RATE = 0x3305, + PROP_AM_SEEK_BAND_BOTTOM = 0x3400, + PROP_AM_SEEK_BAND_TOP = 0x3401, + PROP_AM_SEEK_FREQ_SPACING = 0x3402, + PROP_AM_SEEK_TUNE_SNR_THRESHOLD = 0x3403, + PROP_AM_SEEK_TUNE_RSSI_THRESHOLD = 0x3404, + PROP_AM_AGC_ATTACK_RATE = 0x3702, + PROP_AM_AGC_RELEASE_RATE = 0x3703, + PROP_AM_FRONTEND_AGC_CONTROL = 0x3705, + PROP_AM_NB_DETECT_THRESHOLD = 0x3900, + PROP_AM_NB_INTERVAL = 0x3901, + PROP_AM_NB_RATE = 0x3902, + PROP_AM_NB_IIR_FILTER = 0x3903, + PROP_AM_NB_DELAY = 0x3904, + PROP_RX_VOLUME = 0x4000, + PROP_RX_HARD_MUTE = 0x4001, + PROP_WB_MAX_TUNE_ERROR = 0x5108, + PROP_WB_RSQ_INT_SOURCE = 0x5200, + PROP_WB_RSQ_SNR_HI_THRESHOLD = 0x5201, + PROP_WB_RSQ_SNR_LO_THRESHOLD = 0x5202, + PROP_WB_RSQ_RSSI_HI_THRESHOLD = 0x5203, + PROP_WB_RSQ_RSSI_LO_THRESHOLD = 0x5204, + PROP_WB_VALID_SNR_THRESHOLD = 0x5403, + PROP_WB_VALID_RSSI_THRESHOLD = 0x5404, + PROP_WB_SAME_INTERRUPT_SOURCE = 0x5500, + PROP_WB_ASQ_INTERRUPT_SOURCE = 0x5600, + PROP_AUX_ASQ_INTERRUPT_SOURCE = 0x6600, + PROP_DEBUG_CONTROL = 0xFF00, + PROP_AM_RSQ_INT_SOURCE = 0x3200, + PROP_WB_SAME_INT_SOURCE = 0x5500, // Si4707 only + PROP_WB_ASQ_INT_SOURCE = 0x5600, + PROP_AUX_ASQ_INT_SOURCE = 0x6600, // AUX mode - Si4735-D60 or later + + PROP_SSB_BFO = 0x0100, // Sets the Beat Frequency Offset (BFO) under SSB mode. + PROP_SSB_MODE = 0x0101, // Sets number of properties of the SSB mode. + PROP_SSB_RSQ_INTERRUPTS = 0x3200, // Configure Interrupts related to RSQ + PROP_SSB_RSQ_SNR_HI_THRESHOLD = + 0x3201, // Sets high threshold for SNR interrupt + PROP_SSB_RSQ_SNR_LO_THRESHOLD = + 0x3202, // Sets low threshold for SNR interrupt + PROP_SSB_RSQ_RSSI_HI_THRESHOLD = + 0x3203, // Sets high threshold for RSSI interrupt + PROP_SSB_RSQ_RSSI_LO_THRESHOLD = + 0x3204, // Sets low threshold for RSSI interrupt + PROP_SSB_SOFT_MUTE_RATE = 0x3300, // Sets the attack and decay rates when + // entering or leaving soft mute + PROP_SSB_SOFT_MUTE_MAX_ATTENUATION = + 0x3302, // Sets the maximum attenuation during soft mute (db); 0dB to + // disable soft mute; defaul 8dB; + PROP_SSB_SOFT_MUTE_SNR_THRESHOLD = + 0x3303, // Sets SNR threshould to engage soft mute. Defaul 8dB + PROP_SSB_RF_AGC_ATTACK_RATE = + 0x3700, // Sets the number of milliseconds the high RF peak detector must + // be exceeded before decreasing the gain. Defaul 4. + PROP_SSB_RF_AGC_RELEASE_RATE = + 0x3701, // Sets the number of milliseconds the low RF peak detector must + // be exceeded before increasing the gain. Defaul 24. + PROP_SSB_IF_AGC_RELEASE_RATE = + 0x3703, // Sets the number of milliseconds the low IF peak detector must + // not be exceeded before increasing the gain. Default value is + // 140 (approximately 40 dB / s). + PROP_SSB_IF_AGC_ATTACK_RATE = + 0x3702, // Sets the number of milliseconds the high IF peak detector must + // be exceeded before decreasing gain. Default value is 4 + // (approximately 1400 dB / s). + +} SI47XX_PropertyCodes; + +enum { + // POWER_UP + /* See POWER_UP_AUDIO_OUT constants above for ARG2. */ + POWER_UP_ARG1_CTSIEN = 0b10000000, // CTS interrupt enable + POWER_UP_ARG1_GPO2OEN = 0b01000000, // GPO2/INT output enable + POWER_UP_ARG1_PATCH = 0b00100000, // Patch enable + POWER_UP_ARG1_XOSCEN = + 0b00010000, // Enable internal oscillator with external 32768 Hz crystal + POWER_UP_ARG1_FUNC_FM = 0x0, // FM receive mode + POWER_UP_ARG1_FUNC_AM = 0x1, // AM receive mode + POWER_UP_ARG1_FUNC_TX = 0x2, // FM transmit mode - not Si4735 or Si4707 + POWER_UP_ARG1_FUNC_WB = 0x3, // WB receive mode - not Si4735 + POWER_UP_ARG1_FUNC_AUX = 0x4, // Auxiliary input mode - Si4735-D60 or later + POWER_UP_ARG1_FUNC_REV = 0xF, // Query chip's hardware and firmware revisions + // FM_TUNE_FREQ, AM_TUNE_FREQ + FM_TUNE_FREQ_ARG1_FREEZE = 0b10, + TUNE_FREQ_ARG1_FAST = 0b01, // Fast, inaccurate tune + // FM_SEEK_START, AM_SEEK_START + SEEK_START_ARG1_SEEK_UP = 0b1000, // 1 = Seek up, 0 = Seek down + SEEK_START_ARG1_WRAP = 0b0100, // Wrap when band limit reached + // FM_TUNE_STATUS, AM_TUNE_STATUS, WB_TUNE_STATUS + TUNE_STATUS_ARG1_CANCEL_SEEK = 0b10, // Cancel seek operation - not WB + TUNE_STATUS_ARG1_CLEAR_INT = 0b01, // Clear STC interrupt + // FM_RSQ_STATUS, AM_RSQ_STATUS, WB_RSQ_STATUS + RSQ_STATUS_ARG1_CLEAR_INT = 0b1, // Clear RSQ and related interrupts + // FM_RDS_STATUS + RDS_STATUS_ARG1_STATUS_ONLY = 0b100, + RDS_STATUS_ARG1_CLEAR_FIFO = 0b010, // Clear RDS receive FIFO + RDS_STATUS_ARG1_CLEAR_INT = 0b001, // Clear RDS interrupt + // WB_SAME_STATUS + SAME_STATUS_ARG1_CLEAR_BUFFER = 0b10, // Clear SAME receive buffer + SAME_STATUS_ARG1_CLEAR_INT = 0b01, // Clear SAME interrupt + // AUX_ASQ_STATUS, WB_ASQ_STATUS + ASQ_STATUS_ARG1_CLEAR_INT = 0b1, // Clear ASQ interrupt + // FM_AGC_OVERRIDE, AM_AGC_OVERRIDE, WB_AGC_OVERRIDE + AGC_OVERRIDE_ARG1_DISABLE_AGC = 0b1, // Disable AGC + // GPIO_CTL, GPIO_SET + GPIO_ARG1_GPO3 = 0b1000, // GPO3 + GPIO_ARG1_GPO2 = 0b0100, // GPO2 + GPIO_ARG1_GPO1 = 0b0010, // GPO1 +}; + +// Command responses +// Names that begin with FIELD are argument masks. Others are argument +// constants. +enum { + // FM_TUNE_STATUS, AM_TUNE_STATUS, WB_TUNE_STATUS + FIELD_TUNE_STATUS_RESP1_SEEK_LIMIT = + 0b10000000, // Seek hit search limit - not WB + FIELD_TUNE_STATUS_RESP1_AFC_RAILED = 0b10, // AFC railed + FIELD_TUNE_STATUS_RESP1_SEEKABLE = + 0b01, // Station could currently be found by seek, + FIELD_TUNE_STATUS_RESP1_VALID = 0b01, // that is, the station is valid + // FM_RSQ_STATUS, AM_RSQ_STATUS, WB_RSQ_STATUS + /* See RSQ interrupts above for RESP1. */ + FIELD_RSQ_STATUS_RESP2_SOFT_MUTE = 0b1000, // Soft mute active - not WB + FIELD_RSQ_STATUS_RESP2_AFC_RAILED = 0b0010, // AFC railed + FIELD_RSQ_STATUS_RESP2_SEEKABLE = + 0b0001, // Station could currently be found by seek, + FIELD_RSQ_STATUS_RESP2_VALID = 0b0001, // that is, the station is valid + FIELD_RSQ_STATUS_RESP3_STEREO = 0b10000000, // Stereo pilot found - FM only + FIELD_RSQ_STATUS_RESP3_STEREO_BLEND = + 0b01111111, // Stereo blend in % (100 = full stereo, 0 = full mono) - FM + // only + // FM_RDS_STATUS + /* See RDS interrupts above for RESP1. */ + FIELD_RDS_STATUS_RESP2_FIFO_OVERFLOW = 0b00000100, // FIFO overflowed + FIELD_RDS_STATUS_RESP2_SYNC = 0b00000001, // RDS currently synchronized + FIELD_RDS_STATUS_RESP12_BLOCK_A = 0b11000000, + FIELD_RDS_STATUS_RESP12_BLOCK_B = 0b00110000, + FIELD_RDS_STATUS_RESP12_BLOCK_C = 0b00001100, + FIELD_RDS_STATUS_RESP12_BLOCK_D = 0b00000011, + RDS_STATUS_RESP12_BLOCK_A_NO_ERRORS = 0U << 6, // Block had no errors + RDS_STATUS_RESP12_BLOCK_A_2_BIT_ERRORS = 1U << 6, // Block had 1-2 bit errors + RDS_STATUS_RESP12_BLOCK_A_5_BIT_ERRORS = 2U << 6, // Block had 3-5 bit errors + RDS_STATUS_RESP12_BLOCK_A_UNCORRECTABLE = 3U << 6, // Block was uncorrectable + RDS_STATUS_RESP12_BLOCK_B_NO_ERRORS = 0U << 4, + RDS_STATUS_RESP12_BLOCK_B_2_BIT_ERRORS = 1U << 4, + RDS_STATUS_RESP12_BLOCK_B_5_BIT_ERRORS = 2U << 4, + RDS_STATUS_RESP12_BLOCK_B_UNCORRECTABLE = 3U << 4, + RDS_STATUS_RESP12_BLOCK_C_NO_ERRORS = 0U << 2, + RDS_STATUS_RESP12_BLOCK_C_2_BIT_ERRORS = 1U << 2, + RDS_STATUS_RESP12_BLOCK_C_5_BIT_ERRORS = 2U << 2, + RDS_STATUS_RESP12_BLOCK_C_UNCORRECTABLE = 3U << 2, + RDS_STATUS_RESP12_BLOCK_D_NO_ERRORS = 0U << 0, + RDS_STATUS_RESP12_BLOCK_D_2_BIT_ERRORS = 1U << 0, + RDS_STATUS_RESP12_BLOCK_D_5_BIT_ERRORS = 2U << 0, + RDS_STATUS_RESP12_BLOCK_D_UNCORRECTABLE = 3U << 0, + // WB_SAME_STATUS - TODO + + // AUX_ASQ_STATUS, WB_ASQ_STATUS + /* See ASQ interrupts above for RESP1. */ + FIELD_AUX_ASQ_STATUS_RESP2_OVERLOAD = + 0b1, // Audio input is currently overloading ADC + FIELD_WB_ASQ_STATUS_RESP2_ALERT = 0b1, // Alert tone is present + // FM_AGC_STATUS, AM_AGC_STATUS, WB_AGC_STATUS + FIELD_AGC_STATUS_RESP1_DISABLE_AGC = 0b1, // True if AGC disabled +}; + +typedef union { + struct { + // status ("RESP0") + uint8_t STCINT : 1; + uint8_t DUMMY1 : 1; + uint8_t RDSINT : 1; + uint8_t RSQINT : 1; + uint8_t DUMMY2 : 2; + uint8_t ERR : 1; + uint8_t CTS : 1; + // RESP1 + uint8_t RSSIILINT : 1; //!< RSSI Detect Low. + uint8_t RSSIHINT : 1; //!< RSSI Detect High. + uint8_t SNRLINT : 1; //!< SNR Detect Low. + uint8_t SNRHINT : 1; //!< SNR Detect High. + uint8_t MULTLINT : 1; //!< Multipath Detect Low + uint8_t MULTHINT : 1; //!< Multipath Detect High + uint8_t DUMMY3 : 1; + uint8_t BLENDINT : 1; //!< Blend Detect Interrupt. + // RESP2 + uint8_t VALID : 1; //!< Valid Channel. + uint8_t AFCRL : 1; //!< AFC Rail Indicator. + uint8_t DUMMY4 : 1; + uint8_t + SMUTE : 1; //!< Soft Mute Indicator. Indicates soft mute is engaged. + uint8_t DUMMY5 : 4; + // RESP3 + uint8_t STBLEND : 7; //!< Indicates amount of stereo blend in% (100 = full + //!< stereo, 0 = full mono). + uint8_t PILOT : 1; //!< Indicates stereo pilot presence. + // RESP4 to RESP7 + uint8_t RSSI; //!< RESP4 - Contains the current receive signal strength + //!< (0–127 dBμV). + uint8_t SNR; //!< RESP5 - Contains the current SNR metric (0–127 dB). + uint8_t MULT; //!< RESP6 - Contains the current multipath metric. (0 = no + //!< multipath; 100 = full multipath) + uint8_t FREQOFF; //!< RESP7 - Signed frequency offset (kHz). + } resp; + uint8_t raw[8]; +} RSQStatus; + +typedef union { + struct { + // ARG1 + uint8_t AGCDIS : 1; // if set to 1 indicates if the AGC is disabled. 0 = AGC + // enabled; 1 = AGC disabled. + uint8_t DUMMY : 7; + // ARG2 + uint8_t AGCIDX; // AGC Index; If AMAGCDIS = 1, this byte forces the AGC gain + // index; 0 = Minimum attenuation (max gain) + } arg; + uint8_t raw[2]; +} SI47XX_AgcOverrride; + +typedef union { + struct { + uint8_t + FAST : 1; //!< ARG1 - FAST Tuning. If set, executes fast and + //!< invalidated tune. The tune status will not be accurate. + uint8_t FREEZE : 1; //!< Valid only for FM (Must be 0 to AM) + uint8_t DUMMY1 : 4; //!< Always set 0 + uint8_t + USBLSB : 2; //!< SSB Upper Side Band (USB) and Lower Side Band (LSB) + //!< Selection. 10 = USB is selected; 01 = LSB is selected. + uint8_t FREQH; //!< ARG2 - Tune Frequency High byte. + uint8_t FREQL; //!< ARG3 - Tune Frequency Low byte. + uint8_t ANTCAPH; //!< ARG4 - Antenna Tuning Capacitor High byte. + uint8_t ANTCAPL; //!< ARG5 - Antenna Tuning Capacitor Low byte. Note used + //!< for FM. + } arg; + uint8_t raw[5]; +} SI47XX_SetFrequency; + +typedef union { + struct { + uint8_t AMCHFLT : 4; //!< Selects the bandwidth of the AM channel filter. + uint8_t DUMMY1 : 4; + uint8_t AMPLFLT : 1; //!< Enables the AM Power Line Noise Rejection Filter. + uint8_t DUMMY2 : 7; + } param; + uint8_t raw[2]; +} SI47XX_BW_Config; // AM_CHANNEL_FILTER + +void SI47XX_PowerUp(); +void SI47XX_PowerDown(); +void SI47XX_SetFreq(uint16_t freq); +void SI47XX_ReadRDS(uint8_t buf[13]); +void SI47XX_SwitchMode(SI47XX_MODE mode); +bool SI47XX_IsSSB(); +void RSQ_GET(); +void SI47XX_SetAutomaticGainControl(uint8_t AGCDIS, uint8_t AGCIDX); +void SI47XX_Seek(bool up, bool wrap); +uint16_t SI47XX_getFrequency(bool *valid); +void SI47XX_SetBandwidth(SI47XX_FilterBW AMCHFLT, bool AMPLFLT); +void SI47XX_SetSsbBandwidth(SI47XX_SsbFilterBW bw); +void SI47XX_SetSeekFmLimits(uint16_t bottom, uint16_t top); +void SI47XX_SetSeekAmLimits(uint16_t bottom, uint16_t top); +void SI47XX_SetSeekFmSpacing(uint16_t spacing); +void SI47XX_SetSeekAmSpacing(uint16_t spacing); +void SI47XX_SetSeekFmRssiThreshold(uint16_t value); +void SI47XX_SetSeekAmRssiThreshold(uint16_t value); +void SI47XX_SetBFO(int16_t bfo); +void SI47XX_SetSsbCapacitor(uint16_t v); + +extern SI47XX_MODE si4732mode; +extern RSQStatus rsqStatus; +extern uint16_t siCurrentFreq; + +#endif /* end of include guard: SI473X_H */ diff --git a/src/driver/systick.c b/src/driver/systick.c index c44acf8..89e7352 100644 --- a/src/driver/systick.c +++ b/src/driver/systick.c @@ -48,3 +48,24 @@ void SYSTICK_DelayUs(uint32_t Delay) { Previous = Current; } while (i < Delay * tickMultiplier); } + +void SYSTICK_Delay250ns(const uint32_t Delay) { + const uint32_t ticks = (Delay * tickMultiplier) >> 2; + uint32_t i = 0; + uint32_t Start = SysTick->LOAD; + uint32_t Previous = SysTick->VAL; + + do { + uint32_t Delta; + uint32_t Current; + + do + Current = SysTick->VAL; + while (Current == Previous); + + Delta = (Current < Previous) ? -Current : Start - Current; + i += Delta + Previous; + Previous = Current; + + } while (i < ticks); +} diff --git a/src/driver/systick.h b/src/driver/systick.h index 95ba478..7654574 100644 --- a/src/driver/systick.h +++ b/src/driver/systick.h @@ -21,6 +21,6 @@ void SYSTICK_Init(void); void SYSTICK_DelayUs(uint32_t Delay); +void SYSTICK_Delay250ns(const uint32_t Delay); #endif - diff --git a/src/driver/uart.c b/src/driver/uart.c index 664dd27..0f463d5 100644 --- a/src/driver/uart.c +++ b/src/driver/uart.c @@ -1,32 +1,46 @@ -/* Copyright 2023 Dual Tachyon - * https://github.com/DualTachyon - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - #include "../inc/dp32g030/uart.h" +#include "../board.h" +#include "../external/CMSIS_5/Device/ARM/ARMCM0/Include/ARMCM0.h" #include "../external/printf/printf.h" #include "../inc/dp32g030/dma.h" +#include "../inc/dp32g030/gpio.h" #include "../inc/dp32g030/syscon.h" -#include "../misc.h" #include "../scheduler.h" -#include "system.h" +#include "../settings.h" +#include "aes.h" +#include "bk4819.h" +#include "crc.h" +#include "eeprom.h" +#include "gpio.h" #include "uart.h" +#include #include -uint8_t UART_IsLogEnabled = 0; +static const char Version[] = "OSFW-fffffff"; +static const char UART_Version[45] = + "UV-K5 Firmware, Open Edition, OSFW-fffffff\r\n"; + +static bool UART_IsLogEnabled; uint8_t UART_DMA_Buffer[256]; +static bool bHasCustomAesKey = false; +static bool bIsInLockScreen = false; +static bool gIsLocked = false; +static uint8_t gTryCount; +static uint32_t gCustomAesKey[4] = { + 0xFFFFFFFFU, + 0xFFFFFFFFU, + 0xFFFFFFFFU, + 0xFFFFFFFFU, +}; +static const uint32_t gDefaultAesKey[4] = { + 0x4AA5CC60, + 0x0312CC5F, + 0xFFD2DABB, + 0x6BBA7F92, +}; +static uint32_t gChallenge[4]; + void UART_Init(void) { uint32_t Delta; uint32_t Positive; @@ -39,7 +53,11 @@ void UART_Init(void) { SYSCON_RC_FREQ_DELTA_RCHF_SIG_SHIFT; Frequency = (Delta & SYSCON_RC_FREQ_DELTA_RCHF_DELTA_MASK) >> SYSCON_RC_FREQ_DELTA_RCHF_DELTA_SHIFT; - Frequency = Positive ? Frequency + CPU_CLOCK_HZ : CPU_CLOCK_HZ - Frequency; + if (Positive) { + Frequency += 48000000U; + } else { + Frequency = 48000000U - Frequency; + } UART1->BAUD = Frequency / 39053U; UART1->CTRL = UART_CTRL_RXEN_BITS_ENABLE | UART_CTRL_TXEN_BITS_ENABLE | @@ -90,117 +108,619 @@ void UART_Send(const void *pBuffer, uint32_t Size) { } } -void UART_SendText(const void *str) { - if (str) - UART_Send(str, strlen(str)); -} - void UART_LogSend(const void *pBuffer, uint32_t Size) { - if (UART_IsLogEnabled) + if (UART_IsLogEnabled) { UART_Send(pBuffer, Size); + } } -void UART_LogSendText(const void *str) { - if (UART_IsLogEnabled && str) - UART_Send(str, strlen(str)); +#define DMA_INDEX(x, y) (((x) + (y)) % sizeof(UART_DMA_Buffer)) + +typedef struct { + uint16_t ID; + uint16_t Size; +} Header_t; + +typedef struct { + uint8_t Padding[2]; + uint16_t ID; +} Footer_t; + +typedef struct { + Header_t Header; + uint32_t Timestamp; +} CMD_0514_t; + +typedef struct { + Header_t Header; + struct { + char Version[16]; + bool bHasCustomAesKey; + bool bIsInLockScreen; + uint8_t Padding[2]; + uint32_t Challenge[4]; + } Data; +} REPLY_0514_t; + +typedef struct { + Header_t Header; + uint16_t Offset; + uint8_t Size; + uint8_t Padding; + uint32_t Timestamp; +} CMD_051B_t; + +typedef struct { + Header_t Header; + struct { + uint16_t Offset; + uint8_t Size; + uint8_t Padding; + uint8_t Data[128]; + } Data; +} REPLY_051B_t; + +typedef struct { + Header_t Header; + uint16_t Offset; + uint8_t Size; + bool bAllowPassword; + uint32_t Timestamp; + uint8_t Data[0]; +} CMD_051D_t; + +typedef struct { + Header_t Header; + struct { + uint16_t Offset; + } Data; +} REPLY_051D_t; + +typedef struct { + Header_t Header; + struct { + uint16_t RSSI; + uint8_t ExNoiseIndicator; + uint8_t GlitchIndicator; + } Data; +} REPLY_0527_t; + +typedef struct { + Header_t Header; + struct { + uint16_t Voltage; + uint16_t Current; + } Data; +} REPLY_0529_t; + +typedef struct { + Header_t Header; + uint32_t Response[4]; +} CMD_052D_t; + +typedef struct { + Header_t Header; + struct { + bool bIsLocked; + uint8_t Padding[3]; + } Data; +} REPLY_052D_t; + +typedef struct { + Header_t Header; + uint32_t Timestamp; +} CMD_052F_t; + +typedef struct { + Header_t Header; + uint8_t RegNum; +} CMD_0601_t; + +typedef struct { + Header_t Header; + struct { + uint16_t Val; + uint8_t v1; + uint8_t v2; + } Data; +} REPLY_0601_t; + +typedef struct { + Header_t Header; + uint8_t RegNum; + uint16_t RegValue; +} CMD_0602_t; + +typedef struct { + Header_t Header; + struct { + uint16_t Val; + uint8_t v1; + uint8_t v2; + } Data; +} REPLY_0602_t; + +static const uint8_t Obfuscation[16] = {0x16, 0x6C, 0x14, 0xE6, 0x2E, 0x91, + 0x0D, 0x40, 0x21, 0x35, 0xD5, 0x40, + 0x13, 0x03, 0xE9, 0x80}; + +static union { + uint8_t Buffer[256]; + struct { + Header_t Header; + uint8_t Data[252]; + }; +} UART_Command; + +static uint32_t Timestamp; +static uint16_t gUART_WriteIndex; +static bool bIsEncrypted = true; + +static Header_t Header; +static Footer_t Footer; +static uint8_t *pBytes; +static void SendReply(void *pReply, uint16_t Size) { + uint16_t i; + + if (bIsEncrypted) { + pBytes = (uint8_t *)pReply; + for (i = 0; i < Size; i++) { + pBytes[i] ^= Obfuscation[i % 16]; + } + } + + Header.ID = 0xCDAB; + Header.Size = Size; + UART_Send(&Header, sizeof(Header)); + UART_Send(pReply, Size); + if (bIsEncrypted) { + Footer.Padding[0] = Obfuscation[(Size + 0) % 16] ^ 0xFF; + Footer.Padding[1] = Obfuscation[(Size + 1) % 16] ^ 0xFF; + } else { + Footer.Padding[0] = 0xFF; + Footer.Padding[1] = 0xFF; + } + Footer.ID = 0xBADC; + + UART_Send(&Footer, sizeof(Footer)); } -static char sendBuffer[512] = {0}; -static uint32_t sendBufferIndex = 0; +static void SendVersion(void) { + REPLY_0514_t Reply; + + Reply.Header.ID = 0x0515; + Reply.Header.Size = sizeof(Reply.Data); + strcpy(Reply.Data.Version, Version); + Reply.Data.bHasCustomAesKey = bHasCustomAesKey; + Reply.Data.bIsInLockScreen = bIsInLockScreen; + Reply.Data.Challenge[0] = gChallenge[0]; + Reply.Data.Challenge[1] = gChallenge[1]; + Reply.Data.Challenge[2] = gChallenge[2]; + Reply.Data.Challenge[3] = gChallenge[3]; -void UART_flush() { - UART_Send(sendBuffer, sendBufferIndex); - sendBufferIndex = 0; + SendReply(&Reply, sizeof(Reply)); } -void UART_printf(const char *str, ...) { - char text[128]; - int len; +static bool IsBadChallenge(const uint32_t *pKey, const uint32_t *pIn, + const uint32_t *pResponse) { + uint8_t i; + uint32_t IV[4]; + + IV[0] = 0; + IV[1] = 0; + IV[2] = 0; + IV[3] = 0; + AES_Encrypt(pKey, IV, pIn, IV, true); + for (i = 0; i < 4; i++) { + if (IV[i] != pResponse[i]) { + return true; + } + } - va_list va; - va_start(va, str); - len = vsnprintf(text, sizeof(text), str, va); - va_end(va); + return false; +} - memcpy(sendBuffer + sendBufferIndex, text, len); - sendBufferIndex += len; +static void CMD_0514(const uint8_t *pBuffer) { + const CMD_0514_t *pCmd = (const CMD_0514_t *)pBuffer; - if (sendBufferIndex >= 384) { - UART_flush(); + Timestamp = pCmd->Timestamp; + GPIO_ClearBit(&GPIOB->DATA, GPIOB_PIN_BACKLIGHT); + SendVersion(); +} + +static void CMD_051B(const uint8_t *pBuffer) { + const CMD_051B_t *pCmd = (const CMD_051B_t *)pBuffer; + REPLY_051B_t Reply; + bool bLocked = false; + + if (pCmd->Timestamp != Timestamp) { + return; } + + memset(&Reply, 0, sizeof(Reply)); + Reply.Header.ID = 0x051C; + Reply.Header.Size = pCmd->Size + 4; + Reply.Data.Offset = pCmd->Offset; + Reply.Data.Size = pCmd->Size; + + if (bHasCustomAesKey) { + bLocked = gIsLocked; + } + + if (!bLocked) { + EEPROM_ReadBuffer(pCmd->Offset, Reply.Data.Data, pCmd->Size); + } + + SendReply(&Reply, pCmd->Size + 8); } -void UART_ToggleLog(bool on) { - if (on && UART_IsLogEnabled < 5) { - UART_IsLogEnabled++; +static void CMD_051D(const uint8_t *pBuffer) { + const CMD_051D_t *pCmd = (const CMD_051D_t *)pBuffer; + REPLY_051D_t Reply; + bool bReloadEeprom; + bool bIsLocked; + + if (pCmd->Timestamp != Timestamp) { + return; } - if (!on && UART_IsLogEnabled > 0) { - UART_IsLogEnabled--; + + bReloadEeprom = false; + + Reply.Header.ID = 0x051E; + Reply.Header.Size = sizeof(Reply.Data); + Reply.Data.Offset = pCmd->Offset; + + bIsLocked = bHasCustomAesKey; + if (bHasCustomAesKey) { + bIsLocked = gIsLocked; } + + if (!bIsLocked) { + uint16_t i; + + for (i = 0; i < (pCmd->Size / 8U); i++) { + uint16_t Offset = pCmd->Offset + (i * 8U); + + if (Offset >= 0x0F30 && Offset < 0x0F40) { + if (!gIsLocked) { + bReloadEeprom = true; + } + } + + if ((Offset < 0x0E98 || Offset >= 0x0EA0) || !bIsInLockScreen || + pCmd->bAllowPassword) { + EEPROM_WriteBuffer(Offset, &pCmd->Data[i * 8U], 8); + } + } + + /* if (bReloadEeprom) { + BOARD_EEPROM_Init(); + } */ + } + + SendReply(&Reply, sizeof(Reply)); } -void UART_logf(uint8_t level, const char *pattern, ...) { - if (UART_IsLogEnabled >= level) { - char text[128]; - va_list args; - va_start(args, pattern); - vsnprintf(text, sizeof(text), pattern, args); - va_end(args); - UART_printf("%u %s\n", elapsedMilliseconds, text); +static void CMD_061D(const uint8_t *pBuffer) { + const CMD_051D_t *pCmd = (const CMD_051D_t *)pBuffer; + REPLY_051D_t Reply; + bool bReloadEeprom; + bool bIsLocked; + + if (pCmd->Timestamp != Timestamp) { + return; } + + bReloadEeprom = false; + + Reply.Header.ID = 0x061E; + Reply.Header.Size = sizeof(Reply.Data); + Reply.Data.Offset = pCmd->Offset; + + bIsLocked = bHasCustomAesKey; + if (bHasCustomAesKey) { + bIsLocked = gIsLocked; + } + + const uint32_t EEPROM_SIZE = SETTINGS_GetEEPROMSize(); + const uint32_t PATCH_START = EEPROM_SIZE - PATCH_SIZE; + + for (uint16_t i = 0; i < (pCmd->Size / 8U); i++) { + uint32_t Offset = PATCH_START + pCmd->Offset + (i * 8U); + + if (Offset >= 0x0F30 && Offset < 0x0F40) { + if (!gIsLocked) { + bReloadEeprom = true; + } + } + + if ((Offset < 0x0E98 || Offset >= 0x0EA0) || !bIsInLockScreen || + pCmd->bAllowPassword) { + EEPROM_WriteBuffer(Offset, &pCmd->Data[i * 8U], 8); + } + } + + SendReply(&Reply, sizeof(Reply)); } -void Log(const char *pattern, ...) { - char text[128]; - va_list args; - va_start(args, pattern); - vsnprintf(text, sizeof(text), pattern, args); - va_end(args); - UART_printf("%u %s\n", elapsedMilliseconds, text); - UART_flush(); +static void CMD_0527(void) { + REPLY_0527_t Reply; + + Reply.Header.ID = 0x0528; + Reply.Header.Size = sizeof(Reply.Data); + Reply.Data.RSSI = BK4819_ReadRegister(BK4819_REG_67) & 0x01FF; + Reply.Data.ExNoiseIndicator = BK4819_ReadRegister(BK4819_REG_65) & 0x007F; + Reply.Data.GlitchIndicator = BK4819_ReadRegister(BK4819_REG_63); + + SendReply(&Reply, sizeof(Reply)); } -#define DMA_INDEX(x, y) (((x) + (y)) % sizeof(UART_DMA_Buffer)) +static void CMD_0529(void) { + REPLY_0529_t Reply; -static uint16_t write_index = 0; -uint8_t gUartData[512] = {0}; -static uint16_t bufIndex = 0; -static uint8_t countdown = 0; + Reply.Header.ID = 0x52A; + Reply.Header.Size = sizeof(Reply.Data); + // Original doesn't actually send current! + BOARD_ADC_GetBatteryInfo(&Reply.Data.Voltage, &Reply.Data.Current); + SendReply(&Reply, sizeof(Reply)); +} -uint16_t UART_HasData() { - uint16_t DmaLength = DMA_CH0->ST & 0xFFFU; +static void CMD_052D(const uint8_t *pBuffer) { + const CMD_052D_t *pCmd = (const CMD_052D_t *)pBuffer; + REPLY_052D_t Reply; + bool bIsLocked; - if (write_index == DmaLength) { - if (bufIndex && --countdown == 0) { - bufIndex = 0; - return true; + Reply.Header.ID = 0x052E; + Reply.Header.Size = sizeof(Reply.Data); + + bIsLocked = bHasCustomAesKey; + + if (!bIsLocked) { + bIsLocked = IsBadChallenge(gCustomAesKey, gChallenge, pCmd->Response); + } + if (!bIsLocked) { + bIsLocked = IsBadChallenge(gDefaultAesKey, gChallenge, pCmd->Response); + if (bIsLocked) { + gTryCount++; } - return false; } + if (gTryCount < 3) { + if (!bIsLocked) { + gTryCount = 0; + } + } else { + gTryCount = 3; + bIsLocked = true; + } + gIsLocked = bIsLocked; + Reply.Data.bIsLocked = bIsLocked; + SendReply(&Reply, sizeof(Reply)); +} + +static void CMD_052F(const uint8_t *pBuffer) { + const CMD_052F_t *pCmd = (const CMD_052F_t *)pBuffer; + + /* gEeprom.DUAL_WATCH = DUAL_WATCH_OFF; + gEeprom.CROSS_BAND_RX_TX = CROSS_BAND_OFF; + gEeprom.RX_VFO = 0; + gEeprom.DTMF_SIDE_TONE = false; + gEeprom.VfoInfo[0].FrequencyReverse = false; + gEeprom.VfoInfo[0].pRX = &gEeprom.VfoInfo[0].ConfigRX; + gEeprom.VfoInfo[0].pTX = &gEeprom.VfoInfo[0].ConfigTX; + gEeprom.VfoInfo[0].OFFSET_DIR = FREQUENCY_DEVIATION_OFF; + gEeprom.VfoInfo[0].DTMF_PTT_ID_TX_MODE = PTT_ID_OFF; + gEeprom.VfoInfo[0].DTMF_DECODING_ENABLE = false; + if (gCurrentFunction == FUNCTION_POWER_SAVE) { + FUNCTION_Select(FUNCTION_FOREGROUND); + } */ + Timestamp = pCmd->Timestamp; + GPIO_ClearBit(&GPIOB->DATA, GPIOB_PIN_BACKLIGHT); + + SendVersion(); +} + +#ifdef ENABLE_UART_CAT - uint16_t n = 0; +static void CMD_0601(const uint8_t *pBuffer) { + const CMD_0601_t *pCmd = (const CMD_0601_t *)pBuffer; + REPLY_0601_t Reply; - if (write_index > DmaLength) { // end of buffer - n = 256 - write_index; - memcpy(gUartData + bufIndex, UART_DMA_Buffer + write_index, n); - memset(UART_DMA_Buffer + write_index, 0, n); - bufIndex += n; + Reply.Header.ID = 0x0601; + Reply.Header.Size = sizeof(Reply.Data); + Reply.Data.Val = BK4819_ReadRegister(pCmd->RegNum); + Reply.Data.v1 = pCmd->RegNum; - n = write_index; - memcpy(gUartData + bufIndex, UART_DMA_Buffer, n); - memset(UART_DMA_Buffer, 0, n); - bufIndex += n; + SendReply(&Reply, sizeof(Reply)); +} + +static void CMD_0602(const uint8_t *pBuffer) { + const CMD_0602_t *pCmd = (const CMD_0602_t *)pBuffer; + REPLY_0602_t Reply; + + Reply.Header.ID = 0x0602; + Reply.Header.Size = sizeof(Reply.Data); + BK4819_WriteRegister(pCmd->RegNum, pCmd->RegValue); + Reply.Data.Val = BK4819_ReadRegister(pCmd->RegNum); + Reply.Data.v1 = pCmd->RegNum; + + SendReply(&Reply, sizeof(Reply)); +} +#endif + +uint64_t xtou64(const char *str) { + uint64_t res = 0; + char c; + + while ((c = *str++)) { + char v = ((c & 0xF) + (c >> 6)) | ((c >> 3) & 0x8); + res = (res << 4) | (uint64_t)v; + } + + return res; +} + +bool UART_IsCommandAvailable(void) { + uint16_t DmaLength; + uint16_t CommandLength; + uint16_t Index; + uint16_t TailIndex; + uint16_t Size; + uint16_t CRC; + uint16_t i; + + DmaLength = DMA_CH0->ST & 0xFFFU; + while (1) { + if (gUART_WriteIndex == DmaLength) { + return false; + } + + while (gUART_WriteIndex != DmaLength && + UART_DMA_Buffer[gUART_WriteIndex] != 0xABU) { + gUART_WriteIndex = DMA_INDEX(gUART_WriteIndex, 1); + } + + if (gUART_WriteIndex == DmaLength) { + return false; + } + + if (gUART_WriteIndex < DmaLength) { + CommandLength = DmaLength - gUART_WriteIndex; + } else { + CommandLength = (DmaLength + sizeof(UART_DMA_Buffer)) - gUART_WriteIndex; + } + if (CommandLength < 8) { + return 0; + } + if (UART_DMA_Buffer[DMA_INDEX(gUART_WriteIndex, 1)] == 0xCD) { + break; + } + gUART_WriteIndex = DMA_INDEX(gUART_WriteIndex, 1); + } + + Index = DMA_INDEX(gUART_WriteIndex, 2); + Size = (UART_DMA_Buffer[DMA_INDEX(Index, 1)] << 8) | UART_DMA_Buffer[Index]; + if (Size + 8 > sizeof(UART_DMA_Buffer)) { + gUART_WriteIndex = DmaLength; + return false; + } + if (CommandLength < Size + 8) { + return false; + } + Index = DMA_INDEX(Index, 2); + TailIndex = DMA_INDEX(Index, Size + 2); + if (UART_DMA_Buffer[TailIndex] != 0xDC || + UART_DMA_Buffer[DMA_INDEX(TailIndex, 1)] != 0xBA) { + gUART_WriteIndex = DmaLength; + return false; + } + if (TailIndex < Index) { + uint16_t ChunkSize = sizeof(UART_DMA_Buffer) - Index; + + memcpy(UART_Command.Buffer, UART_DMA_Buffer + Index, ChunkSize); + memcpy(UART_Command.Buffer + ChunkSize, UART_DMA_Buffer, TailIndex); } else { - n = DmaLength - write_index; - memcpy(gUartData + bufIndex, UART_DMA_Buffer + write_index, n); - memset(UART_DMA_Buffer + write_index, 0, n); - bufIndex += n; + memcpy(UART_Command.Buffer, UART_DMA_Buffer + Index, TailIndex - Index); } - countdown = 10; + TailIndex = DMA_INDEX(TailIndex, 2); + if (TailIndex < gUART_WriteIndex) { + memset(UART_DMA_Buffer + gUART_WriteIndex, 0, + sizeof(UART_DMA_Buffer) - gUART_WriteIndex); + memset(UART_DMA_Buffer, 0, TailIndex); + } else { + memset(UART_DMA_Buffer + gUART_WriteIndex, 0, TailIndex - gUART_WriteIndex); + } - write_index = DmaLength; + gUART_WriteIndex = TailIndex; - return false; + if (UART_Command.Header.ID == 0x0514) { + bIsEncrypted = false; + } + if (UART_Command.Header.ID == 0x6902) { + bIsEncrypted = true; + } + + if (bIsEncrypted) { + for (i = 0; i < Size + 2; i++) { + UART_Command.Buffer[i] ^= Obfuscation[i % 16]; + } + } + + CRC = UART_Command.Buffer[Size] | (UART_Command.Buffer[Size + 1] << 8); + if (CRC_Calculate(UART_Command.Buffer, Size) != CRC) { + return false; + } + + return true; +} + +void UART_HandleCommand(void) { + switch (UART_Command.Header.ID) { + case 0x0514: + CMD_0514(UART_Command.Buffer); + break; + + case 0x051B: + CMD_051B(UART_Command.Buffer); + break; + + case 0x051D: + CMD_051D(UART_Command.Buffer); + break; + + case 0x051F: + // Not implementing non-authentic command + break; + + case 0x0521: + // Not implementing non-authentic command + break; + + case 0x0527: + CMD_0527(); + break; + + case 0x0529: + CMD_0529(); + break; + + case 0x052D: + CMD_052D(UART_Command.Buffer); + break; + + case 0x052F: + CMD_052F(UART_Command.Buffer); + break; + + case 0x05DD: + NVIC_SystemReset(); + break; + + // write patch + case 0x061D: + CMD_061D(UART_Command.Buffer); + break; + } +} + +void UART_printf(const char *str, ...) { + char text[128]; + int len; + + va_list va; + va_start(va, str); + len = vsnprintf(text, sizeof(text), str, va); + va_end(va); + + UART_Send(text, len); +} + +void Log(const char *pattern, ...) { + char text[128]; + va_list args; + va_start(args, pattern); + vsnprintf(text, sizeof(text), pattern, args); + va_end(args); + UART_printf("%u %s\n", Now(), text); } diff --git a/src/driver/uart.h b/src/driver/uart.h index 88c1a12..a84840a 100644 --- a/src/driver/uart.h +++ b/src/driver/uart.h @@ -22,20 +22,14 @@ #include extern uint8_t UART_DMA_Buffer[256]; -extern uint8_t gUartData[512]; -extern uint8_t UART_IsLogEnabled; void UART_Init(void); void UART_Send(const void *pBuffer, uint32_t Size); -void UART_SendText(const void *str); void UART_LogSend(const void *pBuffer, uint32_t Size); -void UART_LogSendText(const void *str); void UART_printf(const char *str, ...); -uint16_t UART_HasData(); -void UART_ResetData(); -void UART_logf(uint8_t level, const char *pattern, ...); + +bool UART_IsCommandAvailable(void); +void UART_HandleCommand(void); void Log(const char *pattern, ...); -void UART_ToggleLog(bool on); -void UART_flush(); #endif diff --git a/src/helper/channels.c b/src/helper/channels.c index 1a22099..cfdf1e7 100644 --- a/src/helper/channels.c +++ b/src/helper/channels.c @@ -1,45 +1,70 @@ #include "channels.h" #include "../driver/eeprom.h" #include "../helper/measurements.h" +#include "../helper/presetlist.h" +#include + +#define SCANLIST_MAX 128 int32_t gScanlistSize = 0; -int32_t gScanlist[350] = {0}; +uint16_t gScanlist[SCANLIST_MAX] = {0}; + +static const uint8_t CH_NAME_OFFSET = offsetof(CH, name); +static const uint8_t CH_BANKS_OFFSET = offsetof(CH, memoryBanks); + +static uint32_t presetsSizeBytes(void) { + return ARRAY_SIZE(defaultPresets) * PRESET_SIZE; +} -static uint16_t presetsSizeBytes(void) { - return gSettings.presetsCount * PRESET_SIZE; +static uint32_t getChannelsStart() { + return PRESETS_OFFSET + presetsSizeBytes(); } -int32_t CHANNELS_GetCountMax(void) { - return (SETTINGS_GetEEPROMSize() - PRESETS_OFFSET - presetsSizeBytes()) / - CH_SIZE; +static uint32_t getChannelsEnd() { + uint32_t eepromSize = SETTINGS_GetEEPROMSize(); + uint32_t minSizeWithPatch = getChannelsStart() + CH_SIZE + PATCH_SIZE; + if (eepromSize < minSizeWithPatch) { + return eepromSize; + } + return eepromSize - PATCH_SIZE; +} + +static uint32_t GetChannelOffset(int32_t num) { + return getChannelsEnd() - (num + 1) * CH_SIZE; +} + +uint16_t CHANNELS_GetCountMax(void) { + return (getChannelsEnd() - getChannelsStart()) / CH_SIZE; } void CHANNELS_Load(int32_t num, CH *p) { if (num >= 0) { - EEPROM_ReadBuffer(SETTINGS_GetEEPROMSize() - (num + 1) * CH_SIZE, p, - CH_SIZE); + EEPROM_ReadBuffer(GetChannelOffset(num), p, CH_SIZE); } } void CHANNELS_Save(int32_t num, CH *p) { if (num >= 0) { - EEPROM_WriteBuffer(SETTINGS_GetEEPROMSize() - (num + 1) * CH_SIZE, p, - CH_SIZE); + EEPROM_WriteBuffer(GetChannelOffset(num), p, CH_SIZE); } } -bool CHANNELS_Existing(int32_t i) { - char name[2] = {0}; - // TODO: offsetof - uint32_t addr = SETTINGS_GetEEPROMSize() - ((i + 1) * CH_SIZE) + 4 + 4; +void CHANNELS_Delete(int32_t num) { + char name[1] = {0}; + uint32_t addr = GetChannelOffset(num) + CH_NAME_OFFSET; + EEPROM_WriteBuffer(addr, name, 1); +} + +bool CHANNELS_Existing(int32_t num) { + char name[1] = {0}; + uint32_t addr = GetChannelOffset(num) + CH_NAME_OFFSET; EEPROM_ReadBuffer(addr, name, 1); return IsReadable(name); } -uint8_t CHANNELS_Scanlists(int32_t i) { +uint8_t CHANNELS_Scanlists(int32_t num) { uint8_t scanlists; - // TODO: offsetof - uint32_t addr = SETTINGS_GetEEPROMSize() - ((i + 1) * CH_SIZE) + 4 + 4 + 10; + uint32_t addr = GetChannelOffset(num) + CH_BANKS_OFFSET; EEPROM_ReadBuffer(addr, &scanlists, 1); return scanlists; } @@ -75,21 +100,22 @@ int32_t CHANNELS_Next(int32_t base, bool next) { return -1; } -void CHANNELS_Delete(int32_t i) { - CH v = {0}; - CHANNELS_Save(i, &v); -} - void CHANNELS_LoadScanlist(uint8_t n) { gSettings.currentScanlist = n; int32_t max = CHANNELS_GetCountMax(); + max = 1024; // temporary uint8_t scanlistMask = 1 << n; gScanlistSize = 0; for (int32_t i = 0; i < max; ++i) { - if ((n == 15 && CHANNELS_Existing(i)) || - (CHANNELS_Scanlists(i) & scanlistMask) == scanlistMask) { + if (!CHANNELS_Existing(i)) { + continue; + } + if (n == 15 || (CHANNELS_Scanlists(i) & scanlistMask) == scanlistMask) { gScanlist[gScanlistSize] = i; gScanlistSize++; + if (gScanlistSize >= SCANLIST_MAX) { + break; + } } } SETTINGS_Save(); diff --git a/src/helper/channels.h b/src/helper/channels.h index 27e92f9..79e8f32 100644 --- a/src/helper/channels.h +++ b/src/helper/channels.h @@ -4,7 +4,7 @@ #include "../settings.h" #include -int32_t CHANNELS_GetCountMax(); +uint16_t CHANNELS_GetCountMax(); void CHANNELS_Load(int32_t num, CH *p); void CHANNELS_Save(int32_t num, CH *p); CH *CHANNELS_Get(int32_t i); @@ -16,6 +16,6 @@ uint8_t CHANNELS_Scanlists(int32_t i); void CHANNELS_LoadScanlist(uint8_t n); extern int32_t gScanlistSize; -extern int32_t gScanlist[350]; +extern uint16_t gScanlist[128]; #endif /* end of include guard: CHANNELS_H */ diff --git a/src/helper/eeprom.c b/src/helper/eeprom.c deleted file mode 100644 index 7e69cc6..0000000 --- a/src/helper/eeprom.c +++ /dev/null @@ -1,4 +0,0 @@ -#include "eeprom.h" - -uint8_t EEPROM_GetRemainingPresetsCount(); -uint16_t EEPROM_GetRemainingChannelsCount(); diff --git a/src/helper/eeprom.h b/src/helper/eeprom.h deleted file mode 100644 index 359f42a..0000000 --- a/src/helper/eeprom.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef EEPROM_HELPER_H -#define EEPROM_HELPER_H - -#include - -uint8_t EEPROM_GetRemainingPresetsCount(); -uint16_t EEPROM_GetRemainingChannelsCount(); - -#endif /* end of include guard: EEPROM_HELPER_H */ diff --git a/src/helper/lootlist.c b/src/helper/lootlist.c index 9793718..e1c4237 100644 --- a/src/helper/lootlist.c +++ b/src/helper/lootlist.c @@ -1,7 +1,6 @@ #include "lootlist.h" #include "../dcs.h" #include "../driver/bk4819.h" -#include "../driver/uart.h" #include "../scheduler.h" static Loot loot[LOOT_SIZE_MAX] = {0}; @@ -53,9 +52,9 @@ Loot *LOOT_AddEx(uint32_t f, bool reuse) { lootIndex++; loot[lootIndex] = (Loot){ .f = f, - .firstTime = elapsedMilliseconds, - .lastTimeCheck = elapsedMilliseconds, - .lastTimeOpen = elapsedMilliseconds, + .firstTime = Now(), + .lastTimeCheck = Now(), + .lastTimeOpen = Now(), .duration = 0, .rssi = 0, .open = true, // as we add it when open @@ -86,7 +85,7 @@ void LOOT_Standby(void) { for (uint8_t i = 0; i < LOOT_Size(); ++i) { Loot *p = &loot[i]; p->open = false; - p->lastTimeCheck = elapsedMilliseconds; + p->lastTimeCheck = Now(); } } @@ -133,8 +132,8 @@ Loot *LOOT_Item(uint8_t i) { return &loot[i]; } void LOOT_Replace(Loot *item, uint32_t f) { item->f = f; item->open = false; - item->firstTime = elapsedMilliseconds; - item->lastTimeCheck = elapsedMilliseconds; + item->firstTime = Now(); + item->lastTimeCheck = Now(); item->lastTimeOpen = 0; item->duration = 0; item->rssi = 0; @@ -159,7 +158,7 @@ void LOOT_UpdateEx(Loot *item, Loot *msm) { item->rssi = msm->rssi; if (item->open) { - item->duration += elapsedMilliseconds - item->lastTimeCheck; + item->duration += Now() - item->lastTimeCheck; gLastActiveLoot = item; gLastActiveLootIndex = LOOT_IndexOf(item); } @@ -184,9 +183,9 @@ void LOOT_UpdateEx(Loot *item, Loot *msm) { default: break; } - item->lastTimeOpen = elapsedMilliseconds; + item->lastTimeOpen = Now(); } - item->lastTimeCheck = elapsedMilliseconds; + item->lastTimeCheck = Now(); item->open = msm->open; if (msm->blacklist) { @@ -199,7 +198,6 @@ void LOOT_Update(Loot *msm) { if (item == NULL && msm->open) { item = LOOT_Add(msm->f); - UART_logf(1, "[LOOT] %u", msm->f); } LOOT_UpdateEx(item, msm); diff --git a/src/helper/lootlist.h b/src/helper/lootlist.h index 4ecde55..2444f18 100644 --- a/src/helper/lootlist.h +++ b/src/helper/lootlist.h @@ -16,6 +16,7 @@ typedef struct { uint16_t ct; uint16_t duration; uint16_t rssi; + uint8_t noise; bool open; bool blacklist; bool goodKnown; diff --git a/src/helper/numnav.c b/src/helper/numnav.c index 40530e7..fddc422 100644 --- a/src/helper/numnav.c +++ b/src/helper/numnav.c @@ -1,6 +1,4 @@ #include "numnav.h" -#include "../driver/st7565.h" -#include "../driver/uart.h" #include #include @@ -46,7 +44,6 @@ uint16_t NUMNAV_GetCurrentValue(void) { } uint16_t NUMNAV_Input(KEY_Code_t key) { - Log("numnav key=%u", key); if (pos == 0 && key == KEY_0) { NUMNAV_Deinit(); return initV; @@ -77,13 +74,10 @@ uint16_t NUMNAV_Input(KEY_Code_t key) { uint16_t v = NUMNAV_GetCurrentValue(); if ((pos == maxDigits || v * 10 > maxV) && gNumNavCallback) { - Log("Bound, check value..."); if (v >= minV && v <= maxV) { - Log("Accept! %u < %u < %u", minV, v, maxV); NUMNAV_Accept(); return v; } else { - Log("Decline."); return NUMNAV_Deinit(); } } @@ -91,7 +85,6 @@ uint16_t NUMNAV_Input(KEY_Code_t key) { } uint16_t NUMNAV_Deinit(void) { - Log("NUMNAV_Deinit %u", initV); pos = 0; gNumNavCallback = NULL; gIsNumNavInput = false; @@ -99,7 +92,6 @@ uint16_t NUMNAV_Deinit(void) { } void NUMNAV_Accept(void) { - Log("NUMNAV_Accept %u", NUMNAV_GetCurrentValue()); gNumNavCallback(NUMNAV_GetCurrentValue()); NUMNAV_Deinit(); } diff --git a/src/helper/presetlist.h b/src/helper/presetlist.h index a10d814..9bf077f 100644 --- a/src/helper/presetlist.h +++ b/src/helper/presetlist.h @@ -6,6 +6,476 @@ #define PRESETS_SIZE_MAX 32 +static Preset + defaultPresets[] = + { + (Preset){ + .band = + { + .bounds = {1500000, 2999999}, + .name = "15-30", + .step = STEP_5_0kHz, + .modulation = MOD_AM, + .bw = BK4819_FILTER_BW_NARROW, + .gainIndex = 16, + .squelch = 3, + .squelchType = SQUELCH_RSSI_NOISE_GLITCH, + }, + .allowTx = false, + .lastUsedFreq = 2713500, + .powCalib = {0x8C, 0x8C, 0x8C}, + }, + (Preset){ + .band = + { + .bounds = {3000000, 6399999}, + .name = "30-64", + .step = STEP_5_0kHz, + .modulation = MOD_FM, + .bw = BK4819_FILTER_BW_NARROW, + .gainIndex = 16, + .squelch = 3, + .squelchType = SQUELCH_RSSI_NOISE_GLITCH, + }, + .allowTx = false, + .lastUsedFreq = 3000000, + .powCalib = {0x8C, 0x8C, 0x8C}, + }, + (Preset){ + .band = + { + .bounds = {6400000, 8799999}, + .name = "64-88", + .step = STEP_100_0kHz, + .modulation = MOD_WFM, + .bw = BK4819_FILTER_BW_NARROW, + .gainIndex = 16, + .squelch = 3, + .squelchType = SQUELCH_RSSI_NOISE_GLITCH, + }, + .allowTx = false, + .lastUsedFreq = 7100000, + .powCalib = {0x8C, 0x8C, 0x8C}, + }, + (Preset){ + .band = + { + .bounds = {8800000, 10799999}, + .name = "Bcast FM", + .step = STEP_100_0kHz, + .modulation = MOD_WFM, + .bw = BK4819_FILTER_BW_NARROW, + .gainIndex = 16, + .squelch = 3, + .squelchType = SQUELCH_RSSI_NOISE_GLITCH, + }, + .allowTx = false, + .lastUsedFreq = 10320000, + .powCalib = {0x8C, 0x8C, 0x8C}, + }, + (Preset){ + .band = + { + .bounds = {10800000, 11799999}, + .name = "108-118", + .step = STEP_12_5kHz, + .modulation = MOD_FM, + .bw = BK4819_FILTER_BW_WIDE, + .gainIndex = 16, + .squelch = 3, + .squelchType = SQUELCH_RSSI_NOISE_GLITCH, + }, + .allowTx = false, + .lastUsedFreq = 10800000, + .powCalib = {0x8C, 0x8C, 0x8C}, + }, + (Preset){ + .band = + { + .bounds = {11800000, 13499999}, + .name = "Air", + .step = STEP_12_5kHz, + .modulation = MOD_AM, + .bw = BK4819_FILTER_BW_NARROW, + .gainIndex = 16, + .squelch = 3, + .squelchType = SQUELCH_RSSI_NOISE_GLITCH, + }, + .allowTx = false, + .lastUsedFreq = 13170000, + .powCalib = {0x8C, 0x8C, 0x8C}, + }, + (Preset){ + .band = + { + .bounds = {13500000, 14399999}, + .name = "135-144", + .step = STEP_12_5kHz, + .modulation = MOD_FM, + .bw = BK4819_FILTER_BW_NARROW, + .gainIndex = 16, + .squelch = 3, + .squelchType = SQUELCH_RSSI_NOISE_GLITCH, + }, + .allowTx = false, + .lastUsedFreq = 13510000, + .powCalib = {0x8C, 0x8C, 0x8C}, + }, + (Preset){ + .band = + { + .bounds = {14400000, 14799999}, + .name = "2m HAM", + .step = STEP_25_0kHz, + .modulation = MOD_FM, + .bw = BK4819_FILTER_BW_WIDE, + .gainIndex = 16, + .squelch = 3, + .squelchType = SQUELCH_RSSI_NOISE_GLITCH, + }, + .allowTx = false, + .lastUsedFreq = 14550000, + .powCalib = {0x8C, 0x8C, 0x8C}, + }, + (Preset){ + .band = + { + .bounds = {14800000, 17399999}, + .name = "148-174", + .step = STEP_25_0kHz, + .modulation = MOD_FM, + .bw = BK4819_FILTER_BW_WIDE, + .gainIndex = 16, + .squelch = 3, + .squelchType = SQUELCH_RSSI_NOISE_GLITCH, + }, + .allowTx = false, + .lastUsedFreq = 15300000, + .powCalib = {0x8C, 0x8C, 0x8C}, + }, + (Preset){ + .band = + { + .bounds = {17400000, 22999999}, + .name = "174-230", + .step = STEP_25_0kHz, + .modulation = MOD_FM, + .bw = BK4819_FILTER_BW_WIDE, + .gainIndex = 16, + .squelch = 3, + .squelchType = SQUELCH_RSSI_NOISE_GLITCH, + }, + .allowTx = false, + .lastUsedFreq = 20575000, + .powCalib = {0x8C, 0x8C, 0x8C}, + }, + (Preset){ + .band = + { + .bounds = {23000000, 31999999}, + .name = "230-320", + .step = STEP_25_0kHz, + .modulation = MOD_FM, + .bw = BK4819_FILTER_BW_WIDE, + .gainIndex = 16, + .squelch = 3, + .squelchType = SQUELCH_RSSI_NOISE_GLITCH, + }, + .allowTx = false, + .lastUsedFreq = 25355000, + .powCalib = {0x8C, 0x8C, 0x8C}, + }, + (Preset){ + .band = + { + .bounds = {32000000, 39999999}, + .name = "320-400", + .step = STEP_25_0kHz, + .modulation = MOD_FM, + .bw = BK4819_FILTER_BW_WIDE, + .gainIndex = 16, + .squelch = 3, + .squelchType = SQUELCH_RSSI_NOISE_GLITCH, + }, + .allowTx = false, + .lastUsedFreq = 33605000, + .powCalib = {0x82, 0x82, 0x82}, + }, + (Preset){ + .band = + { + .bounds = {40000000, 43307499}, + .name = "400-433", + .step = STEP_25_0kHz, + .modulation = MOD_FM, + .bw = BK4819_FILTER_BW_WIDE, + .gainIndex = 16, + .squelch = 3, + .squelchType = SQUELCH_RSSI_NOISE_GLITCH, + }, + .allowTx = false, + .lastUsedFreq = 42230000, + .powCalib = {0x8C, 0x8C, 0x8C}, + }, + (Preset){ + .band = + { + .bounds = {43307500, 43479999}, + .name = "LPD", + .step = STEP_25_0kHz, + .modulation = MOD_FM, + .bw = BK4819_FILTER_BW_WIDE, + .gainIndex = 16, + .squelch = 3, + .squelchType = SQUELCH_RSSI_NOISE_GLITCH, + }, + .allowTx = true, + .lastUsedFreq = 43325000, + .powCalib = {0x8C, 0x8C, 0x8C}, + }, + (Preset){ + .band = + { + .bounds = {43480000, 44600624}, + .name = "435-446", + .step = STEP_25_0kHz, + .modulation = MOD_FM, + .bw = BK4819_FILTER_BW_WIDE, + .gainIndex = 16, + .squelch = 3, + .squelchType = SQUELCH_RSSI_NOISE_GLITCH, + }, + .allowTx = false, + .lastUsedFreq = 43700000, + .powCalib = {0x8C, 0x8C, 0x8C}, + }, + (Preset){ + .band = + { + .bounds = {44600625, 44619375}, + .name = "PMR", + .step = STEP_6_25kHz, + .modulation = MOD_FM, + .bw = BK4819_FILTER_BW_WIDE, + .gainIndex = 16, + .squelch = 3, + .squelchType = SQUELCH_RSSI_NOISE_GLITCH, + }, + .allowTx = true, + .lastUsedFreq = 44609375, + .powCalib = {0x8C, 0x8C, 0x8C}, + }, + (Preset){ + .band = + { + .bounds = {44620000, 46256249}, + .name = "446-462", + .step = STEP_25_0kHz, + .modulation = MOD_FM, + .bw = BK4819_FILTER_BW_WIDE, + .gainIndex = 16, + .squelch = 3, + .squelchType = SQUELCH_RSSI_NOISE_GLITCH, + }, + .allowTx = false, + .lastUsedFreq = 46060000, + .powCalib = {0x8C, 0x8C, 0x8C}, + }, + (Preset){ + .band = + { + .bounds = {46256250, 46273749}, + .name = "FRS/G462", + .step = STEP_12_5kHz, + .modulation = MOD_FM, + .bw = BK4819_FILTER_BW_WIDE, + .gainIndex = 16, + .squelch = 3, + .squelchType = SQUELCH_RSSI_NOISE_GLITCH, + }, + .allowTx = false, + .lastUsedFreq = 46256250, + .powCalib = {0x8C, 0x8C, 0x8C}, + }, + (Preset){ + .band = + { + .bounds = {46273750, 46756249}, + .name = "462-467", + .step = STEP_12_5kHz, + .modulation = MOD_FM, + .bw = BK4819_FILTER_BW_WIDE, + .gainIndex = 16, + .squelch = 3, + .squelchType = SQUELCH_RSSI_NOISE_GLITCH, + }, + .allowTx = false, + .lastUsedFreq = 46302500, + .powCalib = {0x8C, 0x8C, 0x8C}, + }, + (Preset){ + .band = + { + .bounds = {46756250, 46774999}, + .name = "FRS/G467", + .step = STEP_12_5kHz, + .modulation = MOD_FM, + .bw = BK4819_FILTER_BW_WIDE, + .gainIndex = 16, + .squelch = 3, + .squelchType = SQUELCH_RSSI_NOISE_GLITCH, + }, + .allowTx = false, + .lastUsedFreq = 46756250, + .powCalib = {0x8C, 0x8C, 0x8C}, + }, + (Preset){ + .band = + { + .bounds = {46775000, 46999999}, + .name = "468-470", + .step = STEP_25_0kHz, + .modulation = MOD_FM, + .bw = BK4819_FILTER_BW_WIDE, + .gainIndex = 16, + .squelch = 3, + .squelchType = SQUELCH_RSSI_NOISE_GLITCH, + }, + .allowTx = false, + .lastUsedFreq = 46980000, + .powCalib = {0x8C, 0x8C, 0x8C}, + }, + (Preset){ + .band = + { + .bounds = {47000000, 62000000}, + .name = "470-620", + .step = STEP_25_0kHz, + .modulation = MOD_FM, + .bw = BK4819_FILTER_BW_WIDE, + .gainIndex = 16, + .squelch = 3, + .squelchType = SQUELCH_RSSI_NOISE_GLITCH, + }, + .allowTx = false, + .lastUsedFreq = 50975000, + .powCalib = {0x8C, 0x8C, 0x8C}, + }, + (Preset){ + .band = + { + .bounds = {84000000, 86299999}, + .name = "840-863", + .step = STEP_25_0kHz, + .modulation = MOD_FM, + .bw = BK4819_FILTER_BW_WIDE, + .gainIndex = 16, + .squelch = 3, + .squelchType = SQUELCH_RSSI_NOISE_GLITCH, + }, + .allowTx = false, + .lastUsedFreq = 85500000, + .powCalib = {0x8C, 0x8C, 0x8C}, + }, + (Preset){ + .band = + { + .bounds = {86300000, 86999999}, + .name = "LORA", + .step = STEP_125_0kHz, + .modulation = MOD_FM, + .bw = BK4819_FILTER_BW_WIDE, + .gainIndex = 16, + .squelch = 3, + .squelchType = SQUELCH_RSSI_NOISE_GLITCH, + }, + .allowTx = false, + .lastUsedFreq = 86400000, + .powCalib = {0x8C, 0x8C, 0x8C}, + }, + (Preset){ + .band = + { + .bounds = {87000000, 88999999}, + .name = "870-890", + .step = STEP_25_0kHz, + .modulation = MOD_FM, + .bw = BK4819_FILTER_BW_WIDE, + .gainIndex = 16, + .squelch = 3, + .squelchType = SQUELCH_RSSI_NOISE_GLITCH, + }, + .allowTx = false, + .lastUsedFreq = 87000000, + .powCalib = {0x8C, 0x8C, 0x8C}, + }, + (Preset){ + .band = + { + .bounds = {89000000, 95999999}, + .name = "GSM-900", + .step = STEP_200_0kHz, + .modulation = MOD_FM, + .bw = BK4819_FILTER_BW_WIDE, + .gainIndex = 16, + .squelch = 3, + .squelchType = SQUELCH_RSSI_NOISE_GLITCH, + }, + .allowTx = false, + .lastUsedFreq = 89000000, + .powCalib = {0x8C, 0x8C, 0x8C}, + }, + (Preset){ + .band = + { + .bounds = {96000000, 125999999}, + .name = "960-1260", + .step = STEP_25_0kHz, + .modulation = MOD_FM, + .bw = BK4819_FILTER_BW_WIDE, + .gainIndex = 16, + .squelch = 3, + .squelchType = SQUELCH_RSSI_NOISE_GLITCH, + }, + .allowTx = false, + .lastUsedFreq = 96000000, + .powCalib = {0x8C, 0x8C, 0x8C}, + }, + (Preset){ + .band = + { + .bounds = {126000000, 129999999}, + .name = "23cm HAM", + .step = STEP_25_0kHz, + .modulation = MOD_FM, + .bw = BK4819_FILTER_BW_WIDE, + .gainIndex = 16, + .squelch = 3, + .squelchType = SQUELCH_RSSI_NOISE_GLITCH, + }, + .allowTx = false, + .lastUsedFreq = 129750000, + .powCalib = {0x8C, 0x8C, 0x8C}, + }, + (Preset){ + .band = + { + .bounds = {126000000, 134000000}, + .name = "1.3-1.34", + .step = STEP_25_0kHz, + .modulation = MOD_FM, + .bw = BK4819_FILTER_BW_WIDE, + .gainIndex = 16, + .squelch = 3, + .squelchType = SQUELCH_RSSI_NOISE_GLITCH, + }, + .allowTx = false, + .lastUsedFreq = 126000000, + .powCalib = {0x8C, 0x8C, 0x8C}, + }, +}; +// char (*__defpres)[sizeof(defaultPresets)/sizeof(Preset)] = 1; + bool PRESETS_Load(); int8_t PRESETS_Size(); Preset *PRESETS_Item(int8_t i); diff --git a/src/helper/rds.c b/src/helper/rds.c new file mode 100644 index 0000000..e5e4bd8 --- /dev/null +++ b/src/helper/rds.c @@ -0,0 +1,441 @@ +#include "rds.h" +#include "../driver/si473x.h" +#include + +si47x_rds_status rdsResponse = {0}; + +enum { + PI_H = 4, // Also "Block A" + PI_L, + Block_B_H, + Block_B_L, + Block_C_H, + Block_C_L, + Block_D_H, + Block_D_L +}; + +#define MAKE_WORD(hb, lb) (((uint8_t)(hb) << 8U) | (uint8_t)lb) + +enum { NO_DATE_TIME = 127 }; +RDS rds = {.offset = NO_DATE_TIME}; + +enum { + RDS_THRESHOLD = 3, // Threshold for larger variables + RDS_BOOL_THRESHOLD = 7 // Threshold for boolean variables +}; + +static char make_printable(char ch) { + // Replace non-ASCII char with space + if (ch < 32 || 126 < ch) + ch = ' '; + return ch; +} + +/* RDS and RBDS data */ +static ternary _abRadioText; // Indicates new radioText[] string +static ternary _abProgramTypeName; // Indicates new programTypeName[] string +/* RDS data counters */ +static uint8_t _extendedCountryCode_count; +static uint8_t _language_count; + +void SI47XX_ClearRDS() { + memset(&rds, 0, sizeof(RDS)); + rds.offset = NO_DATE_TIME; +} + +bool SI47XX_GetRDS() { + + bool new_info = false; + uint8_t segment; + + while (1) { + SI47XX_ReadRDS(rdsResponse.raw); + + // Check for RDS signal + rds.RDSSignal = rdsResponse.raw[2] & FIELD_RDS_STATUS_RESP2_SYNC; + // Get number of RDS groups (packets) available + uint8_t num_groups = rdsResponse.raw[3]; + // Stop if nothing returned + if (!num_groups) + break; + + /* Because PI is resent in every packet's Block A, we told the radio its OK + * to give us packets with a corrupted Block A. + */ + // Check if PI received is valid + if ((rdsResponse.raw[12] & FIELD_RDS_STATUS_RESP12_BLOCK_A) != + RDS_STATUS_RESP12_BLOCK_A_UNCORRECTABLE) { + // Get PI code + rds.programId = MAKE_WORD(rdsResponse.raw[PI_H], rdsResponse.raw[PI_L]); + } + // Get PTY code + rds.programType = ((rdsResponse.raw[Block_B_H] & 0b00000011) << 3U) | + (rdsResponse.raw[Block_B_L] >> 5U); + // Get Traffic Program bit + rds.trafficProgram = (bool)(rdsResponse.raw[Block_B_H] & 0b00000100); + + // Get group type (0-15) + uint8_t type = rdsResponse.raw[Block_B_H] >> 4U; + // Get group version (0=A, 1=B) + bool version = rdsResponse.raw[Block_B_H] & 0b00001000; + + // Save which group type and version was received + if (version) { + rds.groupB |= 1U << type; + } else { + rds.groupA |= 1U << type; + } + + // Groups 0A & 0B - Basic tuning and switching information + // Group 15B - Fast basic tuning and switching information + /* Note: We support both Groups 0 and 15B in case the station has poor + * reception and RDS packets are barely getting through. This increases + * the chances of receiving this info. + */ + if (type == 0 || (type == 15 && version == 1)) { + // Various flags + rds.trafficAlert = (bool)(rdsResponse.raw[Block_B_L] & 0b00010000); + rds.music = (bool)(rdsResponse.raw[Block_B_L] & 0b00001000); + bool DI = rdsResponse.raw[Block_B_L] & 0b00000100; + + // Get segment number + segment = rdsResponse.raw[Block_B_L] & 0b00000011; + // Handle DI code + switch (segment) { + case 0: + rds.dynamicPTY = DI; + break; + case 1: + rds.compressedAudio = DI; + break; + case 2: + rds.binauralAudio = DI; + break; + case 3: + rds.RDSStereo = DI; + break; + } + + // Groups 0A & 0B + if (type == 0) { + // Program Service + char *ps = &rds.programService[segment * 2]; + *ps++ = make_printable(rdsResponse.raw[Block_D_H]); + *ps = make_printable(rdsResponse.raw[Block_D_L]); + } + new_info = true; + } + // Group 1A - Extended Country Code (ECC) and Language Code + else if (type == 1 && version == 0) { + // We are only interested in the Extended Country Code (ECC) and + // Language Code for this Group. + + // Get Variant code + switch (rdsResponse.raw[Block_C_H] & 0b01110000) { + case (0 << 4): // Variant==0 + // Extended Country Code + // Check if count has reached threshold + if (_extendedCountryCode_count < RDS_THRESHOLD) { + uint8_t ecc = rdsResponse.raw[Block_C_L]; + // Check if datum changed + if (rds.extendedCountryCode != ecc) { + _extendedCountryCode_count = 0; + new_info = true; + } + // Save new data + rds.extendedCountryCode = ecc; + ++_extendedCountryCode_count; + } + break; + case (3 << 4): // Variant==3 + // Language Code + // Check if count has reached threshold + if (_language_count < RDS_THRESHOLD) { + uint8_t language = rdsResponse.raw[Block_C_L]; + // Check if datum changed + if (rds.language != language) { + _language_count = 0; + new_info = true; + } + // Save new data + rds.language = language; + ++_language_count; + } + break; + } + } + // Groups 2A & 2B - Radio Text + else if (type == 2) { + // Check A/B flag to see if Radio Text has changed + uint8_t new_ab = (bool)(rdsResponse.raw[Block_B_L] & 0b00010000); + if (new_ab != _abRadioText) { + // New message found - clear buffer + _abRadioText = new_ab; + for (uint8_t i = 0; i < sizeof(rds.radioText) - 1; i++) + rds.radioText[i] = ' '; + rds.radioTextLen = sizeof(rds.radioText); // Default to max length + } + // Get segment number + segment = rdsResponse.raw[Block_B_L] & 0x0F; + + // Get Radio Text + char *rt; // Next position in rds.radioText[] + uint8_t *block; // Next char from segment + uint8_t i; // Loop counter + // TODO maybe: convert RDS non ASCII chars to UTF-8 for terminal interface + if (version == 0) { // 2A + rt = &rds.radioText[segment * 4]; + block = &rdsResponse.raw[Block_C_H]; + i = 4; + } else { // 2B + rt = &rds.radioText[segment * 2]; + block = &rdsResponse.raw[Block_D_H]; + i = 2; + } + // Copy chars + do { + // Get next char from segment + char ch = *block++; + // Check for end of message marker + if (ch == '\r') { + // Save new message length + rds.radioTextLen = rt - rds.radioText; + } + // Put next char in rds.radioText[] + *rt++ = make_printable(ch); + } while (--i); + new_info = true; + } + // Group 4A - Clock-time and date + else if (type == 4 && version == 0) { + // Only use if received perfectly. + /* Note: Error Correcting Codes (ECC) are not perfect. It is possible + * for a block to be damaged enough that the ECC thinks the data is OK + * when it's damaged or that it can recover when it cannot. Because + * date and time are useless unless accurate, we require that the date + * and time be received perfectly to increase the odds of accurate data. + */ + if ((rdsResponse.raw[12] & + (FIELD_RDS_STATUS_RESP12_BLOCK_B | FIELD_RDS_STATUS_RESP12_BLOCK_C | + FIELD_RDS_STATUS_RESP12_BLOCK_D)) == + (RDS_STATUS_RESP12_BLOCK_B_NO_ERRORS | + RDS_STATUS_RESP12_BLOCK_C_NO_ERRORS | + RDS_STATUS_RESP12_BLOCK_D_NO_ERRORS)) { + // Get Modified Julian Date (MJD) + rds.MJD = (rdsResponse.raw[Block_B_L] & 0b00000011) << 15UL | + rdsResponse.raw[Block_C_H] << 7U | + rdsResponse.raw[Block_C_L] >> 1U; + + // Get hour and minute + rds.hour = (rdsResponse.raw[Block_C_L] & 0b00000001) << 4U | + rdsResponse.raw[Block_D_H] >> 4U; + rds.minute = (rdsResponse.raw[Block_D_H] & 0x0F) << 2U | + rdsResponse.raw[Block_D_L] >> 6U; + + // Check if date and time sent (not 0) + if (rds.MJD || rds.hour || rds.minute || rdsResponse.raw[Block_D_L]) { + // Get offset to convert UTC to local time + rds.offset = rdsResponse.raw[Block_D_L] & 0x1F; + // Check if offset should be negative + if (rdsResponse.raw[Block_D_L] & 0b00100000) { + rds.offset = -rds.offset; // Make it negative + } + new_info = true; + } + } + } + // Group 10A - Program Type Name + else if (type == 10 && version == 0) { + // Check A/B flag to see if Program Type Name has changed + uint8_t new_ab = (bool)(rdsResponse.raw[Block_B_L] & 0b00010000); + if (new_ab != _abProgramTypeName) { + // New name found - clear buffer + _abProgramTypeName = new_ab; + for (uint8_t i = 0; i < sizeof(rds.programTypeName) - 1; i++) + rds.programTypeName[i] = ' '; + } + // Get segment number + segment = rdsResponse.raw[Block_B_L] & 0x01; + + // Get Program Type Name + char *name = &rds.programTypeName[segment * 4]; + *name++ = make_printable(rdsResponse.raw[Block_C_H]); + *name++ = make_printable(rdsResponse.raw[Block_C_L]); + *name++ = make_printable(rdsResponse.raw[Block_D_H]); + *name = make_printable(rdsResponse.raw[Block_D_L]); + new_info = true; + } + } + return new_info; +} + +#define DAYS_PER_YEAR 365U +// Leap year +#define DAYS_PER_LEAP_YEAR (DAYS_PER_YEAR + 1) +// Leap year every 4 years +#define DAYS_PER_4YEARS (DAYS_PER_YEAR * 4 + 1) +// Leap year every 4 years except century year (divisable by 100) +#define DAYS_PER_100YEARS (DAYS_PER_4YEARS * (100 / 4) - 1) + +// Get last RDS date and time converted to local date and time. +// Returns true if current station has sent date and time. Otherwise, it +// returns false and writes nothing to structure. Only provides info if mode==FM +// and station is sending RDS data. +bool SI47XX_GetLocalDateTime(DateTime *time) { + // Look for date/time info + if (rds.offset == NO_DATE_TIME) + return false; // No date or time info available + + // Origin for Modified Julian Date (MJD) is November 17, 1858, Wednesday. + // Move origin to Jan. 2, 2000, Sunday. + // Note: We don't use Jan. 1 to compensate for the fact that 2000 is a leap + // year. + unsigned short days = rds.MJD - ( // 1858-Nov-17 + 14 + // 1858-Dec-1 + 31 + // 1859-Jan-1 + DAYS_PER_YEAR + // 1860-Jan-1 + 10 * DAYS_PER_4YEARS + // 1900-Jan-1 + DAYS_PER_100YEARS + // 2000-Jan-1 + 1); // 2000-Jan-2 + + // Convert UTC date and time to local date and time. + // Combine date and time + unsigned long date_time = ((unsigned long)days) * (24 * 60) + + ((unsigned short)rds.hour) * 60 + rds.minute; + // Adjust offset from units of half hours to minutes + int16_t offset = (int16_t)(rds.offset) * 30; + // Compute local date/time + date_time += offset; + // Break down date and time + time->minute = date_time % 60; + date_time /= 60; + time->hour = date_time % 24; + days = date_time / 24; + + // Compute day of the week - Sunday = 0 + time->wday = days % 7; + + // Compute year + unsigned char leap_year = 0; /* 1 if leap year, else 0 */ + // Note: This code assumes all century years (2000, 2100...) are not leap + // years. This will break in 2400 AD. However, RDS' date field will overflow + // long before 2400 AD. + time->year = days / DAYS_PER_100YEARS * 100 + 2000; + days %= DAYS_PER_100YEARS; + if (!(days < DAYS_PER_YEAR)) { + days++; // Adjust for no leap year for century year + time->year += days / DAYS_PER_4YEARS * 4; + days %= DAYS_PER_4YEARS; + if (days < DAYS_PER_LEAP_YEAR) { + leap_year = 1; + } else { + days--; // Adjust for leap year for first of 4 years + time->year += days / DAYS_PER_YEAR; + days %= DAYS_PER_YEAR; + } + } + + // Compute month and day of the month + if (days < 31 + 28 + leap_year) { + if (days < 31) { + /* January */ + time->month = 1; + time->day = days + 1; + } else { + /* February */ + time->month = 2; + time->day = days + 1 - 31; + } + } else { + /* March - December */ + enum { NUM_MONTHS = 10 }; + static const unsigned short month[NUM_MONTHS] = { + 0, + 31, + 31 + 30, + 31 + 30 + 31, + 31 + 30 + 31 + 30, + 31 + 30 + 31 + 30 + 31, + 31 + 30 + 31 + 30 + 31 + 31, + 31 + 30 + 31 + 30 + 31 + 31 + 30, + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30}; + unsigned short value; // Value from table + unsigned char mon; // Index to month[] + + days -= 31 + 28 + leap_year; + // Look up month + for (mon = NUM_MONTHS; days < (value = (month[--mon]));) + ; + time->day = days - value + 1; + time->month = mon + 2 + 1; + } + return true; +} + +bool SI47XX_GetLocalTime(Time *time) { + // Look for date/time info + if (rds.offset == NO_DATE_TIME) + return false; // No date or time info available + + // Convert UTC to local time + /* Note: If the offset is negative, 'hour' and 'minute' could become negative. + * To compensate, we add 24 to hour and 60 to minute. We then do a modulus + * division (%24 and %60) to correct for any overflow caused by either a + * positive offset or the above mentioned addition. + */ + time->hour = (rds.hour + rds.offset / 2 + 24) % 24; + time->minute = (rds.minute + rds.offset % 2 * 30 + 60) % 60; + return true; +} + +void SI47XX_GetProgramType(char buffer[17]) { + typedef struct { + char *pRds; + char *pRdbs; + } RDS_PTY; + + static const RDS_PTY PTY_NAMES[] = { + {"No program type", "No program type"}, + {"News", "News"}, + {"Current affairs", "Information"}, + {"Information", "Sport"}, + {"Sport", "Talk"}, + {"Education", "Rock"}, + {"Drama", "Classic Rock"}, + {"Culture", "Adult Hits"}, + {"Science", "Soft Rock"}, + {"Variable", "Top 40"}, + {"Pop", "Country Music"}, + {"Rock", "Music Oldies"}, + {"Easy listening", "Soft Music"}, + {"Light classical", "Nostalgia"}, + {"Serious classical", "Jazz"}, + {"Other Music", "Classical"}, + {"Weather", "Rhythm and Blues"}, + {"Finance", "Soft Rhythm and Blues"}, + {"Children's programs", "Language"}, + {"Social Affairs", "Religious Music"}, + {"Religion", "Religious Talk"}, + {"Phone-in talk", "Personality"}, + {"Travel", "Public"}, + {"Leisure", "College"}, + {"Jazz Music", "Unassigned"}, + {"Country Music", "Unassigned"}, + {"National Music", "Unassigned"}, + {"Oldies Music", "Unassigned"}, + {"Folk Music", "Unassigned"}, + {"Documentary", "Weather"}, + {"Alarm Test", "Emergency Test"}, + {"Alarm", "Emergency"}, + }; + + const RDS_PTY *pty = &PTY_NAMES[rds.programType]; + if (rds.RBDS) { + strncpy(buffer, pty->pRdbs, 16); + } else { + strncpy(buffer, pty->pRds, 16); + } + buffer[16] = '\0'; +} diff --git a/src/helper/rds.h b/src/helper/rds.h new file mode 100644 index 0000000..6a263b5 --- /dev/null +++ b/src/helper/rds.h @@ -0,0 +1,136 @@ +#ifndef RDS_H +#define RDS_H + +#include +#include + +typedef union { + struct { + // status ("RESP0") + uint8_t STCINT : 1; + uint8_t DUMMY1 : 1; + uint8_t RDSINT : 1; + uint8_t RSQINT : 1; + uint8_t DUMMY2 : 2; + uint8_t ERR : 1; + uint8_t CTS : 1; + // RESP1 + uint8_t RDSRECV : 1; //!< RDS Received; 1 = FIFO filled to minimum number + //!< of groups set by RDSFIFOCNT. + uint8_t RDSSYNCLOST : 1; //!< RDS Sync Lost; 1 = Lost RDS synchronization. + uint8_t + RDSSYNCFOUND : 1; //!< RDS Sync Found; 1 = Found RDS synchronization. + uint8_t DUMMY3 : 1; + uint8_t RDSNEWBLOCKA : 1; //!< RDS New Block A; 1 = Valid Block A data has + //!< been received. + uint8_t RDSNEWBLOCKB : 1; //!< RDS New Block B; 1 = Valid Block B data has + //!< been received. + uint8_t DUMMY4 : 2; + // RESP2 + uint8_t RDSSYNC : 1; //!< RDS Sync; 1 = RDS currently synchronized. + uint8_t DUMMY5 : 1; + uint8_t GRPLOST : 1; //!< Group Lost; 1 = One or more RDS groups discarded + //!< due to FIFO overrun. + uint8_t DUMMY6 : 5; + // RESP3 to RESP11 + uint8_t RDSFIFOUSED; //!< RESP3 - RDS FIFO Used; Number of groups remaining + //!< in the RDS FIFO (0 if empty). + uint8_t BLOCKAH; //!< RESP4 - RDS Block A; HIGH byte + uint8_t BLOCKAL; //!< RESP5 - RDS Block A; LOW byte + uint8_t BLOCKBH; //!< RESP6 - RDS Block B; HIGH byte + uint8_t BLOCKBL; //!< RESP7 - RDS Block B; LOW byte + uint8_t BLOCKCH; //!< RESP8 - RDS Block C; HIGH byte + uint8_t BLOCKCL; //!< RESP9 - RDS Block C; LOW byte + uint8_t BLOCKDH; //!< RESP10 - RDS Block D; HIGH byte + uint8_t BLOCKDL; //!< RESP11 - RDS Block D; LOW byte + // RESP12 - Blocks A to D Corrected Errors. + // 0 = No errors; + // 1 = 1–2 bit errors detected and corrected; + // 2 = 3–5 bit errors detected and corrected. + // 3 = Uncorrectable. + uint8_t BLED : 2; + uint8_t BLEC : 2; + uint8_t BLEB : 2; + uint8_t BLEA : 2; + } resp; + uint8_t raw[13]; +} si47x_rds_status; + +typedef signed char ternary; +/* RDS and RBDS data */ +typedef struct { + uint16_t + programId; // Program Identification (PI) code - unique code assigned to + // program. In the US, except for simulcast stations, each + // station has a unique PI. PI = 0 if no RDS info received. + /* groupA and groupB indicate if the station has broadcast one or more of each + * RDS group type and version. There is one bit for each group type. Bit + * number 0 is for group type 0, and so on. groupA gives version A groups + * (packets), groupB gives version B groups. If a bit is true then one or more + * of that group type and version has been received. Example: If (groupA & + * 1<<4) is true then at least one Group type 4, version A group (packet) has + * been received. Note: If the RDS signal is weak, many bad packets will be + * received. Sometimes, the packets are so corrupted that the radio thinks + * the bad data is OK. This can cause false information to be recorded in the + * groupA and groupB variables. + */ + uint16_t groupA; // One bit for each group type, version A + uint16_t groupB; // One bit for each group type, version B + bool RDSSignal; // True if RDS (or RBDS) signal currently detected + bool RBDS; // True if station using RBDS, else using RDS + uint8_t programType; // Program Type (PTY) code - identifies program format - + // call getProgramTypeStr() + uint8_t extendedCountryCode; // Extended Country Code (ECC) - constants + // defined above + uint8_t language; // Language Code - constants defined above + ternary trafficProgram; // Traffic Program flag - True if station gives + // Traffic Alerts + ternary trafficAlert; // Traffic Alert flag - True if station currently + // broadcasting Traffic Alert + ternary + music; // Music/speech flag - True if broadcasting music, false if speech + ternary dynamicPTY; // Dynamic PTY flag - True if dynamic (changing) PTY, + // false if static PTY + ternary compressedAudio; // Compressed audio flag - True if compressed audio, + // false if not compressed + ternary binauralAudio; // Binaural audio flag - True if binaural audio, false + // if not binaural audio + ternary RDSStereo; // RDS stereo/mono flag - True if RDS info says station is + // stereo, false if mono + char programService[9]; // Station's name or slogan - usually used like Radio + // Text + uint8_t radioTextLen; // Length of Radio Text message + char radioText[65]; // Descriptive message from station + char programTypeName[9]; // Program Type Name (PTYN) + unsigned long MJD; // UTC Modified Julian Date - origin is November 17, 1858 + uint8_t hour; // UTC Hour + uint8_t minute; // UTC Minute + signed char + offset; // Offset measured in half hours to convert UTC to local time. + // If offset==NO_DATE_TIME then MJD, hour, minute are invalid. +} RDS; + +typedef struct DateTime { + uint16_t year; + uint8_t month; + uint8_t day; + uint8_t wday; // Day of the week, Sunday = 0 + uint8_t hour; + uint8_t minute; +} DateTime; + +typedef struct Time { + uint8_t hour; + uint8_t minute; +} Time; + +bool SI47XX_GetLocalDateTime(DateTime *time); +bool SI47XX_GetLocalTime(Time *time); +void SI47XX_GetProgramType(char buffer[17]); +void SI47XX_ClearRDS(); +bool SI47XX_GetRDS(); + +extern RDS rds; +extern si47x_rds_status rdsResponse; + +#endif /* end of include guard: RDS_H */ diff --git a/src/helper/vfos.c b/src/helper/vfos.c index 52a979d..1035446 100644 --- a/src/helper/vfos.c +++ b/src/helper/vfos.c @@ -1,6 +1,5 @@ #include "vfos.h" #include "../driver/eeprom.h" -#include "../driver/uart.h" void VFOS_Load(uint16_t num, VFO *p) { EEPROM_ReadBuffer(VFOS_OFFSET + num * VFO_SIZE, p, VFO_SIZE); diff --git a/src/main.c b/src/main.c index fcab43d..a6f23c5 100644 --- a/src/main.c +++ b/src/main.c @@ -2,14 +2,15 @@ #include "board.h" #include "driver/audio.h" #include "driver/backlight.h" -#include "driver/bk4819.h" #include "driver/eeprom.h" #include "driver/keyboard.h" #include "driver/st7565.h" #include "driver/system.h" #include "driver/systick.h" #include "driver/uart.h" +#include "external/CMSIS_5/Device/ARM/ARMCM0/Include/ARMCM0.h" #include "helper/battery.h" +#include "helper/channels.h" #include "helper/presetlist.h" #include "radio.h" #include "scheduler.h" @@ -20,30 +21,32 @@ #include #include -void _putchar(char c) {} - -static void selfTest(void) { +static void Boot(AppType_t appToRun) { + SVC_Toggle(SVC_KEYBOARD, true, 10); + SVC_Toggle(SVC_LISTEN, true, 10); + SVC_Toggle(SVC_APPS, true, 1); + SVC_Toggle(SVC_SYS, true, 1000); - uint8_t buf[8]; - for (uint8_t i = 0; i < 8; ++i) { - buf[i] = i; - } - EEPROM_WriteBuffer(0, buf, 8); - EEPROM_WriteBuffer(262144 - 8, buf, 8); + APPS_run(appToRun); +} - PrintSmall(0, 16, "Bytes are written"); - ST7565_Blit(); +void _putchar(char c) { UART_Send((uint8_t *)&c, 1); } - while (true) - continue; +void uartHandle() { + if (UART_IsCommandAvailable()) { + __disable_irq(); + UART_HandleCommand(); + __enable_irq(); + } } static void unreborn(void) { uint8_t tpl[128]; - memset(tpl, 0xFF, 128); - UI_ClearScreen(); const uint32_t EEPROM_SIZE = SETTINGS_GetEEPROMSize(); const uint8_t PAGE_SIZE = SETTINGS_GetPageSize(); + + memset(tpl, 0xFF, 128); + for (uint16_t i = 0; i < EEPROM_SIZE; i += PAGE_SIZE) { EEPROM_WriteBuffer(i, tpl, PAGE_SIZE); UI_ClearScreen(); @@ -51,97 +54,58 @@ static void unreborn(void) { i * 100 / EEPROM_SIZE); ST7565_Blit(); } + UI_ClearScreen(); PrintMediumEx(LCD_XCENTER, LCD_YCENTER, POS_C, C_FILL, "0xFFed !!!"); ST7565_Blit(); + while (true) continue; } -static void reset(void) { - SVC_Toggle(SVC_APPS, true, 1); - APPS_run(APP_RESET); - while (true) { - TasksUpdate(); - } -} - -// TODO: - -// static void TX(void) { -// DEV = 300 for SSB -// SAVE 74, dev -// } - -static void AddTasks(void) { - SVC_Toggle(SVC_KEYBOARD, true, 10); - SVC_Toggle(SVC_LISTEN, true, 10); - SVC_Toggle(SVC_APPS, true, 1); - SVC_Toggle(SVC_SYS, true, 1000); - - APPS_run(gSettings.mainApp); -} - -static uint8_t introIndex = 0; static void Intro(void) { - char pb[] = "-\\|/"; UI_ClearScreen(); - PrintMedium(4, 0 + 12, "OSFW"); - PrintMedium(16, 2 * 8 + 12, "reb0rn"); - PrintMedium(72, 2 * 8 + 12, "%c", pb[introIndex & 3]); - PrintSmall(96, 46, "by fagci"); + PrintMediumBoldEx(LCD_XCENTER, LCD_YCENTER, POS_C, C_FILL, "r3b0rn"); ST7565_Blit(); if (PRESETS_Load()) { - if (gSettings.beep) + if (gSettings.beep) { AUDIO_PlayTone(1400, 50); + } + + UI_ClearScreen(); + PrintMediumBoldEx(LCD_XCENTER, LCD_YCENTER, POS_C, C_FILL, "(^__^)"); + ST7565_Blit(); TaskRemove(Intro); - if (gSettings.beep) + + Boot(gSettings.mainApp); + + if (gSettings.beep) { AUDIO_PlayTone(1400, 50); - AddTasks(); - Log("SETTINGS %02u sz %02u", SETTINGS_OFFSET, SETTINGS_SIZE); - Log("VFO1 %02u sz %02u", VFOS_OFFSET, VFO_SIZE); - Log("VFO2 %02u sz %02u", VFOS_OFFSET + VFO_SIZE, VFO_SIZE); - Log("PRESET %02u sz %02u", PRESETS_OFFSET, PRESET_SIZE); - Log("P22 BW: %u", PRESETS_Item(22)->band.bw); - - RADIO_LoadCurrentVFO(); + } } } void Main(void) { - SYSTICK_Init(); + gSettings.contrast = 6; SYSTEM_ConfigureSysCon(); - + SYSTICK_Init(); BOARD_Init(); - BACKLIGHT_Toggle(true); + + UART_Init(); + UART_Send("fagci r3b0rn", 13); + + BACKLIGHT_SetBrightness(7); + SVC_Toggle(SVC_RENDER, true, 25); + KEY_Code_t pressedKey = KEYBOARD_Poll(); - if (pressedKey == KEY_EXIT) { - BACKLIGHT_SetDuration(120); - BACKLIGHT_SetBrightness(15); - BACKLIGHT_On(); - reset(); - } else if (pressedKey == KEY_7) { - BACKLIGHT_SetDuration(120); - BACKLIGHT_SetBrightness(15); - BACKLIGHT_On(); + if (pressedKey == KEY_7) { unreborn(); } SETTINGS_Load(); - // gSettings.eepromType = EEPROM_M24M02; - - /* if (gSettings.checkbyte != EEPROM_CHECKBYTE) { - gSettings.eepromType = EEPROM_BL24C64; - BACKLIGHT_SetDuration(120); - BACKLIGHT_SetBrightness(15); - BACKLIGHT_On(); - reset(); - } */ - - UART_Init(); BATTERY_UpdateBatteryInfo(); RADIO_SetupRegisters(); @@ -149,38 +113,18 @@ void Main(void) { BACKLIGHT_SetDuration(BL_TIME_VALUES[gSettings.backlight]); BACKLIGHT_SetBrightness(gSettings.brightness); BACKLIGHT_On(); + ST7565_Init(); - if (KEYBOARD_Poll() == KEY_STAR) { - PrintMediumEx(0, 7, POS_L, C_FILL, "SET: %u %u", SETTINGS_OFFSET, - SETTINGS_SIZE); - PrintMediumEx(0, 7 + 8, POS_L, C_FILL, "VFO: %u %u", VFOS_OFFSET, VFO_SIZE); - PrintMediumEx(0, 7 + 16, POS_L, C_FILL, "PRES CNT: %u", - gSettings.presetsCount); - ST7565_Blit(); - } else if (KEYBOARD_Poll() == KEY_F) { - UART_IsLogEnabled = 5; - TaskAdd("Intro", Intro, 2, true, 5); - } else if (KEYBOARD_Poll() == KEY_MENU) { - selfTest(); - /* PrintMediumEx(LCD_WIDTH - 1, 7, POS_R, C_FILL, "%u", PRESETS_Size()); - for (uint8_t i = 0; i < PRESETS_Size(); ++i) { - Preset p; - PRESETS_LoadPreset(i, &p); - PrintSmall(i / 10 * 40, 6 * (i % 10) + 6, "%u - %u", - p.band.bounds.start / 100000, p.band.bounds.end / 100000); - } - ST7565_Blit(); */ + if (pressedKey == KEY_EXIT) { + Boot(APP_RESET); } else if (KEYBOARD_Poll() == KEY_5) { - SVC_Toggle(SVC_KEYBOARD, true, 10); - SVC_Toggle(SVC_LISTEN, true, 10); - SVC_Toggle(SVC_APPS, true, 1); - SVC_Toggle(SVC_SYS, true, 1000); - - APPS_run(APP_TEST); + Boot(APP_MEMVIEW); } else { - TaskAdd("Intro", Intro, 2, true, 5); + TaskAdd("Intro", Intro, 1, true, 5); } + TaskAdd("UART", uartHandle, 10, true, 0); + while (true) { TasksUpdate(); // TODO: check if delay not needed or something } diff --git a/src/radio.c b/src/radio.c index 1bbb0b8..8bbb386 100644 --- a/src/radio.c +++ b/src/radio.c @@ -2,7 +2,6 @@ #include "apps/apps.h" #include "driver/audio.h" #include "driver/backlight.h" -#include "driver/bk1080.h" #include "driver/bk4819.h" #include "driver/gpio.h" #include "driver/st7565.h" @@ -13,7 +12,6 @@ #include "helper/channels.h" #include "helper/lootlist.h" #include "helper/measurements.h" -#include "helper/msghelper.h" #include "helper/presetlist.h" #include "helper/vfos.h" #include "inc/dp32g030/gpio.h" @@ -56,9 +54,9 @@ const char *upConverterFreqNames[3] = {"None", "50M", "125M"}; const char *modulationTypeOptions[6] = {"FM", "AM", "SSB", "BYP", "RAW", "WFM"}; const char *powerNames[] = {"LOW", "MID", "HIGH"}; const char *bwNames[3] = {"25k", "12.5k", "6.25k"}; -const char *TX_STATE_NAMES[7] = {"TX Off", "TX On", "VOL HIGH", - "BAT LOW", "DISABLED", "UPCONVERTER", - "POWER OVERDRIVE"}; +const char *TX_STATE_NAMES[7] = {"TX Off", "TX On", "VOL HIGH", + "BAT LOW", "DISABLED", "UPCONVERTER", + "HIGH POWER"}; const SquelchType sqTypeValues[4] = { SQUELCH_RSSI_NOISE_GLITCH, @@ -146,15 +144,11 @@ void toggleBK4819(bool on) { void toggleBK1080(bool on) { if (on) { - BK1080_Init(radio->rx.f, true); - BK1080_Mute(false); SYSTEM_DelayMs(10); AUDIO_ToggleSpeaker(true); } else { AUDIO_ToggleSpeaker(false); SYSTEM_DelayMs(10); - BK1080_Mute(true); - BK1080_Init(0, false); } } @@ -178,11 +172,11 @@ void RADIO_ToggleRX(bool on) { } } - if (isBK1080) { + /* if (isBK1080) { toggleBK1080(on); - } else { - toggleBK4819(on); - } + } else { */ + toggleBK4819(on); + // } } void RADIO_EnableCxCSS(void) { @@ -270,8 +264,8 @@ void RADIO_ToggleTX(bool on) { gTxState = TX_VOL_HIGH; return; } - power = calculateOutputPower(gCurrentPreset, radio->tx.f); - if (power > 0xAA) { + power = calculateOutputPower(txPreset, txF); + if (power > 0x91) { power = 0; gTxState = TX_POW_OVERDRIVE; return; @@ -293,7 +287,7 @@ void RADIO_ToggleTX(bool on) { SYSTEM_DelayMs(10); BK4819_ToggleGpioOut(BK4819_GPIO1_PIN29_PA_ENABLE, true); SYSTEM_DelayMs(5); - BK4819_SetupPowerAmplifier(power, radio->tx.f); + BK4819_SetupPowerAmplifier(power, txF); SYSTEM_DelayMs(10); BK4819_ExitSubAu(); } else if (gTxState == TX_ON) { @@ -314,7 +308,7 @@ void RADIO_ToggleTX(bool on) { gTxState = on; } -void RADIO_ToggleBK1080(bool on) { +/* void RADIO_ToggleBK1080(bool on) { if (on == isBK1080) { return; } @@ -327,10 +321,10 @@ void RADIO_ToggleBK1080(bool on) { toggleBK1080(false); BK4819_RX_TurnOn(); } -} +} */ void RADIO_SetModulationByPreset(void) { - ModulationType mod = gCurrentPreset->band.modulation; + /* ModulationType mod = gCurrentPreset->band.modulation; if (mod == MOD_WFM) { if (RADIO_IsBK1080Range(radio->rx.f)) { RADIO_ToggleBK1080(true); @@ -338,7 +332,7 @@ void RADIO_SetModulationByPreset(void) { } gCurrentPreset->band.modulation = MOD_FM; } - RADIO_ToggleBK1080(false); + RADIO_ToggleBK1080(false); */ BK4819_SetModulation(gCurrentPreset->band.modulation); onPresetUpdate(); } @@ -387,11 +381,11 @@ void RADIO_SetSquelchPure(uint32_t f, uint8_t sql) { void RADIO_TuneToPure(uint32_t f, bool precise) { LOOT_Replace(&gLoot[gSettings.activeVFO], f); - if (isBK1080) { - BK1080_SetFrequency(f); - } else { - BK4819_TuneTo(f, precise); - } + /* if (isBK1080) { + // BK1080_SetFrequency(f); + } else { */ + BK4819_TuneTo(f, precise); + // } } void RADIO_SetupByCurrentVFO(void) { @@ -399,16 +393,13 @@ void RADIO_SetupByCurrentVFO(void) { Preset *p = PRESET_ByFrequency(f); - if (p != gCurrentPreset) { - gVFOPresets[gSettings.activeVFO] = gCurrentPreset = p; + if (gCurrentPreset != p) { + gCurrentPreset = p; + gVFOPresets[gSettings.activeVFO] = gCurrentPreset; gSettings.activePreset = PRESET_GetCurrentIndex(); RADIO_SetupBandParams(&gCurrentPreset->band); - // NOTE: commented coz we think, that band not contains boundary - // BK4819_Squelch(gCurrentPreset->band.squelch, f); - - RADIO_ToggleBK1080(gCurrentPreset->band.modulation == MOD_WFM && - RADIO_IsBK1080Range(f)); + RADIO_ToggleRX(false); // to prevent muting when tune to new band } RADIO_TuneToPure(f, true); @@ -464,6 +455,7 @@ void RADIO_LoadCurrentVFO(void) { radio = &gVFO[gSettings.activeVFO]; gCurrentLoot = &gLoot[gSettings.activeVFO]; RADIO_SetupByCurrentVFO(); + RADIO_SetupBandParams(&gCurrentPreset->band); } void RADIO_SetSquelch(uint8_t sq) { @@ -484,7 +476,7 @@ void RADIO_SetGain(uint8_t gainIndex) { void RADIO_SetupBandParams(Band *b) { uint32_t fMid = b->bounds.start + (b->bounds.end - b->bounds.start) / 2; - BK4819_SelectFilter(fMid); + // BK4819_SelectFilter(fMid); // not needeed as evety BK4819_TuneTo() it works BK4819_SquelchType(b->squelchType); BK4819_Squelch(b->squelch, fMid, gSettings.sqlOpenTime, gSettings.sqlCloseTime); @@ -684,16 +676,17 @@ void RADIO_NextFreq(bool next) { } Preset *nextPreset = PRESET_ByFrequency(radio->rx.f + dir); + Band *nextBand = &nextPreset->band; + uint32_t nextBandStep = StepFrequencyTable[nextBand->step]; + if (nextPreset != gCurrentPreset && nextPreset != &defaultPreset) { if (next) { - RADIO_TuneTo(nextPreset->band.bounds.start); + RADIO_TuneTo(nextBand->bounds.start); } else { - RADIO_TuneTo(nextPreset->band.bounds.end - - nextPreset->band.bounds.end % - StepFrequencyTable[nextPreset->band.step]); + RADIO_TuneTo(nextBand->bounds.end - nextBand->bounds.end % nextBandStep); } } else { - RADIO_TuneTo(radio->rx.f + StepFrequencyTable[nextPreset->band.step] * dir); + RADIO_TuneTo(radio->rx.f + nextBandStep * dir); } onVfoUpdate(); } diff --git a/src/scheduler.c b/src/scheduler.c index 94ffc40..96544c7 100644 --- a/src/scheduler.c +++ b/src/scheduler.c @@ -1,13 +1,23 @@ #include "scheduler.h" -#include "driver/uart.h" -volatile Task tasks[TASKS_MAX]; -uint8_t tasksCount = 0; -volatile uint32_t elapsedMilliseconds = 0; +static uint32_t elapsedMilliseconds = 0; + +Task tasks[TASKS_MAX]; +static uint8_t tasksCount = 0; + +static void handle(Task *task) { task->handler(); } + +static int8_t taskIndex(void (*handler)(void)) { + for (int8_t i = 0; i < tasksCount; ++i) { + if ((&tasks[i])->handler == handler) { + return i; + } + } + return -1; +} Task *TaskAdd(const char *name, void (*handler)(void), uint16_t interval, bool continuous, uint8_t priority) { - UART_logf(3, "TaskAdd(%s)", name); if (tasksCount == TASKS_MAX) { return NULL; } @@ -25,70 +35,44 @@ Task *TaskAdd(const char *name, void (*handler)(void), uint16_t interval, } } - tasks[insertI] = - (Task){name, handler, interval, interval, continuous, priority, false}; + tasks[insertI] = (Task){ + .name = name, + .handler = handler, + .interval = interval, + .countdown = interval, + .continuous = continuous, + .priority = priority, + .active = false, + }; tasksCount++; return &tasks[insertI]; } void TaskRemove(void (*handler)(void)) { - uint8_t i; - Task *t; - for (i = 0; i < tasksCount; ++i) { - t = &tasks[i]; - if (t->handler == handler) { - t->handler = NULL; - UART_logf(3, "TaskRemove(%s)", t->name); - tasksCount--; - break; - } + int8_t i = taskIndex(handler); + if (i == -1) { + return; } + tasksCount--; for (; i < tasksCount; ++i) { - if (tasks[i].handler == NULL && tasks[i + 1].handler != NULL) { - tasks[i] = tasks[i + 1]; - tasks[i + 1].handler = NULL; - } + tasks[i] = tasks[i + 1]; } } -bool TaskExists(void (*handler)(void)) { - uint8_t i; - Task *t; - for (i = 0; i < tasksCount; ++i) { - t = &tasks[i]; - if (t->handler == handler) { - return true; - } - } - return false; -} +bool TaskExists(void (*handler)(void)) { return taskIndex(handler) != -1; } void TaskTouch(void (*handler)(void)) { - Task *t; - for (uint8_t i = 0; i < tasksCount; ++i) { - t = &tasks[i]; - if (t->handler == handler) { - t->countdown = 0; - UART_logf(3, "TaskTouch(%s)", t->name); - return; - } + int8_t i = taskIndex(handler); + if (i != -1) { + (&tasks[i])->countdown = 0; } } -static void handle(Task *task) { - UART_logf(3, "%s::handle() start", task->name); - task->handler(); - UART_logf(3, "%s::handle() end", task->name); -} - void TasksUpdate(void) { - Task *task; for (uint8_t i = 0; i < tasksCount; ++i) { - tasks[i].active = true; - } - for (uint8_t i = 0; i < tasksCount; ++i) { - task = &tasks[i]; - if (task->handler && !task->countdown) { + Task *task = &tasks[i]; + task->active = true; + if (!task->countdown) { handle(task); if (task->continuous) { task->countdown = task->interval; @@ -100,25 +84,19 @@ void TasksUpdate(void) { } void SystickHandler(void) { - Task *task; + elapsedMilliseconds++; for (uint8_t i = 0; i < tasksCount; ++i) { - task = &tasks[i]; - if (task->active && task->handler && task->countdown) { + Task *task = &tasks[i]; + if (task->active && task->countdown) { --task->countdown; } } - elapsedMilliseconds++; } uint32_t Now(void) { return elapsedMilliseconds; } void SetTimeout(uint32_t *v, uint32_t t) { - uint32_t max = (uint32_t)0 - 1; - if (t == max) { - *v = max; - return; - } - *v = Now() + t; + *v = t == UINT32_MAX ? UINT32_MAX : Now() + t; } bool CheckTimeout(uint32_t *v) { return Now() >= *v; } diff --git a/src/scheduler.h b/src/scheduler.h index 1c0b31f..ff4e335 100644 --- a/src/scheduler.h +++ b/src/scheduler.h @@ -5,18 +5,17 @@ #include #include -#define TASKS_MAX 64 +#define TASKS_MAX 32 -typedef volatile struct { - const char *name; - void (*handler)(void); +typedef struct { uint16_t interval; uint16_t countdown; - bool continuous; + const char *name; + void (*handler)(void); uint8_t priority; + bool continuous; bool active; } Task; -extern volatile uint32_t elapsedMilliseconds; Task *TaskAdd(const char *name, void (*handler)(void), uint16_t interval, bool continuous, uint8_t priority); @@ -29,6 +28,6 @@ uint32_t Now(void); void SetTimeout(uint32_t *v, uint32_t t); bool CheckTimeout(uint32_t *v); -extern volatile Task tasks[TASKS_MAX]; +extern Task tasks[TASKS_MAX]; #endif /* end of include guard: SCHEDULER_H */ diff --git a/src/settings.c b/src/settings.c index 5f675de..35a95f0 100644 --- a/src/settings.c +++ b/src/settings.c @@ -12,14 +12,14 @@ const char *BL_SQL_MODE_NAMES[3] = {"Off", "On", "Open"}; const char *TX_POWER_NAMES[3] = {"Low", "Mid", "High"}; const char *TX_OFFSET_NAMES[3] = {"Unset", "+", "-"}; const char *EEPROM_TYPE_NAMES[8] = { - "Undefined 1", // 000 - "Undefined 2", // 001 - "BL24C64 (default)", // 010 - "BL24C128", // 011 - "BL24C256", // 100 - "BL24C512", // 101 - "BL24C1024", // 110 - "M24M02 (x1)", // 111 + "none 1", // 000 + "none 2", // 001 + "BL24C64 (stock)", // 010 + "BL24C128", // 011 + "BL24C256", // 100 + "BL24C512", // 101 + "BL24C1024", // 110 + "M24M02 (x1)", // 111 }; const uint32_t EEPROM_SIZES[8] = { @@ -33,14 +33,14 @@ const uint32_t EEPROM_SIZES[8] = { 262144, // 111 }; -const uint8_t PAGE_SIZES[8] = { +const uint16_t PAGE_SIZES[8] = { 32, // 000 32, // 001 32, // 010 - 32, // 011 - 32, // 100 - 32, // 101 - 32, // 110 + 64, // 011 + 64, // 100 + 128, // 101 + 128, // 110 128, // 111 }; @@ -65,4 +65,4 @@ uint32_t SETTINGS_GetEEPROMSize(void) { return EEPROM_SIZES[gSettings.eepromType]; } -uint8_t SETTINGS_GetPageSize(void) { return PAGE_SIZES[gSettings.eepromType]; } +uint16_t SETTINGS_GetPageSize(void) { return PAGE_SIZES[gSettings.eepromType]; } diff --git a/src/settings.h b/src/settings.h index c436601..4f11900 100644 --- a/src/settings.h +++ b/src/settings.h @@ -148,7 +148,7 @@ typedef struct { F rx; F tx; char name[10]; - uint8_t memoryBanks : 8; + uint8_t memoryBanks; ModulationType modulation : 4; BK4819_FilterBandwidth_t bw : 2; TXOutputPower power : 2; @@ -190,11 +190,11 @@ typedef struct { PowerCalibration powCalib; uint32_t lastUsedFreq : 27; uint32_t offset : 26; + Band band; uint8_t memoryBanks : 8; TXOutputPower power : 2; OffsetDirection offsetDir : 2; bool allowTx : 1; - Band band; } __attribute__((packed)) Preset; // getsize(Preset) @@ -211,6 +211,8 @@ typedef struct { #define VFOS_OFFSET (SETTINGS_OFFSET + SETTINGS_SIZE) #define PRESETS_OFFSET (VFOS_OFFSET + VFO_SIZE * 2) +#define PATCH_SIZE 15832 + // settings // VFOs // presets @@ -230,6 +232,6 @@ void SETTINGS_Load(); void SETTINGS_DelayedSave(); uint32_t SETTINGS_GetFilterBound(); uint32_t SETTINGS_GetEEPROMSize(); -uint8_t SETTINGS_GetPageSize(); +uint16_t SETTINGS_GetPageSize(); #endif /* end of include guard: SETTINGS_H */ diff --git a/src/svc.c b/src/svc.c index 63c8dd9..340961a 100644 --- a/src/svc.c +++ b/src/svc.c @@ -1,5 +1,4 @@ #include "svc.h" -#include "driver/uart.h" #include "scheduler.h" #include "svc_apps.h" #include "svc_bat_save.h" diff --git a/src/svc_listening.c b/src/svc_listening.c index 598f633..92051d0 100644 --- a/src/svc_listening.c +++ b/src/svc_listening.c @@ -1,5 +1,4 @@ #include "svc_listening.h" -// #include "apps/messenger.h" #include "driver/bk4819-regs.h" #include "driver/bk4819.h" #include "radio.h" @@ -31,4 +30,5 @@ void SVC_LISTEN_Update(void) { void SVC_LISTEN_Deinit(void) { gListenFn = NULL; BK4819_WriteRegister(BK4819_REG_3F, 0); + RADIO_ToggleRX(false); } diff --git a/src/svc_render.c b/src/svc_render.c index abc3702..c3e7e28 100644 --- a/src/svc_render.c +++ b/src/svc_render.c @@ -9,12 +9,12 @@ static uint32_t lastRender = 0; void SVC_RENDER_Init(void) {} void SVC_RENDER_Update(void) { - if (gRedrawScreen && elapsedMilliseconds - lastRender >= RENDER_TIME) { + if (gRedrawScreen && Now() - lastRender >= RENDER_TIME) { APPS_render(); STATUSLINE_render(); ST7565_Render(); gRedrawScreen = false; - lastRender = elapsedMilliseconds; + lastRender = Now(); } } void SVC_RENDER_Deinit(void) {} diff --git a/src/svc_scan.c b/src/svc_scan.c index 4fb444b..8926e71 100644 --- a/src/svc_scan.c +++ b/src/svc_scan.c @@ -44,10 +44,8 @@ static void next(void) { } } -#include "driver/uart.h" void SVC_SCAN_Init(void) { gScanForward = true; - Log("SCAN init, SF:%u", !!gScanFn); if (!gScanFn) { if (radio->channel >= 0) { gScanFn = RADIO_NextCH; diff --git a/src/ui/graphics.c b/src/ui/graphics.c index ecedce9..b3978a6 100644 --- a/src/ui/graphics.c +++ b/src/ui/graphics.c @@ -16,7 +16,7 @@ } #endif -Cursor cursor = {0, 0}; +static Cursor cursor = {0, 0}; static const GFXfont *fontSmall = &TomThumb; static const GFXfont *fontMedium = &MuMatrix8ptRegular; @@ -55,10 +55,10 @@ static void DrawALine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, _swap_int16_t(x1, y1); } - if (x0 > x1) { + /* if (x0 > x1) { _swap_int16_t(x0, x1); _swap_int16_t(y0, y1); - } + } */ int16_t dx, dy; dx = x1 - x0; @@ -243,10 +243,7 @@ void write(uint8_t c, uint8_t textsize_x, uint8_t textsize_y, bool wrap, } } -void moveTo(uint8_t x, uint8_t y) { - cursor.x = x; - cursor.y = y; -} +void moveTo(uint8_t x, uint8_t y) {} static void printString(const GFXfont *gfxFont, uint8_t x, uint8_t y, Color color, TextPos posLCR, const char *pattern, @@ -256,14 +253,14 @@ static void printString(const GFXfont *gfxFont, uint8_t x, uint8_t y, int16_t x1, y1; uint16_t w, h; - getTextBounds(String, x, y, &x1, &y1, &w, &h, false, - gfxFont); // calc width of new string - if (posLCR == 1) { // centered + getTextBounds(String, x, y, &x1, &y1, &w, &h, false, gfxFont); + if (posLCR == POS_C) { x = x - w / 2; - } else if (posLCR == 2) { + } else if (posLCR == POS_R) { x = x - w; } - moveTo(x, y); + cursor.x = x; + cursor.y = y; for (uint8_t i = 0; i < strlen(String); i++) { write(String[i], 1, 1, true, color, false, gfxFont); } @@ -351,109 +348,3 @@ void PrintSymbolsEx(uint8_t x, uint8_t y, TextPos posLCR, Color color, printString(&Symbols, x, y, color, posLCR, pattern, args); va_end(args); } - -static void fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t corners, - int16_t delta, Color color) { - - int16_t f = 1 - r; - int16_t ddF_x = 1; - int16_t ddF_y = -2 * r; - int16_t x = 0; - int16_t y = r; - int16_t px = x; - int16_t py = y; - - delta++; // Avoid some +1's in the loop - - while (x < y) { - if (f >= 0) { - y--; - ddF_y += 2; - f += ddF_y; - } - x++; - ddF_x += 2; - f += ddF_x; - // These checks avoid double-drawing certain lines, important - // for the SSD1306 library which has an INVERT drawing mode. - if (x < (y + 1)) { - if (corners & 1) - DrawVLine(x0 + x, y0 - y, 2 * y + delta, color); - if (corners & 2) - DrawVLine(x0 - x, y0 - y, 2 * y + delta, color); - } - if (y != py) { - if (corners & 1) - DrawVLine(x0 + py, y0 - px, 2 * px + delta, color); - if (corners & 2) - DrawVLine(x0 - py, y0 - px, 2 * px + delta, color); - py = y; - } - px = x; - } -} - -static void drawCircleHelper(int16_t x0, int16_t y0, int16_t r, - uint8_t cornername, Color color) { - int16_t f = 1 - r; - int16_t ddF_x = 1; - int16_t ddF_y = -2 * r; - int16_t x = 0; - int16_t y = r; - - while (x < y) { - if (f >= 0) { - y--; - ddF_y += 2; - f += ddF_y; - } - x++; - ddF_x += 2; - f += ddF_x; - if (cornername & 0x4) { - PutPixel(x0 + x, y0 + y, color); - PutPixel(x0 + y, y0 + x, color); - } - if (cornername & 0x2) { - PutPixel(x0 + x, y0 - y, color); - PutPixel(x0 + y, y0 - x, color); - } - if (cornername & 0x8) { - PutPixel(x0 - y, y0 + x, color); - PutPixel(x0 - x, y0 + y, color); - } - if (cornername & 0x1) { - PutPixel(x0 - y, y0 - x, color); - PutPixel(x0 - x, y0 - y, color); - } - } -} - -void DrawRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, - Color color) { - int16_t max_radius = ((w < h) ? w : h) / 2; // 1/2 minor axis - if (r > max_radius) - r = max_radius; - // smarter version - DrawHLine(x + r, y, w - 2 * r, color); // Top - DrawHLine(x + r, y + h - 1, w - 2 * r, color); // Bottom - DrawVLine(x, y + r, h - 2 * r, color); // Left - DrawVLine(x + w - 1, y + r, h - 2 * r, color); // Right - // draw four corners - drawCircleHelper(x + r, y + r, r, 1, color); - drawCircleHelper(x + w - r - 1, y + r, r, 2, color); - drawCircleHelper(x + w - r - 1, y + h - r - 1, r, 4, color); - drawCircleHelper(x + r, y + h - r - 1, r, 8, color); -} - -void FillRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, - Color color) { - int16_t max_radius = ((w < h) ? w : h) / 2; // 1/2 minor axis - if (r > max_radius) - r = max_radius; - // smarter version - FillRect(x + r, y, w - 2 * r, h, color); - // draw four corners - fillCircleHelper(x + w - r - 1, y + r, r, 1, h - 2 * r - 1, color); - fillCircleHelper(x + r, y + r, r, 2, h - 2 * r - 1, color); -} diff --git a/src/ui/graphics.h b/src/ui/graphics.h index 2120782..5e7c6c9 100644 --- a/src/ui/graphics.h +++ b/src/ui/graphics.h @@ -44,8 +44,6 @@ typedef struct { uint8_t y; } Cursor; -extern Cursor cursor; - void UI_ClearStatus(); void UI_ClearScreen(); @@ -76,9 +74,4 @@ void PrintBiggestDigitsEx(uint8_t x, uint8_t y, TextPos posLCR, Color color, void PrintSymbolsEx(uint8_t x, uint8_t y, TextPos posLCR, Color color, const char *pattern, ...); -void DrawRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, - Color color); -void FillRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, - Color color); - #endif /* end of include guard: GRAPHICS_H */ diff --git a/src/ui/statusline.c b/src/ui/statusline.c index a08b0ae..378bdc7 100644 --- a/src/ui/statusline.c +++ b/src/ui/statusline.c @@ -1,7 +1,6 @@ #include "statusline.h" #include "../driver/eeprom.h" #include "../driver/st7565.h" -#include "../driver/uart.h" #include "../helper/battery.h" #include "../scheduler.h" #include "../svc.h" @@ -12,13 +11,12 @@ static uint8_t previousBatteryLevel = 255; static bool showBattery = true; -static bool lastEepromRead = false; static bool lastEepromWrite = false; static char statuslineText[32] = {0}; static void eepromRWReset(void) { - lastEepromRead = lastEepromWrite = gEepromRead = gEepromWrite = false; + lastEepromWrite = gEepromWrite = false; gRedrawScreen = true; } @@ -48,8 +46,7 @@ void STATUSLINE_update(void) { gRedrawScreen = true; } - if (lastEepromRead != gEepromRead || lastEepromWrite != gEepromWrite) { - lastEepromRead = gEepromRead; + if (lastEepromWrite != gEepromWrite) { lastEepromWrite = gEepromWrite; gRedrawScreen = true; TaskAdd("EEPROM RW-", eepromRWReset, 500, false, 0); @@ -83,8 +80,6 @@ void STATUSLINE_render(void) { if (gEepromWrite) { icons[idx++] = SYM_EEPROM_W; - /* } else if (gEepromRead) { - icons[idx++] = SYM_EEPROM_R; */ } if (SVC_Running(SVC_SCAN)) { @@ -112,11 +107,7 @@ void STATUSLINE_render(void) { (gSettings.batteryStyle == BAT_VOLTAGE ? 38 : 18), BASE_Y, POS_R, C_FILL, "%s", icons); - if (UART_IsLogEnabled) { - PrintSmall(0, BASE_Y, statuslineText, "D:%u", UART_IsLogEnabled); - } else if (statuslineText[0] >= 32) { - PrintSmall(0, BASE_Y, statuslineText); - } + PrintSmall(0, BASE_Y, statuslineText); // FillRect(0, 0, LCD_WIDTH, 7, C_INVERT); } diff --git a/src/driver/bk1080-regs.h b/temp/bk1080-regs.h similarity index 100% rename from src/driver/bk1080-regs.h rename to temp/bk1080-regs.h diff --git a/src/driver/bk1080.c b/temp/bk1080.c similarity index 99% rename from src/driver/bk1080.c rename to temp/bk1080.c index 533e52a..9ea1752 100644 --- a/src/driver/bk1080.c +++ b/temp/bk1080.c @@ -1,5 +1,4 @@ #include "bk1080.h" -#include "../driver/uart.h" #include "../inc/dp32g030/gpio.h" #include "../misc.h" #include "bk1080-regs.h" diff --git a/src/driver/bk1080.h b/temp/bk1080.h similarity index 100% rename from src/driver/bk1080.h rename to temp/bk1080.h diff --git a/src/ui/fonts/DSEG7_Classic_Mini_Regular_11.h b/temp/fonts/DSEG7_Classic_Mini_Regular_11.h similarity index 100% rename from src/ui/fonts/DSEG7_Classic_Mini_Regular_11.h rename to temp/fonts/DSEG7_Classic_Mini_Regular_11.h diff --git a/src/ui/fonts/Minecraft8.h b/temp/fonts/Minecraft8.h similarity index 100% rename from src/ui/fonts/Minecraft8.h rename to temp/fonts/Minecraft8.h diff --git a/src/ui/fonts/NumbersSoftAce1.h b/temp/fonts/NumbersSoftAce1.h similarity index 100% rename from src/ui/fonts/NumbersSoftAce1.h rename to temp/fonts/NumbersSoftAce1.h diff --git a/src/ui/fonts/NumbersSoftAce2.h b/temp/fonts/NumbersSoftAce2.h similarity index 100% rename from src/ui/fonts/NumbersSoftAce2.h rename to temp/fonts/NumbersSoftAce2.h diff --git a/src/ui/fonts/NumbersSoftAce3.h b/temp/fonts/NumbersSoftAce3.h similarity index 100% rename from src/ui/fonts/NumbersSoftAce3.h rename to temp/fonts/NumbersSoftAce3.h diff --git a/src/ui/fonts/NumbersSoftAce4.h b/temp/fonts/NumbersSoftAce4.h similarity index 100% rename from src/ui/fonts/NumbersSoftAce4.h rename to temp/fonts/NumbersSoftAce4.h diff --git a/src/ui/fonts/NumbersSoftAce5.h b/temp/fonts/NumbersSoftAce5.h similarity index 100% rename from src/ui/fonts/NumbersSoftAce5.h rename to temp/fonts/NumbersSoftAce5.h diff --git a/src/ui/fonts/NumbersSoftAce6.h b/temp/fonts/NumbersSoftAce6.h similarity index 100% rename from src/ui/fonts/NumbersSoftAce6.h rename to temp/fonts/NumbersSoftAce6.h diff --git a/src/ui/fonts/NumbersStepanv2.h b/temp/fonts/NumbersStepanv2.h similarity index 100% rename from src/ui/fonts/NumbersStepanv2.h rename to temp/fonts/NumbersStepanv2.h diff --git a/src/ui/fonts/Numbers_seg_13_16.h b/temp/fonts/Numbers_seg_13_16.h similarity index 100% rename from src/ui/fonts/Numbers_seg_13_16.h rename to temp/fonts/Numbers_seg_13_16.h diff --git a/src/apps/messenger.c b/temp/messenger.c similarity index 100% rename from src/apps/messenger.c rename to temp/messenger.c diff --git a/src/apps/messenger.h b/temp/messenger.h similarity index 100% rename from src/apps/messenger.h rename to temp/messenger.h diff --git a/src/helper/msghelper.c b/temp/msghelper.c similarity index 100% rename from src/helper/msghelper.c rename to temp/msghelper.c diff --git a/src/helper/msghelper.h b/temp/msghelper.h similarity index 100% rename from src/helper/msghelper.h rename to temp/msghelper.h diff --git a/src/apps/taskman.c b/temp/taskman.c similarity index 100% rename from src/apps/taskman.c rename to temp/taskman.c diff --git a/src/apps/taskman.h b/temp/taskman.h similarity index 100% rename from src/apps/taskman.h rename to temp/taskman.h