diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..4b6c3f9 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +FROM archlinux:latest +RUN pacman -Syyu base-devel --noconfirm +RUN pacman -Syyu arm-none-eabi-gcc --noconfirm +RUN pacman -Syyu arm-none-eabi-newlib --noconfirm +RUN pacman -Syyu git --noconfirm +RUN pacman -Syyu python-pip --noconfirm +RUN pacman -Syyu python-crcmod --noconfirm +WORKDIR /app +COPY . . + +RUN git submodule update --init --recursive +#RUN make && cp firmware* compiled-firmware/ diff --git a/Makefile b/Makefile index c7e0521..9e878a2 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ ENABLE_VOICE := 0 ENABLE_VOX := 0 ENABLE_ALARM := 0 ENABLE_TX1750 := 0 -ENABLE_PWRON_PASSWORD := 1 +ENABLE_PWRON_PASSWORD := 0 ENABLE_BIG_FREQ := 0 ENABLE_SMALL_BOLD := 1 ENABLE_KEEP_MEM_NAME := 1 diff --git a/README.md b/README.md index c1051ae..36212d0 100644 --- a/README.md +++ b/README.md @@ -159,13 +159,13 @@ You may obtain a copy of the License at # Example changes/updates

- - - + + +

Video showing the AM fix working .. - + diff --git a/app/action.c b/app/action.c index 3d0ec31..fe07b1d 100644 --- a/app/action.c +++ b/app/action.c @@ -333,6 +333,7 @@ void ACTION_Handle(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld) if (Key == KEY_SIDE1 && !bKeyHeld && bKeyPressed) { gBeepToPlay = BEEP_1KHZ_60MS_OPTIONAL; + if (gDTMF_InputIndex > 0) { gDTMF_InputBox[--gDTMF_InputIndex] = '-'; diff --git a/app/app.c b/app/app.c index c0a284b..e1006ab 100644 --- a/app/app.c +++ b/app/app.c @@ -2256,14 +2256,16 @@ static void APP_ProcessKey(KEY_Code_t Key, bool bKeyPressed, bool bKeyHeld) char Code; if (Key == KEY_SIDE2) - { + { // transmit 1750Hz tone Code = 0xFE; } else { - Code = DTMF_GetCharacter(Key); + Code = DTMF_GetCharacter(Key - KEY_0); if (Code == 0xFF) goto Skip; + + // transmit DTMF keys } if (!bKeyPressed || bKeyHeld) diff --git a/app/dtmf.c b/app/dtmf.c index 83d71d3..b5135ff 100644 --- a/app/dtmf.c +++ b/app/dtmf.c @@ -390,8 +390,9 @@ void DTMF_Reply(void) default: case DTMF_REPLY_NONE: - if (gDTMF_CallState != DTMF_CALL_STATE_NONE || - gCurrentVfo->DTMF_PTT_ID_TX_MODE == PTT_ID_OFF || + if (gDTMF_CallState != DTMF_CALL_STATE_NONE || + gCurrentVfo->DTMF_PTT_ID_TX_MODE == PTT_ID_APOLLO || + gCurrentVfo->DTMF_PTT_ID_TX_MODE == PTT_ID_OFF || gCurrentVfo->DTMF_PTT_ID_TX_MODE == PTT_ID_TX_DOWN) { gDTMF_ReplyState = DTMF_REPLY_NONE; diff --git a/app/main.c b/app/main.c index c7b3659..b650338 100644 --- a/app/main.c +++ b/app/main.c @@ -34,6 +34,9 @@ #include "settings.h" #include "ui/inputbox.h" #include "ui/ui.h" +#ifdef ENABLE_SPECTRUM +// #include "app/spectrum.h" +#endif void toggle_chan_scanlist(void) { // toggle the selected channels scanlist setting diff --git a/app/spectrum.c b/app/spectrum.c new file mode 100644 index 0000000..9d00b86 --- /dev/null +++ b/app/spectrum.c @@ -0,0 +1,1193 @@ +/* Copyright 2023 fagci + * https://github.com/fagci + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "../app/spectrum.h" + +struct FrequencyBandInfo { + uint32_t lower; + uint32_t upper; + uint32_t middle; +}; + +const struct FrequencyBandInfo FrequencyBandTable[7] = { + [BAND1_50MHz ] = {.lower = 1600000, .middle = 6500000, .upper = 7600000}, + [BAND2_108MHz] = {.lower = 10800000, .middle = 12200000, .upper = 13599990}, + [BAND3_136MHz] = {.lower = 13600000, .middle = 15000000, .upper = 17399990}, + [BAND4_174MHz] = {.lower = 17400000, .middle = 26000000, .upper = 34999990}, + [BAND5_350MHz] = {.lower = 35000000, .middle = 37000000, .upper = 39999990}, + [BAND6_400MHz] = {.lower = 40000000, .middle = 43500000, .upper = 46999990}, + [BAND7_470MHz] = {.lower = 47000000, .middle = 55000000, .upper = 130000000}, +}; + + +#define F_MIN FrequencyBandTable[0].lower +#define F_MAX FrequencyBandTable[ARRAY_SIZE(FrequencyBandTable) - 1].upper + +const uint16_t RSSI_MAX_VALUE = 65535; + +static uint16_t R30, R37, R3D, R43, R47, R48, R7E; +static uint32_t initialFreq; +static char String[32]; + +bool isInitialized = false; +bool isListening = true; +bool monitorMode = false; +bool redrawStatus = true; +bool redrawScreen = false; +bool newScanStart = true; +bool preventKeypress = true; +bool audioState = true; + +State currentState = SPECTRUM, previousState = SPECTRUM; + +PeakInfo peak; +ScanInfo scanInfo; +KeyboardState kbd = {KEY_INVALID, KEY_INVALID, 0}; + +const char *bwOptions[] = {" 25k", "12.5k", "6.25k"}; +const char *modulationTypeOptions[] = {" FM", " AM", "USB"}; +const uint8_t modulationTypeTuneSteps[] = {100, 50, 10}; +const uint8_t modTypeReg47Values[] = {1, 7, 5}; + +SpectrumSettings settings = {stepsCount: STEPS_64, + scanStepIndex: S_STEP_25_0kHz, + frequencyChangeStep: 80000, + scanDelay: 3200, + rssiTriggerLevel: 150, + backlightState: true, + bw: BK4819_FILTER_BW_WIDE, + listenBw: BK4819_FILTER_BW_WIDE, + modulationType: false, + dbMin: -130, + dbMax: -50}; + +uint32_t fMeasure = 0; +uint32_t currentFreq, tempFreq; +uint16_t rssiHistory[128] = {}; + +uint8_t freqInputIndex = 0; +uint8_t freqInputDotIndex = 0; +KEY_Code_t freqInputArr[10]; +char freqInputString[11] = "----------\0"; // XXXX.XXXXX\0 + +uint8_t menuState = 0; +uint16_t listenT = 0; + +RegisterSpec registerSpecs[] = { + {}, + {"LNAs", 0x13, 8, 0b11, 1}, + {"LNA", 0x13, 5, 0b111, 1}, + {"PGA", 0x13, 0, 0b111, 1}, + {"IF", 0x3D, 0, 0xFFFF, 0x2aaa}, + // {"MIX", 0x13, 3, 0b11, 1}, // TODO: hidden +}; + +uint16_t statuslineUpdateTimer = 0; + +static uint8_t DBm2S(int dbm) { + uint8_t i = 0; + dbm *= -1; + for (i = 0; i < ARRAY_SIZE(U8RssiMap); i++) { + if (dbm >= U8RssiMap[i]) { + return i; + } + } + return i; +} + +static int Rssi2DBm(uint16_t rssi) { return (rssi >> 1) - 160; } + +static uint16_t GetRegMenuValue(uint8_t st) { + RegisterSpec s = registerSpecs[st]; + return (BK4819_ReadRegister(s.num) >> s.offset) & s.maxValue; +} + +static void SetRegMenuValue(uint8_t st, bool add) { + uint16_t v = GetRegMenuValue(st); + RegisterSpec s = registerSpecs[st]; + + uint16_t reg = BK4819_ReadRegister(s.num); + if (add && v <= s.maxValue - s.inc) { + v += s.inc; + } else if (!add && v >= 0 + s.inc) { + v -= s.inc; + } + // TODO: use max value for bits count in max value, or reset by additional + // mask in spec + reg &= ~(s.maxValue << s.offset); + BK4819_WriteRegister(s.num, reg | (v << s.offset)); + redrawScreen = true; +} + +// GUI functions + +static void PutPixel(uint8_t x, uint8_t y, bool fill) { + if (fill) { + gFrameBuffer[y >> 3][x] |= 1 << (y & 7); + } else { + gFrameBuffer[y >> 3][x] &= ~(1 << (y & 7)); + } +} +static void PutPixelStatus(uint8_t x, uint8_t y, bool fill) { + if (fill) { + gStatusLine[x] |= 1 << y; + } else { + gStatusLine[x] &= ~(1 << y); + } +} + +static void DrawHLine(int sy, int ey, int nx, bool fill) { + for (int i = sy; i <= ey; i++) { + if (i < 56 && nx < 128) { + PutPixel(nx, i, fill); + } + } +} + +static void GUI_DisplaySmallest(const char *pString, uint8_t x, uint8_t y, + bool statusbar, bool fill) { + uint8_t c; + uint8_t pixels; + const uint8_t *p = (const uint8_t *)pString; + + while ((c = *p++) && c != '\0') { + c -= 0x20; + for (int i = 0; i < 3; ++i) { + pixels = gFont3x5[c][i]; + for (int j = 0; j < 6; ++j) { + if (pixels & 1) { + if (statusbar) + PutPixelStatus(x + i, y + j, fill); + else + PutPixel(x + i, y + j, fill); + } + pixels >>= 1; + } + } + x += 4; + } +} + +// Utility functions + +KEY_Code_t GetKey() { + KEY_Code_t btn = KEYBOARD_Poll(); + if (btn == KEY_INVALID && !GPIO_CheckBit(&GPIOC->DATA, GPIOC_PIN_PTT)) { + btn = KEY_PTT; + } + return btn; +} + +static int clamp(int v, int min, int max) { + return v <= min ? min : (v >= max ? max : v); +} + +static uint8_t my_abs(signed v) { return v > 0 ? v : -v; } + +void SetState(State state) { + previousState = currentState; + currentState = state; + redrawScreen = true; + redrawStatus = true; +} + +// Radio functions + +static void ToggleAFBit(bool on) { + uint16_t reg = BK4819_ReadRegister(BK4819_REG_47); + reg &= ~(1 << 8); + if (on) + reg |= on << 8; + BK4819_WriteRegister(BK4819_REG_47, reg); +} + +static void BackupRegisters() { + R30 = BK4819_ReadRegister(0x30); + R37 = BK4819_ReadRegister(0x37); + R3D = BK4819_ReadRegister(0x3D); + R43 = BK4819_ReadRegister(0x43); + R47 = BK4819_ReadRegister(0x47); + R48 = BK4819_ReadRegister(0x48); + R7E = BK4819_ReadRegister(0x7E); +} + +static void RestoreRegisters() { + BK4819_WriteRegister(0x30, R30); + BK4819_WriteRegister(0x37, R37); + BK4819_WriteRegister(0x3D, R3D); + BK4819_WriteRegister(0x43, R43); + BK4819_WriteRegister(0x47, R47); + BK4819_WriteRegister(0x48, R48); + BK4819_WriteRegister(0x7E, R7E); +} + +static void SetModulation(ModulationType type) { + RestoreRegisters(); + uint16_t reg = BK4819_ReadRegister(BK4819_REG_47); + reg &= ~(0b111 << 8); + BK4819_WriteRegister(BK4819_REG_47, reg | (modTypeReg47Values[type] << 8)); + if (type == MOD_USB) { + BK4819_WriteRegister(0x3D, 0b0010101101000101); + BK4819_WriteRegister(BK4819_REG_37, 0x160F); + BK4819_WriteRegister(0x48, 0b0000001110101000); + } +} + +static void ToggleAFDAC(bool on) { + uint32_t Reg = BK4819_ReadRegister(BK4819_REG_30); + Reg &= ~(1 << 9); + if (on) + Reg |= (1 << 9); + BK4819_WriteRegister(BK4819_REG_30, Reg); +} + +static void SetF(uint32_t f) { + fMeasure = f; + + BK4819_SetFrequency(fMeasure); + BK4819_PickRXFilterPathBasedOnFrequency(fMeasure); + uint16_t reg = BK4819_ReadRegister(BK4819_REG_30); + BK4819_WriteRegister(BK4819_REG_30, 0); + BK4819_WriteRegister(BK4819_REG_30, reg); +} + +// Spectrum related + +bool IsPeakOverLevel() { return peak.rssi >= settings.rssiTriggerLevel; } + +static void ResetPeak() { + peak.t = 0; + peak.rssi = 0; +} + +bool IsCenterMode() { return settings.scanStepIndex < S_STEP_2_5kHz; } +uint8_t GetStepsCount() { return 128 >> settings.stepsCount; } +uint16_t GetScanStep() { return scanStepValues[settings.scanStepIndex]; } +uint32_t GetBW() { return GetStepsCount() * GetScanStep(); } +uint32_t GetFStart() { + return IsCenterMode() ? currentFreq - (GetBW() >> 1) : currentFreq; +} +uint32_t GetFEnd() { return currentFreq + GetBW(); } + +static void TuneToPeak() { + scanInfo.f = peak.f; + scanInfo.rssi = peak.rssi; + scanInfo.i = peak.i; + SetF(scanInfo.f); +} + +static void DeInitSpectrum() { + SetF(initialFreq); + RestoreRegisters(); + isInitialized = false; +} + +uint8_t GetBWRegValueForScan() { + return scanStepBWRegValues[settings.scanStepIndex]; +} + +uint16_t GetRssi() { + // SYSTICK_DelayUs(800); + // testing autodelay based on Glitch value + while ((BK4819_ReadRegister(0x63) & 0b11111111) >= 255) { + SYSTICK_DelayUs(100); + } + return BK4819_GetRSSI(); +} + +static void ToggleAudio(bool on) { + if (on == audioState) { + return; + } + audioState = on; + if (on) { + GPIO_SetBit(&GPIOC->DATA, GPIOC_PIN_AUDIO_PATH); + } else { + GPIO_ClearBit(&GPIOC->DATA, GPIOC_PIN_AUDIO_PATH); + } +} + +static void ToggleRX(bool on) { + isListening = on; + + BK4819_ToggleGpioOut(BK4819_GPIO0_PIN28_GREEN, on); + + ToggleAudio(on); + ToggleAFDAC(on); + ToggleAFBit(on); + + if (on) { + listenT = 1000; + BK4819_WriteRegister(0x43, listenBWRegValues[settings.listenBw]); + } else { + BK4819_WriteRegister(0x43, GetBWRegValueForScan()); + } +} + +// Scan info + +static void ResetScanStats() { + scanInfo.rssi = 0; + scanInfo.rssiMax = 0; + scanInfo.iPeak = 0; + scanInfo.fPeak = 0; +} + +static void InitScan() { + ResetScanStats(); + scanInfo.i = 0; + scanInfo.f = GetFStart(); + + scanInfo.scanStep = GetScanStep(); + scanInfo.measurementsCount = GetStepsCount(); +} + +static void ResetBlacklist() { + for (int i = 0; i < 128; ++i) { + if (rssiHistory[i] == RSSI_MAX_VALUE) + rssiHistory[i] = 0; + } +} + +static void RelaunchScan() { + InitScan(); + ResetPeak(); + ToggleRX(false); +#ifdef SPECTRUM_AUTOMATIC_SQUELCH + settings.rssiTriggerLevel = RSSI_MAX_VALUE; +#endif + preventKeypress = true; + scanInfo.rssiMin = RSSI_MAX_VALUE; +} + +static void UpdateScanInfo() { + if (scanInfo.rssi > scanInfo.rssiMax) { + scanInfo.rssiMax = scanInfo.rssi; + scanInfo.fPeak = scanInfo.f; + scanInfo.iPeak = scanInfo.i; + } + + if (scanInfo.rssi < scanInfo.rssiMin) { + scanInfo.rssiMin = scanInfo.rssi; + settings.dbMin = Rssi2DBm(scanInfo.rssiMin); + redrawStatus = true; + } +} + +static void AutoTriggerLevel() { + if (settings.rssiTriggerLevel == RSSI_MAX_VALUE) { + settings.rssiTriggerLevel = clamp(scanInfo.rssiMax + 8, 0, RSSI_MAX_VALUE); + } +} + +static void UpdatePeakInfoForce() { + peak.t = 0; + peak.rssi = scanInfo.rssiMax; + peak.f = scanInfo.fPeak; + peak.i = scanInfo.iPeak; + AutoTriggerLevel(); +} + +static void UpdatePeakInfo() { + if (peak.f == 0 || peak.t >= 1024 || peak.rssi < scanInfo.rssiMax) + UpdatePeakInfoForce(); +} + +static void Measure() { rssiHistory[scanInfo.i] = scanInfo.rssi = GetRssi(); } + +// Update things by keypress + +static void UpdateRssiTriggerLevel(bool inc) { + if (inc) + settings.rssiTriggerLevel += 2; + else + settings.rssiTriggerLevel -= 2; + redrawScreen = true; + redrawStatus = true; +} + +static void UpdateDBMax(bool inc) { + if (inc && settings.dbMax < 10) { + settings.dbMax += 1; + } else if (!inc && settings.dbMax > settings.dbMin) { + settings.dbMax -= 1; + } else { + return; + } + redrawStatus = true; + redrawScreen = true; + SYSTEM_DelayMs(20); +} + +static void UpdateScanStep(bool inc) { + if (inc && settings.scanStepIndex < S_STEP_100_0kHz) { + settings.scanStepIndex++; + } else if (!inc && settings.scanStepIndex > 0) { + settings.scanStepIndex--; + } else { + return; + } + settings.frequencyChangeStep = GetBW() >> 1; + RelaunchScan(); + ResetBlacklist(); + redrawScreen = true; +} + +static void UpdateCurrentFreq(bool inc) { + if (inc && currentFreq < F_MAX) { + currentFreq += settings.frequencyChangeStep; + } else if (!inc && currentFreq > F_MIN) { + currentFreq -= settings.frequencyChangeStep; + } else { + return; + } + RelaunchScan(); + ResetBlacklist(); + redrawScreen = true; +} + +static void UpdateCurrentFreqStill(bool inc) { + uint8_t offset = modulationTypeTuneSteps[settings.modulationType]; + uint32_t f = fMeasure; + if (inc && f < F_MAX) { + f += offset; + } else if (!inc && f > F_MIN) { + f -= offset; + } + SetF(f); + redrawScreen = true; +} + +static void UpdateFreqChangeStep(bool inc) { + uint16_t diff = GetScanStep() * 4; + if (inc && settings.frequencyChangeStep < 200000) { + settings.frequencyChangeStep += diff; + } else if (!inc && settings.frequencyChangeStep > 10000) { + settings.frequencyChangeStep -= diff; + } + SYSTEM_DelayMs(100); + redrawScreen = true; +} + +static void ToggleModulation() { + if (settings.modulationType < MOD_USB) { + settings.modulationType++; + } else { + settings.modulationType = MOD_FM; + } + SetModulation(settings.modulationType); + redrawScreen = true; +} + +static void ToggleListeningBW() { + if (settings.listenBw == BK4819_FILTER_BW_NARROWER) { + settings.listenBw = BK4819_FILTER_BW_WIDE; + } else { + settings.listenBw++; + } + redrawScreen = true; +} + +static void ToggleBacklight() { + settings.backlightState = !settings.backlightState; + if (settings.backlightState) { + GPIO_SetBit(&GPIOB->DATA, GPIOB_PIN_BACKLIGHT); + } else { + GPIO_ClearBit(&GPIOB->DATA, GPIOB_PIN_BACKLIGHT); + } +} + +static void ToggleStepsCount() { + if (settings.stepsCount == STEPS_128) { + settings.stepsCount = STEPS_16; + } else { + settings.stepsCount--; + } + settings.frequencyChangeStep = GetBW() >> 1; + RelaunchScan(); + ResetBlacklist(); + redrawScreen = true; +} + +static void ResetFreqInput() { + tempFreq = 0; + for (int i = 0; i < 10; ++i) { + freqInputString[i] = '-'; + } +} + +static void FreqInput() { + freqInputIndex = 0; + freqInputDotIndex = 0; + ResetFreqInput(); + SetState(FREQ_INPUT); +} + +static void UpdateFreqInput(KEY_Code_t key) { + if (key != KEY_EXIT && freqInputIndex >= 10) { + return; + } + if (key == KEY_STAR) { + if (freqInputIndex == 0 || freqInputDotIndex) { + return; + } + freqInputDotIndex = freqInputIndex; + } + if (key == KEY_EXIT) { + freqInputIndex--; + } else { + freqInputArr[freqInputIndex++] = key; + } + + ResetFreqInput(); + + uint8_t dotIndex = + freqInputDotIndex == 0 ? freqInputIndex : freqInputDotIndex; + + KEY_Code_t digitKey; + for (int i = 0; i < 10; ++i) { + if (i < freqInputIndex) { + digitKey = freqInputArr[i]; + freqInputString[i] = digitKey <= KEY_9 ? '0' + digitKey : '.'; + } else { + freqInputString[i] = '-'; + } + } + + uint32_t base = 100000; // 1MHz in BK units + for (int i = dotIndex - 1; i >= 0; --i) { + tempFreq += freqInputArr[i] * base; + base *= 10; + } + + base = 10000; // 0.1MHz in BK units + if (dotIndex < freqInputIndex) { + for (int i = dotIndex + 1; i < freqInputIndex; ++i) { + tempFreq += freqInputArr[i] * base; + base /= 10; + } + } + redrawScreen = true; +} + +static void Blacklist() { + rssiHistory[peak.i] = RSSI_MAX_VALUE; + ResetPeak(); + ToggleRX(false); + newScanStart = true; +} + +// Draw things + +// applied x2 to prevent initial rounding +uint8_t Rssi2PX(uint16_t rssi, uint8_t pxMin, uint8_t pxMax) { + const int DB_MIN = settings.dbMin << 1; + const int DB_MAX = settings.dbMax << 1; + const int DB_RANGE = DB_MAX - DB_MIN; + + const uint8_t PX_RANGE = pxMax - pxMin; + + int dbm = clamp(rssi - (160 << 1), DB_MIN, DB_MAX); + + return ((dbm - DB_MIN) * PX_RANGE + DB_RANGE / 2) / DB_RANGE + pxMin; +} + +uint8_t Rssi2Y(uint16_t rssi) { + return DrawingEndY - Rssi2PX(rssi, 0, DrawingEndY); +} + +static void DrawSpectrum() { + for (uint8_t x = 0; x < 128; ++x) { + uint16_t rssi = rssiHistory[x >> settings.stepsCount]; + if (rssi != RSSI_MAX_VALUE) { + DrawHLine(Rssi2Y(rssi), DrawingEndY, x, true); + } + } +} + +static void DrawStatus() { +#ifdef SPECTRUM_EXTRA_VALUES + sprintf(String, "%d/%d P:%d T:%d", settings.dbMin, settings.dbMax, + Rssi2DBm(peak.rssi), Rssi2DBm(settings.rssiTriggerLevel)); +#else + sprintf(String, "%d/%d", settings.dbMin, settings.dbMax); +#endif + GUI_DisplaySmallest(String, 0, 1, true, true); + + for (int i = 0; i < 4; i++) { + BOARD_ADC_GetBatteryInfo(&gBatteryVoltages[i], &gBatteryCurrent); + } + + uint16_t Voltage; + uint8_t v = 0; + + Voltage = (gBatteryVoltages[0] + gBatteryVoltages[1] + gBatteryVoltages[2] + + gBatteryVoltages[3]) / + 4; + + if (gBatteryCalibration[5] < Voltage) { + v = 5; + } else if (gBatteryCalibration[4] < Voltage) { + v = 5; + } else if (gBatteryCalibration[3] < Voltage) { + v = 4; + } else if (gBatteryCalibration[2] < Voltage) { + v = 3; + } else if (gBatteryCalibration[1] < Voltage) { + v = 2; + } else if (gBatteryCalibration[0] < Voltage) { + v = 1; + } + + gStatusLine[127] = 0b01111110; + for (int i = 126; i >= 116; i--) { + gStatusLine[i] = 0b01000010; + } + v <<= 1; + for (int i = 125; i >= 116; i--) { + if (126 - i <= v) { + gStatusLine[i + 2] = 0b01111110; + } + } + gStatusLine[117] = 0b01111110; + gStatusLine[116] = 0b00011000; +} + +static void DrawF(uint32_t f) { + sprintf(String, "%u.%05u", f / 100000, f % 100000); + UI_PrintStringSmall(String, 8, 127, 0); + + sprintf(String, "%s", modulationTypeOptions[settings.modulationType]); + GUI_DisplaySmallest(String, 116, 1, false, true); + sprintf(String, "%s", bwOptions[settings.listenBw]); + GUI_DisplaySmallest(String, 108, 7, false, true); +} + +static void DrawNums() { + + if (currentState == SPECTRUM) { + sprintf(String, "%ux", GetStepsCount()); + GUI_DisplaySmallest(String, 0, 1, false, true); + sprintf(String, "%u.%02uk", GetScanStep() / 100, GetScanStep() % 100); + GUI_DisplaySmallest(String, 0, 7, false, true); + } + + if (IsCenterMode()) { + sprintf(String, "%u.%05u \xB1%u.%02uk", currentFreq / 100000, + currentFreq % 100000, settings.frequencyChangeStep / 100, + settings.frequencyChangeStep % 100); + GUI_DisplaySmallest(String, 36, 49, false, true); + } else { + sprintf(String, "%u.%05u", GetFStart() / 100000, GetFStart() % 100000); + GUI_DisplaySmallest(String, 0, 49, false, true); + + sprintf(String, "\xB1%u.%02uk", settings.frequencyChangeStep / 100, + settings.frequencyChangeStep % 100); + GUI_DisplaySmallest(String, 48, 49, false, true); + + sprintf(String, "%u.%05u", GetFEnd() / 100000, GetFEnd() % 100000); + GUI_DisplaySmallest(String, 93, 49, false, true); + } +} + +static void DrawRssiTriggerLevel() { + if (settings.rssiTriggerLevel == RSSI_MAX_VALUE || monitorMode) + return; + uint8_t y = Rssi2Y(settings.rssiTriggerLevel); + for (uint8_t x = 0; x < 128; x += 2) { + PutPixel(x, y, true); + } +} + +static void DrawTicks() { + uint32_t f = GetFStart() % 100000; + uint32_t step = GetScanStep(); + for (uint8_t i = 0; i < 128; i += (1 << settings.stepsCount), f += step) { + uint8_t barValue = 0b00000001; + (f % 10000) < step && (barValue |= 0b00000010); + (f % 50000) < step && (barValue |= 0b00000100); + (f % 100000) < step && (barValue |= 0b00011000); + + gFrameBuffer[5][i] |= barValue; + } + + // center + if (IsCenterMode()) { + gFrameBuffer[5][62] = 0x80; + gFrameBuffer[5][63] = 0x80; + gFrameBuffer[5][64] = 0xff; + gFrameBuffer[5][65] = 0x80; + gFrameBuffer[5][66] = 0x80; + } else { + gFrameBuffer[5][0] = 0xff; + gFrameBuffer[5][1] = 0x80; + gFrameBuffer[5][2] = 0x80; + gFrameBuffer[5][3] = 0x80; + gFrameBuffer[5][124] = 0x80; + gFrameBuffer[5][125] = 0x80; + gFrameBuffer[5][126] = 0x80; + gFrameBuffer[5][127] = 0xff; + } +} + +static void DrawArrow(uint8_t x) { + for (signed i = -2; i <= 2; ++i) { + signed v = x + i; + if (!(v & 128)) { + gFrameBuffer[5][v] |= (0b01111000 << my_abs(i)) & 0b01111000; + } + } +} + +static void OnKeyDown(uint8_t key) { + switch (key) { + case KEY_3: + UpdateDBMax(true); + break; + case KEY_9: + UpdateDBMax(false); + break; + case KEY_1: + UpdateScanStep(true); + break; + case KEY_7: + UpdateScanStep(false); + break; + case KEY_2: + UpdateFreqChangeStep(true); + break; + case KEY_8: + UpdateFreqChangeStep(false); + break; + case KEY_UP: + UpdateCurrentFreq(true); + break; + case KEY_DOWN: + UpdateCurrentFreq(false); + break; + case KEY_SIDE1: + Blacklist(); + break; + case KEY_STAR: + UpdateRssiTriggerLevel(true); + break; + case KEY_F: + UpdateRssiTriggerLevel(false); + break; + case KEY_5: + FreqInput(); + break; + case KEY_0: + ToggleModulation(); + break; + case KEY_6: + ToggleListeningBW(); + break; + case KEY_4: + ToggleStepsCount(); + break; + case KEY_SIDE2: + ToggleBacklight(); + break; + case KEY_PTT: + SetState(STILL); + TuneToPeak(); + break; + case KEY_MENU: + break; + case KEY_EXIT: + if (menuState) { + menuState = 0; + break; + } + DeInitSpectrum(); + break; + default: + break; + } +} + +static void OnKeyDownFreqInput(uint8_t key) { + switch (key) { + case KEY_0: + case KEY_1: + case KEY_2: + case KEY_3: + case KEY_4: + case KEY_5: + case KEY_6: + case KEY_7: + case KEY_8: + case KEY_9: + case KEY_STAR: + UpdateFreqInput(key); + break; + case KEY_EXIT: + if (freqInputIndex == 0) { + SetState(previousState); + break; + } + UpdateFreqInput(key); + break; + case KEY_MENU: + if (tempFreq < F_MIN || tempFreq > F_MAX) { + break; + } + SetState(previousState); + currentFreq = tempFreq; + if (currentState == SPECTRUM) { + ResetBlacklist(); + RelaunchScan(); + } else { + SetF(currentFreq); + } + break; + default: + break; + } +} + +void OnKeyDownStill(KEY_Code_t key) { + switch (key) { + case KEY_3: + UpdateDBMax(true); + break; + case KEY_9: + UpdateDBMax(false); + break; + case KEY_UP: + if (menuState) { + SetRegMenuValue(menuState, true); + break; + } + UpdateCurrentFreqStill(true); + break; + case KEY_DOWN: + if (menuState) { + SetRegMenuValue(menuState, false); + break; + } + UpdateCurrentFreqStill(false); + break; + case KEY_STAR: + UpdateRssiTriggerLevel(true); + break; + case KEY_F: + UpdateRssiTriggerLevel(false); + break; + case KEY_5: + FreqInput(); + break; + case KEY_0: + ToggleModulation(); + break; + case KEY_6: + ToggleListeningBW(); + break; + case KEY_SIDE1: + monitorMode = !monitorMode; + break; + case KEY_SIDE2: + ToggleBacklight(); + break; + case KEY_PTT: + // TODO: start transmit + /* BK4819_ToggleGpioOut(BK4819_GPIO0_PIN28_GREEN, false); + BK4819_ToggleGpioOut(BK4819_GPIO1_PIN29_RED, true); */ + break; + case KEY_MENU: + if (menuState == ARRAY_SIZE(registerSpecs) - 1) { + menuState = 1; + } else { + menuState++; + } + redrawScreen = true; + break; + case KEY_EXIT: + if (!menuState) { + SetState(SPECTRUM); + monitorMode = false; + RelaunchScan(); + break; + } + menuState = 0; + break; + default: + break; + } +} + +static void RenderFreqInput() { + UI_PrintString(freqInputString, 2, 127, 0, 8); +} + +static void RenderStatus() { + memset(gStatusLine, 0, sizeof(gStatusLine)); + DrawStatus(); + ST7565_BlitStatusLine(); +} + +static void RenderSpectrum() { + DrawTicks(); + DrawArrow(peak.i << settings.stepsCount); + DrawSpectrum(); + DrawRssiTriggerLevel(); + DrawF(peak.f); + DrawNums(); +} + +static void RenderStill() { + DrawF(fMeasure); + + const uint8_t METER_PAD_LEFT = 3; + + for (int i = 0; i < 121; i++) { + if (i % 10 == 0) { + gFrameBuffer[2][i + METER_PAD_LEFT] = 0b01110000; + } else if (i % 5 == 0) { + gFrameBuffer[2][i + METER_PAD_LEFT] = 0b00110000; + } else { + gFrameBuffer[2][i + METER_PAD_LEFT] = 0b00010000; + } + } + + uint8_t x = Rssi2PX(scanInfo.rssi, 0, 121); + for (int i = 0; i < x; ++i) { + if (i % 5) { + gFrameBuffer[2][i + METER_PAD_LEFT] |= 0b00000111; + } + } + + int dbm = Rssi2DBm(scanInfo.rssi); + uint8_t s = DBm2S(dbm); + sprintf(String, "S: %u", s); + GUI_DisplaySmallest(String, 4, 25, false, true); + sprintf(String, "%d dBm", dbm); + GUI_DisplaySmallest(String, 28, 25, false, true); + + if (!monitorMode) { + uint8_t x = Rssi2PX(settings.rssiTriggerLevel, 0, 121); + gFrameBuffer[2][METER_PAD_LEFT + x] = 0b11111111; + } + + const uint8_t PAD_LEFT = 4; + const uint8_t CELL_WIDTH = 30; + uint8_t offset = PAD_LEFT; + uint8_t row = 4; + + for (int i = 0, idx = 1; idx <= 4; ++i, ++idx) { + if (idx == 5) { + row += 2; + i = 0; + } + offset = PAD_LEFT + i * CELL_WIDTH; + if (menuState == idx) { + for (int j = 0; j < CELL_WIDTH; ++j) { + gFrameBuffer[row][j + offset] = 0xFF; + gFrameBuffer[row + 1][j + offset] = 0xFF; + } + } + sprintf(String, "%s", registerSpecs[idx].name); + GUI_DisplaySmallest(String, offset + 2, row * 8 + 2, false, + menuState != idx); + sprintf(String, "%u", GetRegMenuValue(idx)); + GUI_DisplaySmallest(String, offset + 2, (row + 1) * 8 + 1, false, + menuState != idx); + } +} + +static void Render() { + memset(gFrameBuffer, 0, sizeof(gFrameBuffer)); + + switch (currentState) { + case SPECTRUM: + RenderSpectrum(); + break; + case FREQ_INPUT: + RenderFreqInput(); + break; + case STILL: + RenderStill(); + break; + } + + ST7565_BlitFullScreen(); +} + +bool HandleUserInput() { + kbd.prev = kbd.current; + kbd.current = GetKey(); + + if (kbd.current == KEY_INVALID) { + kbd.counter = 0; + return true; + } + + if (kbd.current == kbd.prev && kbd.counter <= 16) { + kbd.counter++; + SYSTEM_DelayMs(20); + } + + if (kbd.counter == 3 || kbd.counter > 16) { + switch (currentState) { + case SPECTRUM: + OnKeyDown(kbd.current); + break; + case FREQ_INPUT: + OnKeyDownFreqInput(kbd.current); + break; + case STILL: + OnKeyDownStill(kbd.current); + break; + } + } + + return true; +} + +static void Scan() { + if (rssiHistory[scanInfo.i] != RSSI_MAX_VALUE) { + SetF(scanInfo.f); + Measure(); + UpdateScanInfo(); + } +} + +static void NextScanStep() { + ++peak.t; + ++scanInfo.i; + scanInfo.f += scanInfo.scanStep; +} + +static void UpdateScan() { + Scan(); + + if (scanInfo.i < scanInfo.measurementsCount) { + NextScanStep(); + return; + } + + redrawScreen = true; + preventKeypress = false; + + UpdatePeakInfo(); + if (IsPeakOverLevel()) { + ToggleRX(true); + TuneToPeak(); + return; + } + + newScanStart = true; +} + +static void UpdateStill() { + Measure(); + redrawScreen = true; + preventKeypress = false; + + peak.rssi = scanInfo.rssi; + AutoTriggerLevel(); + + ToggleRX(IsPeakOverLevel() || monitorMode); +} + +static void UpdateListening() { + preventKeypress = false; + if (currentState == STILL) { + listenT = 0; + } + if (listenT) { + listenT--; + SYSTEM_DelayMs(1); + return; + } + + if (currentState == SPECTRUM) { + BK4819_WriteRegister(0x43, GetBWRegValueForScan()); + Measure(); + BK4819_WriteRegister(0x43, listenBWRegValues[settings.listenBw]); + } else { + Measure(); + } + + peak.rssi = scanInfo.rssi; + redrawScreen = true; + + if (IsPeakOverLevel() || monitorMode) { + listenT = 1000; + return; + } + + ToggleRX(false); + newScanStart = true; +} + +static void Tick() { + if (!preventKeypress) { + HandleUserInput(); + } + if (newScanStart) { + InitScan(); + newScanStart = false; + } + if (isListening && currentState != FREQ_INPUT) { + UpdateListening(); + } else { + if (currentState == SPECTRUM) { + UpdateScan(); + } else if (currentState == STILL) { + UpdateStill(); + } + } + if (redrawStatus || ++statuslineUpdateTimer > 4096) { + RenderStatus(); + redrawStatus = false; + statuslineUpdateTimer = 0; + } + if (redrawScreen) { + Render(); + redrawScreen = false; + } +} + +void APP_RunSpectrum() { + // TX here coz it always? set to active VFO + currentFreq = initialFreq = + gEeprom.VfoInfo[gEeprom.TX_VFO].pRX->Frequency; + + BackupRegisters(); + + isListening = true; // to turn off RX later + redrawStatus = true; + redrawScreen = false; // we will wait until scan done + newScanStart = true; + + ToggleRX(true), ToggleRX(false); // hack to prevent noise when squelch off + SetModulation(settings.modulationType = MOD_FM); + BK4819_SetFilterBandwidth(settings.listenBw = BK4819_FILTER_BW_WIDE, false); + + RelaunchScan(); + + for (int i = 0; i < 128; ++i) { + rssiHistory[i] = 0; + } + + isInitialized = true; + + while (isInitialized) { + Tick(); + } +} diff --git a/app/spectrum.h b/app/spectrum.h new file mode 100644 index 0000000..61ac358 --- /dev/null +++ b/app/spectrum.h @@ -0,0 +1,171 @@ +/* Copyright 2023 fagci + * https://github.com/fagci + * + * 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 SPECTRUM_H +#define SPECTRUM_H + +#include "../bitmaps.h" +#include "../board.h" +#include "../bsp/dp32g030/gpio.h" +#include "../driver/bk4819-regs.h" +#include "../driver/bk4819.h" +#include "../driver/gpio.h" +#include "../driver/keyboard.h" +#include "../driver/st7565.h" +#include "../driver/system.h" +#include "../driver/systick.h" +#include "../external/printf/printf.h" +#include "../font.h" +#include "../frequencies.h" +#include "../helper/battery.h" +#include "../misc.h" +#include "../radio.h" +#include "../settings.h" +#include "../ui/helper.h" +#include +#include +#include + +static const uint8_t DrawingEndY = 40; + +static const uint8_t U8RssiMap[] = { + 121, 115, 109, 103, 97, 91, 85, 79, 73, 63, +}; + +static const uint16_t scanStepValues[] = { + 1, 10, 50, 100, + + 250, 500, 625, 833, 1000, 1250, 2500, 10000, +}; + +static const uint16_t scanStepBWRegValues[] = { + // RX RXw TX BW + // 0b0 000 000 001 01 1000 + // 1 + 0b0000000001011000, // 6.25 + // 10 + 0b0000000001011000, // 6.25 + // 50 + 0b0000000001011000, // 6.25 + // 100 + 0b0000000001011000, // 6.25 + // 250 + 0b0000000001011000, // 6.25 + // 500 + 0b0010010001011000, // 6.25 + // 625 + 0b0100100001011000, // 6.25 + // 833 + 0b0110110001001000, // 6.25 + // 1000 + 0b0110110001001000, // 6.25 + // 1250 + 0b0111111100001000, // 6.25 + // 2500 + 0b0011011000101000, // 25 + // 10000 + 0b0011011000101000, // 25 +}; + +static const uint16_t listenBWRegValues[] = { + 0b0011011000101000, // 25 + 0b0111111100001000, // 12.5 + 0b0100100001011000, // 6.25 +}; + +typedef enum State { + SPECTRUM, + FREQ_INPUT, + STILL, +} State; + +typedef enum StepsCount { + STEPS_128, + STEPS_64, + STEPS_32, + STEPS_16, +} StepsCount; + +typedef enum ModulationType { + MOD_FM, + MOD_AM, + MOD_USB, +} ModulationType; + +typedef enum ScanStep { + S_STEP_0_01kHz, + S_STEP_0_1kHz, + S_STEP_0_5kHz, + S_STEP_1_0kHz, + + S_STEP_2_5kHz, + S_STEP_5_0kHz, + S_STEP_6_25kHz, + S_STEP_8_33kHz, + S_STEP_10_0kHz, + S_STEP_12_5kHz, + S_STEP_25_0kHz, + S_STEP_100_0kHz, +} ScanStep; + +typedef struct SpectrumSettings { + uint32_t frequencyChangeStep; + StepsCount stepsCount; + ScanStep scanStepIndex; + uint16_t scanDelay; + uint16_t rssiTriggerLevel; + BK4819_FilterBandwidth_t bw; + BK4819_FilterBandwidth_t listenBw; + int dbMin; + int dbMax; + ModulationType modulationType; + bool backlightState; +} SpectrumSettings; + +typedef struct KeyboardState { + KEY_Code_t current; + KEY_Code_t prev; + uint8_t counter; +} KeyboardState; + +typedef struct ScanInfo { + uint16_t rssi, rssiMin, rssiMax; + uint8_t i, iPeak; + uint32_t f, fPeak; + uint16_t scanStep; + uint8_t measurementsCount; +} ScanInfo; + +typedef struct RegisterSpec { + char *name; + uint8_t num; + uint8_t offset; + uint16_t maxValue; + uint16_t inc; +} RegisterSpec; + +typedef struct PeakInfo { + uint16_t t; + uint16_t rssi; + uint32_t f; + uint8_t i; +} PeakInfo; + +void APP_RunSpectrum(void); + +#endif /* ifndef SPECTRUM_H */ + +// vim: ft=c diff --git a/compile-with-docker.bat b/compile-with-docker.bat new file mode 100644 index 0000000..42adad1 --- /dev/null +++ b/compile-with-docker.bat @@ -0,0 +1,4 @@ +@echo off +docker build -t uvk5 . +docker run -v %CD%\compiled-firmware:/app/compiled-firmware uvk5 /bin/bash -c "cd /app && make clean && make && cp firmware* compiled-firmware/" +pause \ No newline at end of file diff --git a/compile-with-docker.sh b/compile-with-docker.sh new file mode 100644 index 0000000..fb5dd01 --- /dev/null +++ b/compile-with-docker.sh @@ -0,0 +1,3 @@ +#!/bin/sh +docker build -t uvk5 . +docker run -v $(PWD)/compiled-firmware:/app/compiled-firmware uvk5 /bin/bash -c "cd /app && make && cp firmware* compiled-firmware/" \ No newline at end of file diff --git a/driver/bk4819.c b/driver/bk4819.c index d485c96..0d921d7 100644 --- a/driver/bk4819.c +++ b/driver/bk4819.c @@ -1004,6 +1004,42 @@ void BK4819_PlayTone(uint16_t Frequency, bool bTuningGainSwitch) BK4819_WriteRegister(BK4819_REG_71, scale_freq(Frequency)); } +void BK4819_PlaySingleTone(const unsigned int tone_Hz, const unsigned int delay, const unsigned int level, const bool play_speaker) +{ + BK4819_EnterTxMute(); + + if (play_speaker) + { + GPIO_SetBit(&GPIOC->DATA, GPIOC_PIN_AUDIO_PATH); + BK4819_SetAF(BK4819_AF_BEEP); + } + else + BK4819_SetAF(BK4819_AF_MUTE); + + // level 0 ~ 127 +// BK4819_WriteRegister(BK4819_REG_70, BK4819_REG_70_ENABLE_TONE1 | (96u << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN)); +// BK4819_WriteRegister(BK4819_REG_70, BK4819_REG_70_ENABLE_TONE1 | (28u << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN)); + BK4819_WriteRegister(BK4819_REG_70, BK4819_REG_70_ENABLE_TONE1 | ((level & 0x7f) << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN)); + + BK4819_EnableTXLink(); + SYSTEM_DelayMs(50); + + BK4819_WriteRegister(BK4819_REG_71, scale_freq(tone_Hz)); + + BK4819_ExitTxMute(); + SYSTEM_DelayMs(delay); + BK4819_EnterTxMute(); + + if (play_speaker) + { + GPIO_ClearBit(&GPIOC->DATA, GPIOC_PIN_AUDIO_PATH); + BK4819_SetAF(BK4819_AF_MUTE); + } + + BK4819_WriteRegister(BK4819_REG_70, 0x0000); + BK4819_WriteRegister(BK4819_REG_30, 0xC1FE); +} + void BK4819_EnterTxMute(void) { BK4819_WriteRegister(BK4819_REG_50, 0xBB20); @@ -1287,7 +1323,7 @@ void BK4819_TransmitTone(bool bLocalLoopback, uint32_t Frequency) // set the tone amplitude // // BK4819_WriteRegister(BK4819_REG_70, BK4819_REG_70_MASK_ENABLE_TONE1 | (96u << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN)); - BK4819_WriteRegister(BK4819_REG_70, BK4819_REG_70_MASK_ENABLE_TONE1 | (50u << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN)); + BK4819_WriteRegister(BK4819_REG_70, BK4819_REG_70_MASK_ENABLE_TONE1 | (28u << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN)); BK4819_WriteRegister(BK4819_REG_71, scale_freq(Frequency)); @@ -1631,7 +1667,9 @@ void BK4819_PlayRoger(void) BK4819_EnterTxMute(); BK4819_SetAF(BK4819_AF_MUTE); - BK4819_WriteRegister(BK4819_REG_70, 0xE000); // 1110 0000 0000 0000 + +// BK4819_WriteRegister(BK4819_REG_70, BK4819_REG_70_ENABLE_TONE1 | (96u << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN)); + BK4819_WriteRegister(BK4819_REG_70, BK4819_REG_70_ENABLE_TONE1 | (28u << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN)); BK4819_EnableTXLink(); SYSTEM_DelayMs(50); diff --git a/driver/bk4819.h b/driver/bk4819.h index 352bbf5..736b171 100644 --- a/driver/bk4819.h +++ b/driver/bk4819.h @@ -102,6 +102,7 @@ void BK4819_DisableVox(void); void BK4819_DisableDTMF(void); void BK4819_EnableDTMF(void); void BK4819_PlayTone(uint16_t Frequency, bool bTuningGainSwitch); +void BK4819_PlaySingleTone(const unsigned int tone_Hz, const unsigned int delay, const unsigned int level, const bool play_speaker); void BK4819_EnterTxMute(void); void BK4819_ExitTxMute(void); void BK4819_Sleep(void); diff --git a/firmware.bin b/firmware.bin index 9858669..01983d5 100644 Binary files a/firmware.bin and b/firmware.bin differ diff --git a/firmware.packed.bin b/firmware.packed.bin index 3b838c8..be0723a 100644 Binary files a/firmware.packed.bin and b/firmware.packed.bin differ diff --git a/font.c b/font.c index 1aba955..3d0e3b2 100644 --- a/font.c +++ b/font.c @@ -19,6 +19,7 @@ //const uint8_t gFontBig[95][16] = const uint8_t gFontBig[95][15] = { +#if 0 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // , 0x00}, // ' ' {0x00, 0x00, 0x70, 0xF8, 0xF8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x1B, 0x00, 0x00}, // , 0x00}, // '!' {0x00, 0x1E, 0x3E, 0x00, 0x00, 0x3E, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // , 0x00}, // '"' @@ -114,7 +115,104 @@ const uint8_t gFontBig[95][15] = {0x00, 0x00, 0x00, 0x78, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x1F, 0x00, 0x00}, // , 0x00}, // '|' {0x00, 0x08, 0x08, 0x78, 0xF0, 0x80, 0x80, 0x00, 0x00, 0x10, 0x10, 0x1F, 0x0F, 0x00, 0x00}, // , 0x00}, // '}' {0x10, 0x18, 0x08, 0x18, 0x10, 0x18, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // , 0x00} // '->' -}; +#else + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x0D, 0x00, 0x00}, + {0x00, 0x0F, 0x1F, 0x00, 0x00, 0x1F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x20, 0xF8, 0xF8, 0x20, 0xF8, 0xF8, 0x20, 0x00, 0x02, 0x0F, 0x0F, 0x02, 0x0F, 0x0F, 0x02}, + {0x70, 0xF8, 0x88, 0x8E, 0x8E, 0x98, 0x10, 0x00, 0x04, 0x0C, 0x08, 0x38, 0x38, 0x0F, 0x07}, + {0x30, 0x30, 0x00, 0x80, 0xC0, 0x60, 0x30, 0x00, 0x0C, 0x06, 0x03, 0x01, 0x00, 0x0C, 0x0C}, + {0x80, 0xD8, 0x7C, 0xE4, 0xBC, 0xD8, 0x40, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x07, 0x0F, 0x08}, + {0x00, 0x10, 0x1F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xF0, 0xF8, 0x0C, 0x04, 0x00, 0x00, 0x00, 0x00, 0x03, 0x07, 0x0C, 0x08, 0x00}, + {0x00, 0x00, 0x04, 0x0C, 0xF8, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0C, 0x07, 0x03, 0x00}, + {0x00, 0x80, 0xA0, 0xE0, 0xC0, 0xE0, 0xA0, 0x80, 0x00, 0x00, 0x02, 0x03, 0x01, 0x03, 0x02}, + {0x00, 0x80, 0x80, 0xE0, 0xE0, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x1E, 0x0E, 0x00, 0x00}, + {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x80, 0xC0, 0x60, 0x30, 0x00, 0x0C, 0x06, 0x03, 0x01, 0x00, 0x00, 0x00}, + {0xF8, 0xFC, 0x84, 0xC4, 0x64, 0xFC, 0xF8, 0x00, 0x07, 0x0F, 0x09, 0x08, 0x08, 0x0F, 0x07}, + {0x00, 0x10, 0x18, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x0F, 0x0F, 0x08, 0x08}, + {0x18, 0x1C, 0x04, 0x84, 0xC4, 0x7C, 0x38, 0x00, 0x0C, 0x0E, 0x0B, 0x09, 0x08, 0x08, 0x08}, + {0x18, 0x1C, 0x44, 0x44, 0x44, 0xFC, 0xB8, 0x00, 0x06, 0x0E, 0x08, 0x08, 0x08, 0x0F, 0x07}, + {0x80, 0xC0, 0x60, 0x30, 0x18, 0xFC, 0xFC, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x0F, 0x0F}, + {0x7C, 0x7C, 0x44, 0x44, 0x44, 0xC4, 0x84, 0x00, 0x04, 0x0C, 0x08, 0x08, 0x08, 0x0F, 0x07}, + {0xF0, 0xF8, 0x4C, 0x44, 0x44, 0xC4, 0x80, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x07}, + {0x04, 0x04, 0x04, 0x84, 0xE4, 0x7C, 0x1C, 0x00, 0x00, 0x00, 0x0E, 0x0F, 0x01, 0x00, 0x00}, + {0xB8, 0xFC, 0x44, 0x44, 0x44, 0xFC, 0xB8, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x07}, + {0x78, 0xFC, 0x84, 0x84, 0x84, 0xFC, 0xF8, 0x00, 0x00, 0x08, 0x08, 0x08, 0x0C, 0x07, 0x03}, + {0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0E, 0x06, 0x00, 0x00}, + {0x00, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x08, 0x00, 0x00, 0x00, 0x01, 0x03, 0x06, 0x0C, 0x08}, + {0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}, + {0x00, 0x08, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x08, 0x0C, 0x06, 0x03, 0x01, 0x00}, + {0x38, 0x3C, 0x04, 0x84, 0xC4, 0x7C, 0x38, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x0D, 0x00, 0x00}, + {0xF0, 0xF8, 0x08, 0xC8, 0xC8, 0xF8, 0xF0, 0x00, 0x07, 0x0F, 0x08, 0x0B, 0x0B, 0x0B, 0x01}, + {0xF8, 0xFC, 0x84, 0x84, 0x84, 0xFC, 0xF8, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x0F}, + {0xFC, 0xFC, 0x44, 0x44, 0x44, 0xFC, 0xB8, 0x00, 0x0F, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x07}, + {0xF8, 0xFC, 0x04, 0x04, 0x04, 0x1C, 0x18, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x0E, 0x06}, + {0xFC, 0xFC, 0x04, 0x04, 0x0C, 0xF8, 0xF0, 0x00, 0x0F, 0x0F, 0x08, 0x08, 0x0C, 0x07, 0x03}, + {0xFC, 0xFC, 0x44, 0x44, 0x44, 0x04, 0x04, 0x00, 0x0F, 0x0F, 0x08, 0x08, 0x08, 0x08, 0x08}, + {0xFC, 0xFC, 0x44, 0x44, 0x44, 0x04, 0x04, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xF8, 0xFC, 0x04, 0x84, 0x84, 0x9C, 0x98, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x07}, + {0xFC, 0xFC, 0x40, 0x40, 0x40, 0xFC, 0xFC, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x0F}, + {0x00, 0x00, 0x04, 0xFC, 0xFC, 0x04, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0F, 0x0F, 0x08, 0x00}, + {0x00, 0x00, 0x00, 0x04, 0xFC, 0xFC, 0x04, 0x00, 0x06, 0x0E, 0x08, 0x08, 0x0F, 0x07, 0x00}, + {0xFC, 0xFC, 0xE0, 0x30, 0x18, 0x0C, 0x04, 0x00, 0x0F, 0x0F, 0x01, 0x03, 0x06, 0x0C, 0x08}, + {0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x08, 0x08, 0x08, 0x08, 0x08}, + {0xFC, 0xFC, 0x18, 0x70, 0x18, 0xFC, 0xFC, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x0F}, + {0xFC, 0xFC, 0x60, 0xC0, 0x80, 0xFC, 0xFC, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x01, 0x0F, 0x0F}, + {0xF8, 0xFC, 0x04, 0x04, 0x04, 0xFC, 0xF8, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x07}, + {0xFC, 0xFC, 0x84, 0x84, 0x84, 0xFC, 0x78, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xF8, 0xFC, 0x04, 0x04, 0x04, 0xFC, 0xF8, 0x00, 0x07, 0x0F, 0x08, 0x0C, 0x0C, 0x1F, 0x17}, + {0xFC, 0xFC, 0x84, 0x84, 0x84, 0xFC, 0x78, 0x00, 0x0F, 0x0F, 0x01, 0x03, 0x06, 0x0C, 0x08}, + {0x38, 0x7C, 0x44, 0x44, 0x44, 0xCC, 0x88, 0x00, 0x06, 0x0E, 0x08, 0x08, 0x08, 0x0F, 0x07}, + {0x00, 0x04, 0x04, 0xFC, 0xFC, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00}, + {0xFC, 0xFC, 0x00, 0x00, 0x00, 0xFC, 0xFC, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x07}, + {0x7C, 0xFC, 0x80, 0x00, 0x80, 0xFC, 0x7C, 0x00, 0x00, 0x03, 0x0F, 0x0C, 0x0F, 0x03, 0x00}, + {0xFC, 0xFC, 0x00, 0x80, 0x00, 0xFC, 0xFC, 0x00, 0x0F, 0x0F, 0x06, 0x03, 0x06, 0x0F, 0x0F}, + {0x0C, 0x3C, 0xF0, 0xC0, 0xF0, 0x3C, 0x0C, 0x00, 0x0C, 0x0F, 0x03, 0x00, 0x03, 0x0F, 0x0C}, + {0x00, 0x3C, 0x7C, 0xC0, 0xC0, 0x7C, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00}, + {0x04, 0x04, 0x84, 0xC4, 0x64, 0x3C, 0x1C, 0x00, 0x0E, 0x0F, 0x09, 0x08, 0x08, 0x08, 0x08}, + {0x00, 0x00, 0xFC, 0xFC, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x08, 0x08, 0x00}, + {0x38, 0x70, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x0E}, + {0x00, 0x00, 0x04, 0x04, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x0F, 0x0F, 0x00}, + {0x08, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20}, + {0x00, 0x00, 0x03, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0xA0, 0xA0, 0xA0, 0xA0, 0xE0, 0xC0, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x0F}, + {0xFC, 0xFC, 0x20, 0x20, 0x20, 0xE0, 0xC0, 0x00, 0x0F, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x07}, + {0xC0, 0xE0, 0x20, 0x20, 0x20, 0x60, 0x40, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x0C, 0x04}, + {0xC0, 0xE0, 0x20, 0x20, 0x20, 0xFC, 0xFC, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x0F}, + {0xC0, 0xE0, 0x20, 0x20, 0x20, 0xE0, 0xC0, 0x00, 0x07, 0x0F, 0x09, 0x09, 0x09, 0x09, 0x01}, + {0x20, 0x20, 0xF8, 0xFC, 0x24, 0x24, 0x04, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00}, + {0xC0, 0xE0, 0x20, 0x20, 0x20, 0xE0, 0xE0, 0x00, 0x07, 0x4F, 0x48, 0x48, 0x48, 0x7F, 0x3F}, + {0xFC, 0xFC, 0x20, 0x20, 0x20, 0xE0, 0xC0, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x0F}, + {0x00, 0x00, 0x20, 0xEC, 0xEC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0F, 0x0F, 0x08, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x20, 0xEC, 0xEC, 0x00, 0x00, 0x30, 0x70, 0x40, 0x40, 0x7F, 0x3F}, + {0xFC, 0xFC, 0x00, 0x80, 0xC0, 0x60, 0x20, 0x00, 0x0F, 0x0F, 0x01, 0x03, 0x06, 0x0C, 0x08}, + {0x00, 0x00, 0x04, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0F, 0x0F, 0x08, 0x00}, + {0xE0, 0xE0, 0x20, 0xE0, 0x20, 0xE0, 0xC0, 0x00, 0x0F, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x0F}, + {0xE0, 0xE0, 0x20, 0x20, 0x20, 0xE0, 0xC0, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x0F}, + {0xC0, 0xE0, 0x20, 0x20, 0x20, 0xE0, 0xC0, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x07}, + {0xE0, 0xE0, 0x20, 0x20, 0x20, 0xE0, 0xC0, 0x00, 0x7F, 0x7F, 0x08, 0x08, 0x08, 0x0F, 0x07}, + {0xC0, 0xE0, 0x20, 0x20, 0x20, 0xE0, 0xE0, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x7F, 0x7F}, + {0xE0, 0xE0, 0x60, 0x20, 0x20, 0x20, 0x20, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xC0, 0xE0, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x08, 0x09, 0x09, 0x09, 0x09, 0x0F, 0x06}, + {0x20, 0x20, 0xFC, 0xFC, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08}, + {0xE0, 0xE0, 0x00, 0x00, 0x00, 0xE0, 0xE0, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x0F}, + {0xE0, 0xE0, 0x00, 0x00, 0x00, 0xE0, 0xE0, 0x00, 0x00, 0x03, 0x0F, 0x0C, 0x0F, 0x03, 0x00}, + {0xE0, 0xE0, 0x00, 0x80, 0x00, 0xE0, 0xE0, 0x00, 0x07, 0x0F, 0x08, 0x0F, 0x08, 0x0F, 0x07}, + {0x60, 0xE0, 0x80, 0x00, 0x80, 0xE0, 0x60, 0x00, 0x0C, 0x0E, 0x03, 0x01, 0x03, 0x0E, 0x0C}, + {0xE0, 0xE0, 0x00, 0x00, 0x00, 0xE0, 0xE0, 0x00, 0x07, 0x4F, 0x48, 0x48, 0x48, 0x7F, 0x3F}, + {0x20, 0x20, 0x20, 0xA0, 0xE0, 0x60, 0x20, 0x00, 0x0C, 0x0E, 0x0B, 0x09, 0x08, 0x08, 0x08}, + {0x00, 0x00, 0x40, 0xF8, 0xBC, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0F, 0x08, 0x08}, + {0x00, 0x00, 0x00, 0xBC, 0xBC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00}, + {0x00, 0x04, 0x04, 0xBC, 0xF8, 0x40, 0x00, 0x00, 0x00, 0x08, 0x08, 0x0F, 0x07, 0x00, 0x00}, + {0x08, 0x0C, 0x04, 0x0C, 0x08, 0x0C, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} +#endif +}; #if 0 // original font @@ -132,7 +230,7 @@ const uint8_t gFontBig[95][15] = {0x00, 0xF0, 0xF8, 0xB8, 0x1C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1C, 0xB8, 0xF0, 0xE0, 0x00, 0x11, 0x33, 0x77, 0x67, 0x66, 0x66, 0x66, 0x76, 0x33, 0x3F, 0x1F, 0x07}, {0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00} }; -#else +#elif 0 // VCR font const uint8_t gFontBigDigits[11][26] = { @@ -148,6 +246,22 @@ const uint8_t gFontBig[95][15] = {0x00, 0x00, 0x78, 0xFC, 0xC6, 0x86, 0x86, 0x86, 0x86, 0x86, 0xFC, 0xF8, 0x00, 0x00, 0x00, 0x18, 0x38, 0x71, 0x61, 0x61, 0x61, 0x61, 0x71, 0x3F, 0x1F, 0x00}, {0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00} }; +#else + // Terminus font + const uint8_t gFontBigDigits[11][26] = + { + {0x00, 0x00, 0xFC, 0xFE, 0xFE, 0x06, 0x86, 0xC6, 0xE6, 0xFE, 0xFE, 0xFC, 0x00, 0x00, 0x00, 0x3F, 0x7F, 0x7F, 0x67, 0x63, 0x61, 0x60, 0x7F, 0x7F, 0x3F, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x18, 0x1C, 0xFE, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60, 0x7F, 0x7F, 0x7F, 0x60, 0x60, 0x00, 0x00}, + {0x00, 0x00, 0x1C, 0x1E, 0x1E, 0x06, 0x06, 0x06, 0x86, 0xFE, 0xFE, 0x7C, 0x00, 0x00, 0x00, 0x60, 0x70, 0x78, 0x7C, 0x6E, 0x67, 0x63, 0x61, 0x60, 0x60, 0x00}, + {0x00, 0x00, 0x0C, 0x0E, 0x0E, 0x86, 0x86, 0x86, 0x86, 0xFE, 0xFE, 0x7C, 0x00, 0x00, 0x00, 0x30, 0x70, 0x70, 0x61, 0x61, 0x61, 0x61, 0x7F, 0x7F, 0x3E, 0x00}, + {0x00, 0x00, 0x80, 0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0xFE, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0C, 0x0C, 0x0C, 0x0C, 0x7F, 0x7F, 0x7F, 0x00}, + {0x00, 0x00, 0xFE, 0xFE, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x86, 0x00, 0x00, 0x00, 0x30, 0x70, 0x70, 0x60, 0x60, 0x60, 0x60, 0x7F, 0x7F, 0x3F, 0x00}, + {0x00, 0x00, 0xF8, 0xFC, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x80, 0x00, 0x00, 0x00, 0x3F, 0x7F, 0x7F, 0x60, 0x60, 0x60, 0x60, 0x7F, 0x7F, 0x3F, 0x00}, + {0x00, 0x00, 0x0E, 0x0E, 0x0E, 0x06, 0x06, 0x86, 0xE6, 0xFE, 0x7E, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x7F, 0x7F, 0x03, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x7C, 0xFE, 0xFE, 0x86, 0x86, 0x86, 0x86, 0xFE, 0xFE, 0x7C, 0x00, 0x00, 0x00, 0x3F, 0x7F, 0x7F, 0x61, 0x61, 0x61, 0x61, 0x7F, 0x7F, 0x3F, 0x00}, + {0x00, 0x00, 0xFC, 0xFE, 0xFE, 0x06, 0x06, 0x06, 0x06, 0xFE, 0xFE, 0xFC, 0x00, 0x00, 0x00, 0x01, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x7F, 0x3F, 0x1F, 0x00}, + {0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00} + }; #endif /* const uint8_t gFontSmallDigits[11][7] = @@ -363,4 +477,170 @@ const uint8_t gFontSmall[95][6] = {0x00, 0x41, 0x77, 0x3E, 0x08, 0x00}, {0x0C, 0x06, 0x0C, 0x18, 0x0C, 0x00} }; -#endif \ No newline at end of file +#endif + +#ifdef ENABLE_SPECTRUM + const uint8_t gFont3x5[160][3] = + { + {0x00, 0x00, 0x00}, // 32 - space + {0x00, 0x17, 0x00}, // 33 - exclam + {0x03, 0x00, 0x03}, // 34 - quotedbl + {0x1f, 0x0a, 0x1f}, // 35 - numbersign + {0x0a, 0x1f, 0x05}, // 36 - dollar + {0x09, 0x04, 0x12}, // 37 - percent + {0x0f, 0x17, 0x1c}, // 38 - ampersand + {0x00, 0x03, 0x00}, // 39 - quotesingle + {0x00, 0x0e, 0x11}, // 40 - parenleft + {0x11, 0x0e, 0x00}, // 41 - parenright + {0x05, 0x02, 0x05}, // 42 - asterisk + {0x04, 0x0e, 0x04}, // 43 - plus + {0x10, 0x08, 0x00}, // 44 - comma + {0x04, 0x04, 0x04}, // 45 - hyphen + {0x00, 0x10, 0x00}, // 46 - period + {0x18, 0x04, 0x03}, // 47 - slash + {0x1e, 0x11, 0x0f}, // 48 - zero + {0x02, 0x1f, 0x00}, // 49 - one + {0x19, 0x15, 0x12}, // 50 - two + {0x11, 0x15, 0x0a}, // 51 - three + {0x07, 0x04, 0x1f}, // 52 - four + {0x17, 0x15, 0x09}, // 53 - five + {0x1e, 0x15, 0x1d}, // 54 - six + {0x19, 0x05, 0x03}, // 55 - seven + {0x1f, 0x15, 0x1f}, // 56 - eight + {0x17, 0x15, 0x0f}, // 57 - nine + {0x00, 0x0a, 0x00}, // 58 - colon + {0x10, 0x0a, 0x00}, // 59 - semicolon + {0x04, 0x0a, 0x11}, // 60 - less + {0x0a, 0x0a, 0x0a}, // 61 - equal + {0x11, 0x0a, 0x04}, // 62 - greater + {0x01, 0x15, 0x03}, // 63 - question + {0x0e, 0x15, 0x16}, // 64 - at + {0x1e, 0x05, 0x1e}, // 65 - A + {0x1f, 0x15, 0x0a}, // 66 - B + {0x0e, 0x11, 0x11}, // 67 - C + {0x1f, 0x11, 0x0e}, // 68 - D + {0x1f, 0x15, 0x15}, // 69 - E + {0x1f, 0x05, 0x05}, // 70 - F + {0x0e, 0x15, 0x1d}, // 71 - G + {0x1f, 0x04, 0x1f}, // 72 - H + {0x11, 0x1f, 0x11}, // 73 - I + {0x08, 0x10, 0x0f}, // 74 - J + {0x1f, 0x04, 0x1b}, // 75 - K + {0x1f, 0x10, 0x10}, // 76 - L + {0x1f, 0x06, 0x1f}, // 77 - M + {0x1f, 0x0e, 0x1f}, // 78 - N + {0x0e, 0x11, 0x0e}, // 79 - O + {0x1f, 0x05, 0x02}, // 80 - P + {0x0e, 0x19, 0x1e}, // 81 - Q + {0x1f, 0x0d, 0x16}, // 82 - R + {0x12, 0x15, 0x09}, // 83 - S + {0x01, 0x1f, 0x01}, // 84 - T + {0x0f, 0x10, 0x1f}, // 85 - U + {0x07, 0x18, 0x07}, // 86 - V + {0x1f, 0x0c, 0x1f}, // 87 - W + {0x1b, 0x04, 0x1b}, // 88 - X + {0x03, 0x1c, 0x03}, // 89 - Y + {0x19, 0x15, 0x13}, // 90 - Z + {0x1f, 0x11, 0x11}, // 91 - bracketleft + {0x02, 0x04, 0x08}, // 92 - backslash + {0x11, 0x11, 0x1f}, // 93 - bracketright + {0x02, 0x01, 0x02}, // 94 - asciicircum + {0x10, 0x10, 0x10}, // 95 - underscore + {0x01, 0x02, 0x00}, // 96 - grave + {0x1a, 0x16, 0x1c}, // 97 - a + {0x1f, 0x12, 0x0c}, // 98 - b + {0x0c, 0x12, 0x12}, // 99 - c + {0x0c, 0x12, 0x1f}, // 100 - d + {0x0c, 0x1a, 0x16}, // 101 - e + {0x04, 0x1e, 0x05}, // 102 - f + {0x0c, 0x2a, 0x1e}, // 103 - g + {0x1f, 0x02, 0x1c}, // 104 - h + {0x00, 0x1d, 0x00}, // 105 - i + {0x10, 0x20, 0x1d}, // 106 - j + {0x1f, 0x0c, 0x12}, // 107 - k + {0x11, 0x1f, 0x10}, // 108 - l + {0x1e, 0x0e, 0x1e}, // 109 - m + {0x1e, 0x02, 0x1c}, // 110 - n + {0x0c, 0x12, 0x0c}, // 111 - o + {0x3e, 0x12, 0x0c}, // 112 - p + {0x0c, 0x12, 0x3e}, // 113 - q + {0x1c, 0x02, 0x02}, // 114 - r + {0x14, 0x1e, 0x0a}, // 115 - s + {0x02, 0x1f, 0x12}, // 116 - t + {0x0e, 0x10, 0x1e}, // 117 - u + {0x0e, 0x18, 0x0e}, // 118 - v + {0x1e, 0x1c, 0x1e}, // 119 - w + {0x12, 0x0c, 0x12}, // 120 - x + {0x06, 0x28, 0x1e}, // 121 - y + {0x1a, 0x1e, 0x16}, // 122 - z + {0x04, 0x1b, 0x11}, // 123 - braceleft + {0x00, 0x1b, 0x00}, // 124 - bar + {0x11, 0x1b, 0x04}, // 125 - braceright + {0x02, 0x03, 0x01}, // 126 - asciitilde + {0x00, 0x00, 0x00}, // 127 - empty + {0x00, 0x00, 0x00}, // 128 - empty + {0x00, 0x00, 0x00}, // 129 - empty + {0x00, 0x00, 0x00}, // 130 - empty + {0x00, 0x00, 0x00}, // 131 - empty + {0x00, 0x00, 0x00}, // 132 - empty + {0x00, 0x00, 0x00}, // 133 - empty + {0x00, 0x00, 0x00}, // 134 - empty + {0x00, 0x00, 0x00}, // 135 - empty + {0x00, 0x00, 0x00}, // 136 - empty + {0x00, 0x00, 0x00}, // 137 - empty + {0x00, 0x00, 0x00}, // 138 - empty + {0x00, 0x00, 0x00}, // 139 - empty + {0x00, 0x00, 0x00}, // 140 - empty + {0x00, 0x00, 0x00}, // 141 - empty + {0x00, 0x00, 0x00}, // 142 - empty + {0x00, 0x00, 0x00}, // 143 - empty + {0x00, 0x00, 0x00}, // 144 - empty + {0x00, 0x00, 0x00}, // 145 - empty + {0x00, 0x00, 0x00}, // 146 - empty + {0x00, 0x00, 0x00}, // 147 - empty + {0x00, 0x00, 0x00}, // 148 - empty + {0x00, 0x00, 0x00}, // 149 - empty + {0x00, 0x00, 0x00}, // 150 - empty + {0x00, 0x00, 0x00}, // 151 - empty + {0x00, 0x00, 0x00}, // 152 - empty + {0x00, 0x00, 0x00}, // 153 - empty + {0x00, 0x00, 0x00}, // 154 - empty + {0x00, 0x00, 0x00}, // 155 - empty + {0x00, 0x00, 0x00}, // 156 - empty + {0x00, 0x00, 0x00}, // 157 - empty + {0x00, 0x00, 0x00}, // 158 - empty + {0x00, 0x00, 0x00}, // 159 - empty + {0x00, 0x00, 0x00}, // 160 - empty + {0x00, 0x1d, 0x00}, // 161 - exclamdown + {0x0e, 0x1b, 0x0a}, // 162 - cent + {0x14, 0x1f, 0x15}, // 163 - sterling + {0x15, 0x0e, 0x15}, // 164 - currency + {0x0b, 0x1c, 0x0b}, // 165 - yen + {0x00, 0x1b, 0x00}, // 166 - brokenbar + {0x14, 0x1b, 0x05}, // 167 - section + {0x01, 0x00, 0x01}, // 168 - dieresis + {0x02, 0x05, 0x05}, // 169 - copyright + {0x16, 0x15, 0x17}, // 170 - ordfeminine + {0x02, 0x05, 0x00}, // 171 - guillemotleft + {0x02, 0x02, 0x06}, // 172 - logicalnot + {0x04, 0x04, 0x00}, // 173 - softhyphen + {0x07, 0x03, 0x04}, // 174 - registered + {0x01, 0x01, 0x01}, // 175 - macron + {0x02, 0x05, 0x02}, // 176 - degree + {0x12, 0x17, 0x12}, // 177 - plusminus + {0x01, 0x07, 0x04}, // 178 - twosuperior + {0x05, 0x07, 0x07}, // 179 - threesuperior + {0x00, 0x02, 0x01}, // 180 - acute + {0x1f, 0x08, 0x07}, // 181 - mu + {0x02, 0x1d, 0x1f}, // 182 - paragraph + {0x0e, 0x0e, 0x0e}, // 183 - periodcentered + {0x10, 0x14, 0x08}, // 184 - cedilla + {0x00, 0x07, 0x00}, // 185 - onesuperior + {0x12, 0x15, 0x12}, // 186 - ordmasculine + {0x00, 0x05, 0x02}, // 187 - guillemotright + {0x03, 0x08, 0x18}, // 188 - onequarter + {0x0b, 0x18, 0x10}, // 189 - onehalf + {0x03, 0x0b, 0x18}, // 190 - threequarters + {0x18, 0x15, 0x10}, // 191 - questiondown + }; +#endif diff --git a/functions.c b/functions.c index a302208..cd02ab1 100644 --- a/functions.c +++ b/functions.c @@ -204,6 +204,9 @@ void FUNCTION_Select(FUNCTION_Type_t Function) DTMF_Reply(); + if (gCurrentVfo->DTMF_PTT_ID_TX_MODE == PTT_ID_APOLLO) + BK4819_PlaySingleTone(2525, 250, 0, gEeprom.DTMF_SIDE_TONE); + #if defined(ENABLE_ALARM) || defined(ENABLE_TX1750) if (gAlarmState != ALARM_STATE_OFF) { diff --git a/AM_fix.mp4 b/images/AM_fix.mp4 similarity index 100% rename from AM_fix.mp4 rename to images/AM_fix.mp4 diff --git a/image1.png b/images/image1.png similarity index 100% rename from image1.png rename to images/image1.png diff --git a/image2.png b/images/image2.png similarity index 100% rename from image2.png rename to images/image2.png diff --git a/image3.png b/images/image3.png similarity index 100% rename from image3.png rename to images/image3.png diff --git a/radio.c b/radio.c index 98b7907..38dd1b5 100644 --- a/radio.c +++ b/radio.c @@ -332,12 +332,12 @@ void RADIO_ConfigureChannel(const unsigned int VFO, const unsigned int configure if (Data[5] == 0xFF) { gEeprom.VfoInfo[VFO].DTMF_DECODING_ENABLE = false; - gEeprom.VfoInfo[VFO].DTMF_PTT_ID_TX_MODE = 0; + gEeprom.VfoInfo[VFO].DTMF_PTT_ID_TX_MODE = PTT_ID_OFF; } else { - gEeprom.VfoInfo[VFO].DTMF_DECODING_ENABLE = !!((Data[5] >> 0) & 1u); - gEeprom.VfoInfo[VFO].DTMF_PTT_ID_TX_MODE = ((Data[5] >> 1) & 3u); + gEeprom.VfoInfo[VFO].DTMF_DECODING_ENABLE = ((Data[5] >> 0) & 1u) ? true : false; + gEeprom.VfoInfo[VFO].DTMF_PTT_ID_TX_MODE = ((Data[5] >> 1) & 7u); } // *************** @@ -1080,8 +1080,12 @@ void RADIO_SendEndOfTransmission(void) if (gEeprom.ROGER == ROGER_MODE_MDC) BK4819_PlayRogerMDC(); + if (gCurrentVfo->DTMF_PTT_ID_TX_MODE == PTT_ID_APOLLO) + BK4819_PlaySingleTone(2475, 250, 28, gEeprom.DTMF_SIDE_TONE); + if (gDTMF_CallState == DTMF_CALL_STATE_NONE && - (gCurrentVfo->DTMF_PTT_ID_TX_MODE == PTT_ID_TX_DOWN || gCurrentVfo->DTMF_PTT_ID_TX_MODE == PTT_ID_BOTH)) + (gCurrentVfo->DTMF_PTT_ID_TX_MODE == PTT_ID_TX_DOWN || + gCurrentVfo->DTMF_PTT_ID_TX_MODE == PTT_ID_BOTH)) { // end-of-tx if (gEeprom.DTMF_SIDE_TONE) { @@ -1093,15 +1097,14 @@ void RADIO_SendEndOfTransmission(void) BK4819_EnterDTMF_TX(gEeprom.DTMF_SIDE_TONE); BK4819_PlayDTMFString( - gEeprom.DTMF_DOWN_CODE, - 0, - gEeprom.DTMF_FIRST_CODE_PERSIST_TIME, - gEeprom.DTMF_HASH_CODE_PERSIST_TIME, - gEeprom.DTMF_CODE_PERSIST_TIME, - gEeprom.DTMF_CODE_INTERVAL_TIME); - + gEeprom.DTMF_DOWN_CODE, + 0, + gEeprom.DTMF_FIRST_CODE_PERSIST_TIME, + gEeprom.DTMF_HASH_CODE_PERSIST_TIME, + gEeprom.DTMF_CODE_PERSIST_TIME, + gEeprom.DTMF_CODE_INTERVAL_TIME); + GPIO_ClearBit(&GPIOC->DATA, GPIOC_PIN_AUDIO_PATH); - gEnableSpeaker = false; } diff --git a/radio.h b/radio.h index 66f1536..e1d03da 100644 --- a/radio.h +++ b/radio.h @@ -44,7 +44,8 @@ enum PTT_ID_t { PTT_ID_OFF = 0, // OFF PTT_ID_TX_UP, // BEGIN OF TX PTT_ID_TX_DOWN, // END OF TX - PTT_ID_BOTH // BOTH + PTT_ID_BOTH, // BOTH + PTT_ID_APOLLO // Apolo quindar tones }; typedef enum PTT_ID_t PTT_ID_t; diff --git a/settings.c b/settings.c index b7821f8..1910c55 100644 --- a/settings.c +++ b/settings.c @@ -219,7 +219,7 @@ void SETTINGS_SaveChannel(uint8_t Channel, uint8_t VFO, const VFO_Info_t *pVFO, | (pVFO->OUTPUT_POWER << 2) | (pVFO->CHANNEL_BANDWIDTH << 1) | (pVFO->FrequencyReverse << 0); - State[5] = (pVFO->DTMF_PTT_ID_TX_MODE << 1) | (pVFO->DTMF_DECODING_ENABLE << 0); + State[5] = ((pVFO->DTMF_PTT_ID_TX_MODE & 7u) << 1) | ((pVFO->DTMF_DECODING_ENABLE & 1u) << 0); State[6] = pVFO->STEP_SETTING; State[7] = pVFO->SCRAMBLING_TYPE; EEPROM_WriteBuffer(OffsetVFO + 8, State); diff --git a/ui/menu.c b/ui/menu.c index 26b3cc0..03984b7 100644 --- a/ui/menu.c +++ b/ui/menu.c @@ -240,12 +240,13 @@ const char gSubMenu_D_RSP[4][11] = "BOTH" }; -const char gSubMenu_PTT_ID[4][7] = +const char gSubMenu_PTT_ID[5][15] = { "OFF", - "KEY UP", - "KEY DN", - "BOTH" + "KEY\nUP", + "KEY\nDOWN", + "KEY\nUP+DOWN", + "APOLLO\nQUINDAR" }; const char gSubMenu_PONMSG[4][8] = diff --git a/ui/menu.h b/ui/menu.h index d4d96fa..157b3d2 100644 --- a/ui/menu.h +++ b/ui/menu.h @@ -139,7 +139,7 @@ extern const char gSubMenu_MDF[4][15]; extern const char gSubMenu_AL_MOD[2][5]; #endif extern const char gSubMenu_D_RSP[4][11]; -extern const char gSubMenu_PTT_ID[4][7]; +extern const char gSubMenu_PTT_ID[5][15]; extern const char gSubMenu_PONMSG[4][8]; extern const char gSubMenu_ROGER[3][9]; extern const char gSubMenu_RESET[2][4];