mirror of
https://github.com/egzumer/uv-k5-firmware-custom
synced 2024-11-22 18:44:58 +00:00
998 lines
24 KiB
C
998 lines
24 KiB
C
/* 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 <string.h>
|
|
|
|
#include "app/dtmf.h"
|
|
#ifdef ENABLE_FMRADIO
|
|
#include "app/fm.h"
|
|
#endif
|
|
#include "audio.h"
|
|
#include "bsp/dp32g030/gpio.h"
|
|
#include "dcs.h"
|
|
#include "driver/bk4819.h"
|
|
#include "driver/eeprom.h"
|
|
#include "driver/gpio.h"
|
|
#include "driver/system.h"
|
|
#include "frequencies.h"
|
|
#include "functions.h"
|
|
#include "helper/battery.h"
|
|
#include "misc.h"
|
|
#include "radio.h"
|
|
#include "settings.h"
|
|
|
|
#ifndef ARRAY_SIZE
|
|
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
|
|
#endif
|
|
|
|
VFO_Info_t *gTxVfo;
|
|
VFO_Info_t *gRxVfo;
|
|
VFO_Info_t *gCurrentVfo;
|
|
DCS_CodeType_t gSelectedCodeType;
|
|
DCS_CodeType_t gCurrentCodeType;
|
|
uint8_t gSelectedCode;
|
|
STEP_Setting_t gStepSetting;
|
|
VfoState_t VfoState[2];
|
|
|
|
bool RADIO_CheckValidChannel(uint16_t Channel, bool bCheckScanList, uint8_t VFO)
|
|
{
|
|
uint8_t Attributes;
|
|
uint8_t PriorityCh1;
|
|
uint8_t PriorityCh2;
|
|
|
|
if (!IS_MR_CHANNEL(Channel))
|
|
return false;
|
|
|
|
// Check channel is valid
|
|
Attributes = gMR_ChannelAttributes[Channel];
|
|
if ((Attributes & MR_CH_BAND_MASK) > BAND7_470MHz)
|
|
return false;
|
|
|
|
if (bCheckScanList)
|
|
{
|
|
switch (VFO)
|
|
{
|
|
case 0:
|
|
if ((Attributes & MR_CH_SCANLIST1) == 0)
|
|
return false;
|
|
|
|
PriorityCh1 = gEeprom.SCANLIST_PRIORITY_CH1[0];
|
|
PriorityCh2 = gEeprom.SCANLIST_PRIORITY_CH2[0];
|
|
break;
|
|
|
|
case 1:
|
|
if ((Attributes & MR_CH_SCANLIST2) == 0)
|
|
return false;
|
|
|
|
PriorityCh1 = gEeprom.SCANLIST_PRIORITY_CH1[1];
|
|
PriorityCh2 = gEeprom.SCANLIST_PRIORITY_CH2[1];
|
|
break;
|
|
|
|
default:
|
|
return true;
|
|
}
|
|
|
|
if (PriorityCh1 == Channel)
|
|
return false;
|
|
|
|
if (PriorityCh2 == Channel)
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
uint8_t RADIO_FindNextChannel(uint8_t Channel, int8_t Direction, bool bCheckScanList, uint8_t VFO)
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < 200; i++)
|
|
{
|
|
if (Channel == 0xFF)
|
|
Channel = MR_CHANNEL_LAST;
|
|
else
|
|
if (Channel > MR_CHANNEL_LAST)
|
|
Channel = MR_CHANNEL_FIRST;
|
|
|
|
if (RADIO_CheckValidChannel(Channel, bCheckScanList, VFO))
|
|
return Channel;
|
|
|
|
Channel += Direction;
|
|
}
|
|
|
|
return 0xFF;
|
|
}
|
|
|
|
void RADIO_InitInfo(VFO_Info_t *pInfo, uint8_t ChannelSave, uint8_t Band, uint32_t Frequency)
|
|
{
|
|
memset(pInfo, 0, sizeof(*pInfo));
|
|
|
|
pInfo->Band = Band;
|
|
pInfo->SCANLIST1_PARTICIPATION = true;
|
|
pInfo->SCANLIST2_PARTICIPATION = true;
|
|
pInfo->STEP_SETTING = STEP_12_5kHz;
|
|
pInfo->StepFrequency = 2500;
|
|
pInfo->CHANNEL_SAVE = ChannelSave;
|
|
pInfo->FrequencyReverse = false;
|
|
pInfo->OUTPUT_POWER = OUTPUT_POWER_LOW;
|
|
pInfo->ConfigRX.Frequency = Frequency;
|
|
pInfo->ConfigTX.Frequency = Frequency;
|
|
pInfo->pRX = &pInfo->ConfigRX;
|
|
pInfo->pTX = &pInfo->ConfigTX;
|
|
pInfo->TX_OFFSET_FREQUENCY = 1000000;
|
|
#ifdef ENABLE_COMPANDER
|
|
pInfo->Compander = false;
|
|
#endif
|
|
|
|
if (ChannelSave == (FREQ_CHANNEL_FIRST + BAND2_108MHz))
|
|
{
|
|
pInfo->AM_CHANNEL_MODE = true;
|
|
pInfo->IsAM = true;
|
|
}
|
|
|
|
RADIO_ConfigureSquelchAndOutputPower(pInfo);
|
|
}
|
|
|
|
void RADIO_ConfigureChannel(uint8_t VFO, uint32_t Arg)
|
|
{
|
|
uint8_t Channel;
|
|
uint8_t Attributes;
|
|
uint8_t Band;
|
|
bool bParticipation2;
|
|
uint16_t Base;
|
|
uint32_t Frequency;
|
|
VFO_Info_t *pRadio = &gEeprom.VfoInfo[VFO];
|
|
|
|
if (!gSetting_350EN)
|
|
{
|
|
if (gEeprom.FreqChannel[VFO] == 204)
|
|
gEeprom.FreqChannel[VFO]++;
|
|
|
|
if (gEeprom.ScreenChannel[VFO] == 204)
|
|
gEeprom.ScreenChannel[VFO]++;
|
|
}
|
|
|
|
Channel = gEeprom.ScreenChannel[VFO];
|
|
|
|
if (IS_VALID_CHANNEL(Channel))
|
|
{
|
|
#ifdef ENABLE_NOAA
|
|
if (Channel >= NOAA_CHANNEL_FIRST)
|
|
{
|
|
RADIO_InitInfo(pRadio, gEeprom.ScreenChannel[VFO], 2, NoaaFrequencyTable[Channel - NOAA_CHANNEL_FIRST]);
|
|
|
|
if (gEeprom.CROSS_BAND_RX_TX == CROSS_BAND_OFF)
|
|
return;
|
|
|
|
gUpdateStatus = true;
|
|
gEeprom.CROSS_BAND_RX_TX = CROSS_BAND_OFF;
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
if (IS_MR_CHANNEL(Channel))
|
|
{
|
|
Channel = RADIO_FindNextChannel(Channel, RADIO_CHANNEL_UP, false, VFO);
|
|
if (Channel == 0xFF)
|
|
{
|
|
Channel = gEeprom.FreqChannel[VFO];
|
|
gEeprom.ScreenChannel[VFO] = gEeprom.FreqChannel[VFO];
|
|
}
|
|
else
|
|
{
|
|
gEeprom.ScreenChannel[VFO] = Channel;
|
|
gEeprom.MrChannel[VFO] = Channel;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
Channel = 205;
|
|
|
|
Attributes = gMR_ChannelAttributes[Channel];
|
|
if (Attributes == 0xFF)
|
|
{
|
|
uint8_t Index;
|
|
|
|
if (IS_MR_CHANNEL(Channel))
|
|
{
|
|
Channel = gEeprom.FreqChannel[VFO];
|
|
gEeprom.ScreenChannel[VFO] = gEeprom.FreqChannel[VFO];
|
|
}
|
|
|
|
Index = Channel - FREQ_CHANNEL_FIRST;
|
|
|
|
RADIO_InitInfo(pRadio, Channel, Index, LowerLimitFrequencyBandTable[Index]);
|
|
return;
|
|
}
|
|
|
|
Band = Attributes & MR_CH_BAND_MASK;
|
|
if (Band > BAND7_470MHz)
|
|
Band = BAND6_400MHz;
|
|
|
|
if (IS_MR_CHANNEL(Channel))
|
|
{
|
|
gEeprom.VfoInfo[VFO].Band = Band;
|
|
gEeprom.VfoInfo[VFO].SCANLIST1_PARTICIPATION = !!(Attributes & MR_CH_SCANLIST1);
|
|
bParticipation2 = !!(Attributes & MR_CH_SCANLIST2);
|
|
}
|
|
else
|
|
{
|
|
Band = Channel - FREQ_CHANNEL_FIRST;
|
|
gEeprom.VfoInfo[VFO].Band = Band;
|
|
bParticipation2 = true;
|
|
gEeprom.VfoInfo[VFO].SCANLIST1_PARTICIPATION = true;
|
|
}
|
|
|
|
gEeprom.VfoInfo[VFO].SCANLIST2_PARTICIPATION = bParticipation2;
|
|
gEeprom.VfoInfo[VFO].CHANNEL_SAVE = Channel;
|
|
|
|
if (IS_MR_CHANNEL(Channel))
|
|
Base = Channel * 16;
|
|
else
|
|
Base = 0x0C80 + ((Channel - FREQ_CHANNEL_FIRST) * 32) + (VFO * 16);
|
|
|
|
if (Arg == 2 || Channel >= FREQ_CHANNEL_FIRST)
|
|
{
|
|
uint8_t Tmp;
|
|
uint8_t Data[8];
|
|
|
|
EEPROM_ReadBuffer(Base + 8, Data, sizeof(Data));
|
|
|
|
Tmp = Data[3] & 0x0F;
|
|
if (Tmp > 2)
|
|
Tmp = 0;
|
|
gEeprom.VfoInfo[VFO].TX_OFFSET_FREQUENCY_DIRECTION = Tmp;
|
|
gEeprom.VfoInfo[VFO].AM_CHANNEL_MODE = !!(Data[3] & 0x10);
|
|
|
|
Tmp = Data[6];
|
|
if (Tmp >= ARRAY_SIZE(StepFrequencyTable))
|
|
Tmp = STEP_12_5kHz;
|
|
gEeprom.VfoInfo[VFO].STEP_SETTING = Tmp;
|
|
gEeprom.VfoInfo[VFO].StepFrequency = StepFrequencyTable[Tmp];
|
|
|
|
Tmp = Data[7];
|
|
if (Tmp > 10)
|
|
Tmp = 0;
|
|
gEeprom.VfoInfo[VFO].SCRAMBLING_TYPE = Tmp;
|
|
|
|
gEeprom.VfoInfo[VFO].ConfigRX.CodeType = (Data[2] >> 0) & 0x0F;
|
|
gEeprom.VfoInfo[VFO].ConfigTX.CodeType = (Data[2] >> 4) & 0x0F;
|
|
|
|
Tmp = Data[0];
|
|
switch (gEeprom.VfoInfo[VFO].ConfigRX.CodeType)
|
|
{
|
|
default:
|
|
case CODE_TYPE_OFF:
|
|
gEeprom.VfoInfo[VFO].ConfigRX.CodeType = CODE_TYPE_OFF;
|
|
Tmp = 0;
|
|
break;
|
|
|
|
case CODE_TYPE_CONTINUOUS_TONE:
|
|
if (Tmp >= 50)
|
|
Tmp = 0;
|
|
break;
|
|
|
|
case CODE_TYPE_DIGITAL:
|
|
case CODE_TYPE_REVERSE_DIGITAL:
|
|
if (Tmp >= 104)
|
|
Tmp = 0;
|
|
break;
|
|
}
|
|
gEeprom.VfoInfo[VFO].ConfigRX.Code = Tmp;
|
|
|
|
Tmp = Data[1];
|
|
switch (gEeprom.VfoInfo[VFO].ConfigTX.CodeType)
|
|
{
|
|
default:
|
|
case CODE_TYPE_OFF:
|
|
gEeprom.VfoInfo[VFO].ConfigTX.CodeType = CODE_TYPE_OFF;
|
|
Tmp = 0;
|
|
break;
|
|
|
|
case CODE_TYPE_CONTINUOUS_TONE:
|
|
if (Tmp >= 50)
|
|
Tmp = 0;
|
|
break;
|
|
|
|
case CODE_TYPE_DIGITAL:
|
|
case CODE_TYPE_REVERSE_DIGITAL:
|
|
if (Tmp >= 104)
|
|
Tmp = 0;
|
|
break;
|
|
}
|
|
gEeprom.VfoInfo[VFO].ConfigTX.Code = Tmp;
|
|
|
|
if (Data[4] == 0xFF)
|
|
{
|
|
gEeprom.VfoInfo[VFO].FrequencyReverse = false;
|
|
gEeprom.VfoInfo[VFO].CHANNEL_BANDWIDTH = 0;
|
|
gEeprom.VfoInfo[VFO].OUTPUT_POWER = OUTPUT_POWER_LOW;
|
|
gEeprom.VfoInfo[VFO].BUSY_CHANNEL_LOCK = false;
|
|
}
|
|
else
|
|
{
|
|
const uint8_t d4 = Data[4];
|
|
gEeprom.VfoInfo[VFO].FrequencyReverse = !!((d4 >> 0) & 1u);
|
|
gEeprom.VfoInfo[VFO].CHANNEL_BANDWIDTH = !!((d4 >> 1) & 1u);
|
|
gEeprom.VfoInfo[VFO].OUTPUT_POWER = ((d4 >> 2) & 3u);
|
|
gEeprom.VfoInfo[VFO].BUSY_CHANNEL_LOCK = !!((d4 >> 4) & 1u);
|
|
}
|
|
|
|
if (Data[5] == 0xFF)
|
|
{
|
|
gEeprom.VfoInfo[VFO].DTMF_DECODING_ENABLE = false;
|
|
gEeprom.VfoInfo[VFO].DTMF_PTT_ID_TX_MODE = 0;
|
|
}
|
|
else
|
|
{
|
|
gEeprom.VfoInfo[VFO].DTMF_DECODING_ENABLE = !!((Data[5] >> 0) & 1u);
|
|
gEeprom.VfoInfo[VFO].DTMF_PTT_ID_TX_MODE = ((Data[5] >> 1) & 3u);
|
|
}
|
|
|
|
struct
|
|
{
|
|
uint32_t Frequency;
|
|
uint32_t Offset;
|
|
} __attribute__((packed)) Info;
|
|
|
|
EEPROM_ReadBuffer(Base, &Info, sizeof(Info));
|
|
pRadio->ConfigRX.Frequency = Info.Frequency;
|
|
if (Info.Offset >= 100000000)
|
|
Info.Offset = 1000000;
|
|
gEeprom.VfoInfo[VFO].TX_OFFSET_FREQUENCY = Info.Offset;
|
|
}
|
|
|
|
Frequency = pRadio->ConfigRX.Frequency;
|
|
|
|
if (Frequency < LowerLimitFrequencyBandTable[Band])
|
|
Frequency = LowerLimitFrequencyBandTable[Band];
|
|
else
|
|
if (Frequency > UpperLimitFrequencyBandTable[Band])
|
|
Frequency = UpperLimitFrequencyBandTable[Band];
|
|
else
|
|
if (Channel >= FREQ_CHANNEL_FIRST)
|
|
Frequency = FREQUENCY_FloorToStep(Frequency, gEeprom.VfoInfo[VFO].StepFrequency, LowerLimitFrequencyBandTable[Band]);
|
|
|
|
pRadio->ConfigRX.Frequency = Frequency;
|
|
|
|
if (Frequency >= 10800000 && Frequency < 13600000)
|
|
gEeprom.VfoInfo[VFO].TX_OFFSET_FREQUENCY_DIRECTION = TX_OFFSET_FREQUENCY_DIRECTION_OFF;
|
|
else
|
|
if (!IS_MR_CHANNEL(Channel))
|
|
gEeprom.VfoInfo[VFO].TX_OFFSET_FREQUENCY = FREQUENCY_FloorToStep(gEeprom.VfoInfo[VFO].TX_OFFSET_FREQUENCY, gEeprom.VfoInfo[VFO].StepFrequency, 0);
|
|
|
|
RADIO_ApplyOffset(pRadio);
|
|
|
|
memset(gEeprom.VfoInfo[VFO].Name, 0, sizeof(gEeprom.VfoInfo[VFO].Name));
|
|
if (IS_MR_CHANNEL(Channel))
|
|
{ // 16 bytes allocated to the channel name but only 12 used
|
|
EEPROM_ReadBuffer(0x0F50 + (Channel * 16), gEeprom.VfoInfo[VFO].Name + 0, 8);
|
|
EEPROM_ReadBuffer(0x0F58 + (Channel * 16), gEeprom.VfoInfo[VFO].Name + 8, 2);
|
|
}
|
|
|
|
if (!gEeprom.VfoInfo[VFO].FrequencyReverse)
|
|
{
|
|
gEeprom.VfoInfo[VFO].pRX = &gEeprom.VfoInfo[VFO].ConfigRX;
|
|
gEeprom.VfoInfo[VFO].pTX = &gEeprom.VfoInfo[VFO].ConfigTX;
|
|
}
|
|
else
|
|
{
|
|
gEeprom.VfoInfo[VFO].pRX = &gEeprom.VfoInfo[VFO].ConfigTX;
|
|
gEeprom.VfoInfo[VFO].pTX = &gEeprom.VfoInfo[VFO].ConfigRX;
|
|
}
|
|
|
|
if (!gSetting_350EN)
|
|
{
|
|
FREQ_Config_t *pConfig = gEeprom.VfoInfo[VFO].pRX;
|
|
if (pConfig->Frequency >= 35000000 && pConfig->Frequency < 40000000)
|
|
pConfig->Frequency = 43300000;
|
|
}
|
|
|
|
if (gEeprom.VfoInfo[VFO].AM_CHANNEL_MODE)
|
|
{
|
|
gEeprom.VfoInfo[VFO].IsAM = true;
|
|
gEeprom.VfoInfo[VFO].SCRAMBLING_TYPE = 0;
|
|
gEeprom.VfoInfo[VFO].DTMF_DECODING_ENABLE = false;
|
|
gEeprom.VfoInfo[VFO].ConfigRX.CodeType = CODE_TYPE_OFF;
|
|
gEeprom.VfoInfo[VFO].ConfigTX.CodeType = CODE_TYPE_OFF;
|
|
}
|
|
else
|
|
gEeprom.VfoInfo[VFO].IsAM = false;
|
|
|
|
#ifdef ENABLE_COMPANDER
|
|
gEeprom.VfoInfo[VFO].Compander = false;
|
|
#endif
|
|
|
|
RADIO_ConfigureSquelchAndOutputPower(pRadio);
|
|
}
|
|
|
|
void RADIO_ConfigureSquelchAndOutputPower(VFO_Info_t *pInfo)
|
|
{
|
|
uint8_t Txp[3];
|
|
FREQUENCY_Band_t Band = FREQUENCY_GetBand(pInfo->pRX->Frequency);
|
|
uint16_t Base = (Band < BAND4_174MHz) ? 0x1E60 : 0x1E00;
|
|
|
|
if (gEeprom.SQUELCH_LEVEL == 0)
|
|
{
|
|
pInfo->SquelchOpenRSSIThresh = 0x00;
|
|
pInfo->SquelchOpenNoiseThresh = 0x7F;
|
|
pInfo->SquelchCloseGlitchThresh = 0xFF;
|
|
pInfo->SquelchCloseRSSIThresh = 0x00;
|
|
pInfo->SquelchCloseNoiseThresh = 0x7F;
|
|
pInfo->SquelchOpenGlitchThresh = 0xFF;
|
|
}
|
|
else
|
|
{
|
|
Base += gEeprom.SQUELCH_LEVEL;
|
|
EEPROM_ReadBuffer(Base + 0x00, &pInfo->SquelchOpenRSSIThresh, 1);
|
|
EEPROM_ReadBuffer(Base + 0x10, &pInfo->SquelchCloseRSSIThresh, 1);
|
|
EEPROM_ReadBuffer(Base + 0x20, &pInfo->SquelchOpenNoiseThresh, 1);
|
|
EEPROM_ReadBuffer(Base + 0x30, &pInfo->SquelchCloseNoiseThresh, 1);
|
|
EEPROM_ReadBuffer(Base + 0x40, &pInfo->SquelchCloseGlitchThresh, 1);
|
|
EEPROM_ReadBuffer(Base + 0x50, &pInfo->SquelchOpenGlitchThresh, 1);
|
|
|
|
if (pInfo->SquelchOpenNoiseThresh > 127)
|
|
pInfo->SquelchOpenNoiseThresh = 127;
|
|
|
|
if (pInfo->SquelchCloseNoiseThresh > 127)
|
|
pInfo->SquelchCloseNoiseThresh = 127;
|
|
}
|
|
|
|
Band = FREQUENCY_GetBand(pInfo->pTX->Frequency);
|
|
|
|
EEPROM_ReadBuffer(0x1ED0 + (Band * 16) + (pInfo->OUTPUT_POWER * 3), Txp, 3);
|
|
|
|
pInfo->TXP_CalculatedSetting = FREQUENCY_CalculateOutputPower(
|
|
Txp[0],
|
|
Txp[1],
|
|
Txp[2],
|
|
LowerLimitFrequencyBandTable[Band],
|
|
MiddleFrequencyBandTable[Band],
|
|
UpperLimitFrequencyBandTable[Band],
|
|
pInfo->pTX->Frequency);
|
|
}
|
|
|
|
void RADIO_ApplyOffset(VFO_Info_t *pInfo)
|
|
{
|
|
uint32_t Frequency = pInfo->ConfigRX.Frequency;
|
|
|
|
switch (pInfo->TX_OFFSET_FREQUENCY_DIRECTION)
|
|
{
|
|
case TX_OFFSET_FREQUENCY_DIRECTION_OFF:
|
|
break;
|
|
case TX_OFFSET_FREQUENCY_DIRECTION_ADD:
|
|
Frequency += pInfo->TX_OFFSET_FREQUENCY;
|
|
break;
|
|
case TX_OFFSET_FREQUENCY_DIRECTION_SUB:
|
|
Frequency -= pInfo->TX_OFFSET_FREQUENCY;
|
|
break;
|
|
}
|
|
|
|
// limit to 50MHz to 600MHz
|
|
if (Frequency < 5000000)
|
|
Frequency = 5000000;
|
|
else
|
|
if (Frequency > 60000000)
|
|
Frequency = 60000000;
|
|
|
|
pInfo->ConfigTX.Frequency = Frequency;
|
|
}
|
|
|
|
static void RADIO_SelectCurrentVfo(void)
|
|
{
|
|
gCurrentVfo = (gEeprom.CROSS_BAND_RX_TX == CROSS_BAND_OFF) ? gRxVfo : &gEeprom.VfoInfo[gEeprom.TX_CHANNEL];
|
|
}
|
|
|
|
void RADIO_SelectVfos(void)
|
|
{
|
|
if (gEeprom.CROSS_BAND_RX_TX == CROSS_BAND_CHAN_B)
|
|
gEeprom.TX_CHANNEL = 1;
|
|
else
|
|
if (gEeprom.CROSS_BAND_RX_TX == CROSS_BAND_CHAN_A)
|
|
gEeprom.TX_CHANNEL = 0;
|
|
else
|
|
if (gEeprom.DUAL_WATCH == DUAL_WATCH_CHAN_B)
|
|
gEeprom.TX_CHANNEL = 1;
|
|
else
|
|
if (gEeprom.DUAL_WATCH == DUAL_WATCH_CHAN_A)
|
|
gEeprom.TX_CHANNEL = 0;
|
|
|
|
if (gEeprom.CROSS_BAND_RX_TX == CROSS_BAND_OFF)
|
|
gEeprom.RX_CHANNEL = gEeprom.TX_CHANNEL;
|
|
else
|
|
gEeprom.RX_CHANNEL = (gEeprom.TX_CHANNEL == 0) ? 1 : 0;
|
|
|
|
gTxVfo = &gEeprom.VfoInfo[gEeprom.TX_CHANNEL];
|
|
gRxVfo = &gEeprom.VfoInfo[gEeprom.RX_CHANNEL];
|
|
|
|
RADIO_SelectCurrentVfo();
|
|
}
|
|
|
|
void RADIO_SetupRegisters(bool bSwitchToFunction0)
|
|
{
|
|
BK4819_FilterBandwidth_t Bandwidth;
|
|
uint16_t InterruptMask;
|
|
uint32_t Frequency;
|
|
|
|
GPIO_ClearBit(&GPIOC->DATA, GPIOC_PIN_AUDIO_PATH);
|
|
|
|
gEnableSpeaker = false;
|
|
|
|
BK4819_ToggleGpioOut(BK4819_GPIO0_PIN28_GREEN, false);
|
|
|
|
Bandwidth = gRxVfo->CHANNEL_BANDWIDTH;
|
|
if (Bandwidth != BK4819_FILTER_BW_WIDE)
|
|
Bandwidth = BK4819_FILTER_BW_NARROW;
|
|
BK4819_SetFilterBandwidth(Bandwidth);
|
|
|
|
BK4819_ToggleGpioOut(BK4819_GPIO1_PIN29_RED, false);
|
|
|
|
BK4819_SetupPowerAmplifier(0, 0);
|
|
|
|
BK4819_ToggleGpioOut(BK4819_GPIO5_PIN1, false);
|
|
|
|
while (1)
|
|
{
|
|
const uint16_t Status = BK4819_ReadRegister(BK4819_REG_0C);
|
|
if ((Status & 1u) == 0) // INTERRUPT REQUEST
|
|
break;
|
|
|
|
BK4819_WriteRegister(BK4819_REG_02, 0);
|
|
SYSTEM_DelayMs(1);
|
|
}
|
|
BK4819_WriteRegister(BK4819_REG_3F, 0);
|
|
|
|
// mic gain 0.5dB/step 0 to 31
|
|
BK4819_WriteRegister(BK4819_REG_7D, 0xE940 | (gEeprom.MIC_SENSITIVITY_TUNING & 0x1f));
|
|
|
|
#ifdef ENABLE_NOAA
|
|
if (IS_NOT_NOAA_CHANNEL(gRxVfo->CHANNEL_SAVE) || !gIsNoaaMode)
|
|
Frequency = gRxVfo->pRX->Frequency;
|
|
else
|
|
Frequency = NoaaFrequencyTable[gNoaaChannel];
|
|
#else
|
|
Frequency = gRxVfo->pRX->Frequency;
|
|
#endif
|
|
BK4819_SetFrequency(Frequency);
|
|
|
|
BK4819_SetupSquelch(
|
|
gRxVfo->SquelchOpenRSSIThresh, gRxVfo->SquelchCloseRSSIThresh,
|
|
gRxVfo->SquelchOpenNoiseThresh, gRxVfo->SquelchCloseNoiseThresh,
|
|
gRxVfo->SquelchCloseGlitchThresh, gRxVfo->SquelchOpenGlitchThresh);
|
|
|
|
BK4819_PickRXFilterPathBasedOnFrequency(Frequency);
|
|
|
|
BK4819_ToggleGpioOut(BK4819_GPIO6_PIN2, true);
|
|
|
|
// AF Rx Gain and DAC
|
|
BK4819_WriteRegister(BK4819_REG_48, 0xB3A8); // 1011 00 111010 1000
|
|
|
|
InterruptMask = BK4819_REG_3F_SQUELCH_FOUND | BK4819_REG_3F_SQUELCH_LOST;
|
|
|
|
#ifdef ENABLE_NOAA
|
|
if (IS_NOT_NOAA_CHANNEL(gRxVfo->CHANNEL_SAVE))
|
|
#endif
|
|
{
|
|
if (!gRxVfo->IsAM)
|
|
{
|
|
uint8_t CodeType = gSelectedCodeType;
|
|
uint8_t Code = gSelectedCode;
|
|
if (gCssScanMode == CSS_SCAN_MODE_OFF)
|
|
{
|
|
CodeType = gRxVfo->pRX->CodeType;
|
|
Code = gRxVfo->pRX->Code;
|
|
}
|
|
|
|
switch (CodeType)
|
|
{
|
|
default:
|
|
case CODE_TYPE_OFF:
|
|
BK4819_SetCTCSSFrequency(670);
|
|
|
|
//#ifndef ENABLE_CTCSS_TAIL_PHASE_SHIFT
|
|
BK4819_SetTailDetection(550); // QS's 55Hz tone method
|
|
//#else
|
|
// BK4819_SetTailDetection(670); // 67Hz
|
|
//#endif
|
|
|
|
InterruptMask = 0
|
|
| BK4819_REG_3F_CxCSS_TAIL
|
|
| BK4819_REG_3F_SQUELCH_FOUND
|
|
| BK4819_REG_3F_SQUELCH_LOST;
|
|
|
|
break;
|
|
|
|
case CODE_TYPE_CONTINUOUS_TONE:
|
|
BK4819_SetCTCSSFrequency(CTCSS_Options[Code]);
|
|
|
|
//#ifndef ENABLE_CTCSS_TAIL_PHASE_SHIFT
|
|
BK4819_SetTailDetection(550); // QS's 55Hz tone method
|
|
//#else
|
|
// BK4819_SetTailDetection(CTCSS_Options[Code]);
|
|
//#endif
|
|
|
|
InterruptMask = 0
|
|
| BK4819_REG_3F_CxCSS_TAIL
|
|
| BK4819_REG_3F_CTCSS_FOUND
|
|
| BK4819_REG_3F_CTCSS_LOST
|
|
| BK4819_REG_3F_SQUELCH_FOUND
|
|
| BK4819_REG_3F_SQUELCH_LOST;
|
|
|
|
break;
|
|
|
|
case CODE_TYPE_DIGITAL:
|
|
case CODE_TYPE_REVERSE_DIGITAL:
|
|
BK4819_SetCDCSSCodeWord(DCS_GetGolayCodeWord(CodeType, Code));
|
|
InterruptMask = 0
|
|
| BK4819_REG_3F_CxCSS_TAIL
|
|
| BK4819_REG_3F_CDCSS_FOUND
|
|
| BK4819_REG_3F_CDCSS_LOST
|
|
| BK4819_REG_3F_SQUELCH_FOUND
|
|
| BK4819_REG_3F_SQUELCH_LOST;
|
|
break;
|
|
}
|
|
|
|
if (gRxVfo->SCRAMBLING_TYPE == 0 || !gSetting_ScrambleEnable)
|
|
BK4819_DisableScramble();
|
|
else
|
|
BK4819_EnableScramble(gRxVfo->SCRAMBLING_TYPE - 1);
|
|
}
|
|
}
|
|
#ifdef ENABLE_NOAA
|
|
else
|
|
{
|
|
BK4819_SetCTCSSFrequency(2625);
|
|
InterruptMask = 0
|
|
| BK4819_REG_3F_CTCSS_FOUND
|
|
| BK4819_REG_3F_CTCSS_LOST
|
|
| BK4819_REG_3F_SQUELCH_FOUND
|
|
| BK4819_REG_3F_SQUELCH_LOST;
|
|
}
|
|
#endif
|
|
|
|
#ifdef ENABLE_NOAA
|
|
#ifdef ENABLE_FMRADIO
|
|
if (gEeprom.VOX_SWITCH && !gFmRadioMode && IS_NOT_NOAA_CHANNEL(gCurrentVfo->CHANNEL_SAVE) && !gCurrentVfo->IsAM)
|
|
#else
|
|
if (gEeprom.VOX_SWITCH && IS_NOT_NOAA_CHANNEL(gCurrentVfo->CHANNEL_SAVE) && !gCurrentVfo->IsAM)
|
|
#endif
|
|
#else
|
|
#ifdef ENABLE_FMRADIO
|
|
if (gEeprom.VOX_SWITCH && !gFmRadioMode && !gCurrentVfo->IsAM)
|
|
#else
|
|
if (gEeprom.VOX_SWITCH && !gCurrentVfo->IsAM)
|
|
#endif
|
|
#endif
|
|
{
|
|
BK4819_EnableVox(gEeprom.VOX1_THRESHOLD, gEeprom.VOX0_THRESHOLD);
|
|
InterruptMask |= BK4819_REG_3F_VOX_FOUND | BK4819_REG_3F_VOX_LOST;
|
|
}
|
|
else
|
|
BK4819_DisableVox();
|
|
|
|
#ifdef ENABLE_COMPANDER
|
|
if (gRxVfo->Compander && !gRxVfo->IsAM)
|
|
BK4819_EnableCompander();
|
|
else
|
|
BK4819_DisableCompander();
|
|
#endif
|
|
|
|
if (gRxVfo->IsAM || (!gRxVfo->DTMF_DECODING_ENABLE && !gSetting_KILLED))
|
|
{
|
|
BK4819_DisableDTMF();
|
|
}
|
|
else
|
|
{
|
|
BK4819_EnableDTMF();
|
|
InterruptMask |= BK4819_REG_3F_DTMF_5TONE_FOUND;
|
|
}
|
|
|
|
// enable/disable BK4819 interrupts
|
|
BK4819_WriteRegister(BK4819_REG_3F, InterruptMask);
|
|
|
|
FUNCTION_Init();
|
|
|
|
if (bSwitchToFunction0)
|
|
FUNCTION_Select(FUNCTION_FOREGROUND);
|
|
}
|
|
|
|
#ifdef ENABLE_NOAA
|
|
void RADIO_ConfigureNOAA(void)
|
|
{
|
|
uint8_t ChanAB;
|
|
|
|
gUpdateStatus = true;
|
|
|
|
if (gEeprom.NOAA_AUTO_SCAN)
|
|
{
|
|
if (gEeprom.DUAL_WATCH != DUAL_WATCH_OFF)
|
|
{
|
|
if (IS_NOT_NOAA_CHANNEL(gEeprom.ScreenChannel[0]))
|
|
{
|
|
if (IS_NOT_NOAA_CHANNEL(gEeprom.ScreenChannel[1]))
|
|
{
|
|
gIsNoaaMode = false;
|
|
return;
|
|
}
|
|
ChanAB = 1;
|
|
}
|
|
else
|
|
ChanAB = 0;
|
|
|
|
if (!gIsNoaaMode)
|
|
gNoaaChannel = gEeprom.VfoInfo[ChanAB].CHANNEL_SAVE - NOAA_CHANNEL_FIRST;
|
|
|
|
gIsNoaaMode = true;
|
|
return;
|
|
}
|
|
|
|
if (gRxVfo->CHANNEL_SAVE >= NOAA_CHANNEL_FIRST)
|
|
{
|
|
gIsNoaaMode = true;
|
|
gNoaaChannel = gRxVfo->CHANNEL_SAVE - NOAA_CHANNEL_FIRST;
|
|
gNOAA_Countdown = 50;
|
|
gScheduleNOAA = false;
|
|
}
|
|
else
|
|
gIsNoaaMode = false;
|
|
}
|
|
else
|
|
gIsNoaaMode = false;
|
|
}
|
|
#endif
|
|
|
|
void RADIO_SetTxParameters(void)
|
|
{
|
|
BK4819_FilterBandwidth_t Bandwidth;
|
|
|
|
GPIO_ClearBit(&GPIOC->DATA, GPIOC_PIN_AUDIO_PATH);
|
|
|
|
gEnableSpeaker = false;
|
|
|
|
BK4819_ToggleGpioOut(BK4819_GPIO6_PIN2, false);
|
|
|
|
Bandwidth = gCurrentVfo->CHANNEL_BANDWIDTH;
|
|
if (Bandwidth != BK4819_FILTER_BW_WIDE)
|
|
Bandwidth = BK4819_FILTER_BW_NARROW;
|
|
BK4819_SetFilterBandwidth(Bandwidth);
|
|
|
|
BK4819_SetFrequency(gCurrentVfo->pTX->Frequency);
|
|
|
|
#ifdef ENABLE_COMPANDER
|
|
if (gCurrentVfo->Compander && !gCurrentVfo->IsAM)
|
|
BK4819_EnableCompander();
|
|
else
|
|
BK4819_DisableCompander();
|
|
#endif
|
|
|
|
BK4819_PrepareTransmit();
|
|
|
|
SYSTEM_DelayMs(10);
|
|
|
|
BK4819_PickRXFilterPathBasedOnFrequency(gCurrentVfo->pTX->Frequency);
|
|
|
|
BK4819_ToggleGpioOut(BK4819_GPIO5_PIN1, true);
|
|
|
|
SYSTEM_DelayMs(5);
|
|
|
|
BK4819_SetupPowerAmplifier(gCurrentVfo->TXP_CalculatedSetting, gCurrentVfo->pTX->Frequency);
|
|
|
|
SYSTEM_DelayMs(10);
|
|
|
|
switch (gCurrentVfo->pTX->CodeType)
|
|
{
|
|
default:
|
|
case CODE_TYPE_OFF:
|
|
BK4819_ExitSubAu();
|
|
break;
|
|
|
|
case CODE_TYPE_CONTINUOUS_TONE:
|
|
BK4819_SetCTCSSFrequency(CTCSS_Options[gCurrentVfo->pTX->Code]);
|
|
break;
|
|
|
|
case CODE_TYPE_DIGITAL:
|
|
case CODE_TYPE_REVERSE_DIGITAL:
|
|
BK4819_SetCDCSSCodeWord(
|
|
DCS_GetGolayCodeWord(gCurrentVfo->pTX->CodeType, gCurrentVfo->pTX->Code)
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void RADIO_SetVfoState(VfoState_t State)
|
|
{
|
|
if (State == VFO_STATE_NORMAL)
|
|
{
|
|
VfoState[0] = VFO_STATE_NORMAL;
|
|
VfoState[1] = VFO_STATE_NORMAL;
|
|
|
|
#ifdef ENABLE_FMRADIO
|
|
gFM_ResumeCountdown = 0;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
if (State == VFO_STATE_VOLTAGE_HIGH)
|
|
{
|
|
VfoState[0] = VFO_STATE_VOLTAGE_HIGH;
|
|
VfoState[1] = VFO_STATE_TX_DISABLE;
|
|
}
|
|
else
|
|
{
|
|
const uint8_t Channel = (gEeprom.CROSS_BAND_RX_TX == CROSS_BAND_OFF) ? gEeprom.RX_CHANNEL : gEeprom.TX_CHANNEL;
|
|
VfoState[Channel] = State;
|
|
}
|
|
|
|
#ifdef ENABLE_FMRADIO
|
|
gFM_ResumeCountdown = 5;
|
|
#endif
|
|
}
|
|
|
|
gUpdateDisplay = true;
|
|
}
|
|
|
|
void RADIO_PrepareTX(void)
|
|
{
|
|
if (gEeprom.DUAL_WATCH != DUAL_WATCH_OFF)
|
|
{
|
|
gDualWatchCountdown = dual_watch_count_after_tx;
|
|
gScheduleDualWatch = false;
|
|
|
|
if (!gRxVfoIsActive)
|
|
{
|
|
gEeprom.RX_CHANNEL = gEeprom.TX_CHANNEL;
|
|
gRxVfo = &gEeprom.VfoInfo[gEeprom.TX_CHANNEL];
|
|
}
|
|
gRxVfoIsActive = true;
|
|
}
|
|
|
|
RADIO_SelectCurrentVfo();
|
|
|
|
#ifdef ENABLE_ALARM
|
|
if (gAlarmState == ALARM_STATE_OFF || gAlarmState == ALARM_STATE_TX1750 || (gAlarmState == ALARM_STATE_ALARM && gEeprom.ALARM_MODE == ALARM_MODE_TONE))
|
|
#endif
|
|
{
|
|
VfoState_t State;
|
|
|
|
#ifndef ENABLE_TX_WHEN_AM
|
|
// disable the TX when VFO/Channel is set to AM
|
|
// the radio does NOT do AM, the adverts are false
|
|
if (gCurrentVfo->IsAM)
|
|
State = VFO_STATE_TX_DISABLE;
|
|
else
|
|
#endif
|
|
if (!FREQUENCY_Check(gCurrentVfo))
|
|
{
|
|
if (gCurrentVfo->BUSY_CHANNEL_LOCK && gCurrentFunction == FUNCTION_RECEIVE)
|
|
State = VFO_STATE_BUSY;
|
|
else
|
|
if (gBatteryDisplayLevel == 0)
|
|
State = VFO_STATE_BAT_LOW;
|
|
else
|
|
if (gBatteryDisplayLevel >= 6)
|
|
State = VFO_STATE_VOLTAGE_HIGH;
|
|
else
|
|
goto Skip;
|
|
}
|
|
else
|
|
State = VFO_STATE_TX_DISABLE;
|
|
|
|
RADIO_SetVfoState(State);
|
|
|
|
#ifdef ENABLE_ALARM
|
|
gAlarmState = ALARM_STATE_OFF;
|
|
#endif
|
|
|
|
AUDIO_PlayBeep(BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL);
|
|
|
|
gDTMF_ReplyState = DTMF_REPLY_NONE;
|
|
|
|
return;
|
|
}
|
|
|
|
Skip:
|
|
if (gDTMF_ReplyState == DTMF_REPLY_ANI)
|
|
{
|
|
if (gDTMF_CallMode == DTMF_CALL_MODE_DTMF)
|
|
{
|
|
gDTMF_IsTx = true;
|
|
gDTMF_CallState = DTMF_CALL_STATE_NONE;
|
|
gDTMF_TxStopCountdown = 6;
|
|
}
|
|
else
|
|
{
|
|
gDTMF_CallState = DTMF_CALL_STATE_CALL_OUT;
|
|
gDTMF_IsTx = false;
|
|
}
|
|
}
|
|
|
|
FUNCTION_Select(FUNCTION_TRANSMIT);
|
|
|
|
#ifdef ENABLE_ALARM
|
|
gTxTimerCountdown = (gAlarmState == ALARM_STATE_OFF) ? gEeprom.TX_TIMEOUT_TIMER * 120 : 0;
|
|
#else
|
|
gTxTimerCountdown = gEeprom.TX_TIMEOUT_TIMER * 120;
|
|
#endif
|
|
|
|
gTxTimeoutReached = false;
|
|
gFlagEndTransmission = false;
|
|
gRTTECountdown = 0;
|
|
gDTMF_ReplyState = DTMF_REPLY_NONE;
|
|
}
|
|
|
|
void RADIO_EnableCxCSS(void)
|
|
{
|
|
switch (gCurrentVfo->pTX->CodeType)
|
|
{
|
|
case CODE_TYPE_OFF:
|
|
break;
|
|
|
|
case CODE_TYPE_CONTINUOUS_TONE:
|
|
BK4819_EnableCTCSS();
|
|
SYSTEM_DelayMs(200);
|
|
break;
|
|
|
|
case CODE_TYPE_DIGITAL:
|
|
case CODE_TYPE_REVERSE_DIGITAL:
|
|
BK4819_EnableCDCSS();
|
|
SYSTEM_DelayMs(200);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void RADIO_PrepareCssTX(void)
|
|
{
|
|
RADIO_PrepareTX();
|
|
SYSTEM_DelayMs(200);
|
|
RADIO_EnableCxCSS();
|
|
RADIO_SetupRegisters(true);
|
|
}
|
|
|
|
void RADIO_SendEndOfTransmission(void)
|
|
{
|
|
if (gEeprom.ROGER == ROGER_MODE_ROGER)
|
|
BK4819_PlayRoger();
|
|
else
|
|
if (gEeprom.ROGER == ROGER_MODE_MDC)
|
|
BK4819_PlayRogerMDC();
|
|
|
|
if (gDTMF_CallState == DTMF_CALL_STATE_NONE && (gCurrentVfo->DTMF_PTT_ID_TX_MODE == PTT_ID_EOT || gCurrentVfo->DTMF_PTT_ID_TX_MODE == PTT_ID_BOTH))
|
|
{
|
|
if (gEeprom.DTMF_SIDE_TONE)
|
|
{
|
|
GPIO_SetBit(&GPIOC->DATA, GPIOC_PIN_AUDIO_PATH);
|
|
gEnableSpeaker = true;
|
|
SYSTEM_DelayMs(60);
|
|
}
|
|
|
|
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);
|
|
|
|
GPIO_ClearBit(&GPIOC->DATA, GPIOC_PIN_AUDIO_PATH);
|
|
|
|
gEnableSpeaker = false;
|
|
}
|
|
|
|
BK4819_ExitDTMF_TX(true);
|
|
}
|