528 lines
14 KiB
C
528 lines
14 KiB
C
/*
|
|
* Copyright (C) 2021-2025 Roger Clark, VK3KYY / G4KYF
|
|
*
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
|
|
* in the documentation and/or other materials provided with the distribution.
|
|
*
|
|
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* 4. Use of this source code or binary releases for commercial purposes is strictly forbidden. This includes, without limitation,
|
|
* incorporation in a commercial product or incorporation into a product or project which allows commercial use.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
*/
|
|
|
|
#include "functions/settings.h"
|
|
#include "functions/trx.h"
|
|
#include "functions/rxPowerSaving.h"
|
|
#include "hardware/HR-C6000.h"
|
|
#include "hardware/AT1846S.h"
|
|
#if defined(USING_EXTERNAL_DEBUGGER)
|
|
#include "SeggerRTT/RTT/SEGGER_RTT.h"
|
|
#endif
|
|
#include "main.h"
|
|
|
|
#if defined(PLATFORM_MD9600)
|
|
//list of CTCSS tones supported by the HRC6000. These are used to find the index for the tone. The order is critical.
|
|
const uint16_t HRC_CTCSSTones[] =
|
|
{
|
|
6700, 7190, 7440, 7700, 7970, 8250, 8540,
|
|
8850, 9150, 9480, 9740, 10000, 10350, 10720,
|
|
11090, 11480, 11880, 12300, 12730, 13180, 13650,
|
|
14130, 14620, 15140, 15670, 16220, 16790, 17380,
|
|
17990, 18620, 19280, 20350, 21070, 21810, 22570,
|
|
23360, 24180, 25030, 6930, 6250, 15980, 16550,
|
|
17130, 17730, 18350, 18990, 19660, 19950, 20650,
|
|
22910, 25410
|
|
};
|
|
#endif
|
|
|
|
// AT-1846 native values for Rx
|
|
static uint8_t fl_l;
|
|
static uint8_t fl_h;
|
|
static uint8_t fh_l;
|
|
static uint8_t fh_h;
|
|
|
|
RadioDevice_t currentRadioDeviceId = RADIO_DEVICE_PRIMARY;
|
|
TRXDevice_t radioDevices[RADIO_DEVICE_MAX] = {
|
|
{
|
|
.currentRxFrequency = FREQUENCY_UNSET,
|
|
.currentTxFrequency = FREQUENCY_UNSET,
|
|
.lastSetTxFrequency = FREQUENCY_UNSET,
|
|
.trxCurrentBand = { RADIO_BAND_VHF, RADIO_BAND_VHF },
|
|
.trxDMRModeRx = DMR_MODE_DMO,
|
|
.trxDMRModeTx = DMR_MODE_DMO,
|
|
.currentMode = RADIO_MODE_NONE,
|
|
.txPowerLevel = POWER_UNSET,
|
|
.lastSetTxPowerLevel = POWER_UNSET,
|
|
.trxRxSignal = 0,
|
|
.trxRxNoise = 255,
|
|
.currentBandWidthIs25kHz = BANDWIDTH_12P5KHZ,
|
|
.analogSignalReceived = false,
|
|
.analogTriggeredAudio = false,
|
|
.digitalSignalReceived = false
|
|
}
|
|
};
|
|
|
|
TRXDevice_t *currentRadioDevice = &radioDevices[RADIO_DEVICE_PRIMARY];
|
|
|
|
void radioPowerOn(void)
|
|
{
|
|
//Turn off Tx Voltages to prevent transmission.
|
|
HAL_GPIO_WritePin(PA_EN_1_GPIO_Port, PA_EN_1_Pin, GPIO_PIN_RESET);
|
|
HAL_GPIO_WritePin(PA_EN_2_GPIO_Port, PA_EN_2_Pin, GPIO_PIN_RESET);
|
|
|
|
//Turn on all receiver voltages. (thats what the TYT firmware does, both receivers are on together)
|
|
|
|
radioSetRxLNAForDevice(currentRadioDeviceId);
|
|
|
|
HAL_GPIO_WritePin(C6000_PWD_GPIO_Port, C6000_PWD_Pin, GPIO_PIN_RESET);// Power On the C6000
|
|
|
|
//Turn on the Microphone power
|
|
HAL_GPIO_WritePin(MICPWR_SW_GPIO_Port, MICPWR_SW_Pin, GPIO_PIN_SET);
|
|
}
|
|
|
|
void radioSetRxLNAForDevice(RadioDevice_t deviceId)
|
|
{
|
|
if (radioDevices[deviceId].trxCurrentBand[TRX_RX_FREQ_BAND] == RADIO_BAND_VHF)
|
|
{
|
|
HAL_GPIO_WritePin(R5_V_SW_GPIO_Port, R5_V_SW_Pin, GPIO_PIN_SET);
|
|
HAL_GPIO_WritePin(R5_U_SW_GPIO_Port, R5_U_SW_Pin, GPIO_PIN_RESET);
|
|
}
|
|
else
|
|
{
|
|
HAL_GPIO_WritePin(R5_V_SW_GPIO_Port, R5_V_SW_Pin, GPIO_PIN_RESET);
|
|
HAL_GPIO_WritePin(R5_U_SW_GPIO_Port, R5_U_SW_Pin, GPIO_PIN_SET);
|
|
}
|
|
}
|
|
|
|
void radioPowerOff(bool invalidateFrequency, bool includeMic)
|
|
{
|
|
//turn off all of the transmitter and receiver voltages
|
|
HAL_GPIO_WritePin(PA_EN_1_GPIO_Port, PA_EN_1_Pin, GPIO_PIN_RESET);
|
|
HAL_GPIO_WritePin(PA_EN_2_GPIO_Port, PA_EN_2_Pin, GPIO_PIN_RESET);
|
|
|
|
HAL_GPIO_WritePin(R5_V_SW_GPIO_Port, R5_V_SW_Pin, GPIO_PIN_RESET);
|
|
HAL_GPIO_WritePin(R5_U_SW_GPIO_Port, R5_U_SW_Pin, GPIO_PIN_RESET);
|
|
|
|
// Some external speaker mic are problematic when the
|
|
// Mic pin is powered down, triggering some cycling PTT down events.
|
|
// So, we're keeping that pin high all the time when Rx Power Saving is running
|
|
if (includeMic)
|
|
{
|
|
HAL_GPIO_WritePin(MICPWR_SW_GPIO_Port, MICPWR_SW_Pin, GPIO_PIN_RESET);
|
|
}
|
|
|
|
HAL_GPIO_WritePin(C6000_PWD_GPIO_Port, C6000_PWD_Pin, GPIO_PIN_SET);// Power Down the C6000
|
|
|
|
// Turn off Rx in AT1846S
|
|
if (currentRadioDevice->currentBandWidthIs25kHz)
|
|
{
|
|
// 25 kHz settings
|
|
radioWriteReg2byte(0x30, 0x70, 0x06); // RX off
|
|
}
|
|
else
|
|
{
|
|
// 12.5 kHz settings
|
|
radioWriteReg2byte(0x30, 0x40, 0x06); // RX off
|
|
}
|
|
|
|
if (invalidateFrequency)
|
|
{
|
|
trxInvalidateCurrentFrequency();
|
|
}
|
|
}
|
|
|
|
void radioInit(void)
|
|
{
|
|
radioSetTRxDevice(RADIO_DEVICE_PRIMARY);
|
|
AT1846sInit();
|
|
}
|
|
|
|
void radioPostinit(void)
|
|
{
|
|
AT1846sPostInit();
|
|
}
|
|
|
|
RadioDevice_t radioSetTRxDevice(RadioDevice_t deviceId)
|
|
{
|
|
RadioDevice_t previousDeviceId = currentRadioDeviceId;
|
|
|
|
currentRadioDeviceId = deviceId;
|
|
|
|
currentRadioDevice = &radioDevices[currentRadioDeviceId];
|
|
|
|
return previousDeviceId;
|
|
}
|
|
|
|
RadioDevice_t radioGetTRxDeviceId(void)
|
|
{
|
|
return currentRadioDeviceId;
|
|
}
|
|
|
|
void radioSetBandwidth(bool Is25K)
|
|
{
|
|
AT1846sSetBandWidth(Is25K);
|
|
}
|
|
|
|
void radioSetMode(int mode) // Called withing trx.c: in task critical sections
|
|
{
|
|
if (mode == RADIO_MODE_ANALOG)
|
|
{
|
|
HRC6000SetFMRx();
|
|
}
|
|
else
|
|
{
|
|
HRC6000SetDMR();
|
|
}
|
|
AT1846sSetMode(mode);
|
|
}
|
|
|
|
void radioReadVoxAndMicStrength(void)
|
|
{
|
|
trxTxVox = adcGetVOX(); //MDUV380 Mic is not connected to AT1846 but has dedicated ADC channel like MD9600
|
|
trxTxMic = trxTxVox; //MDUV380 doesn't have separate Signals so use Vox for both.
|
|
}
|
|
|
|
static void trxUpdateAT1846SCalibration(void)
|
|
{
|
|
//Nothing needed on the MDUV380
|
|
}
|
|
|
|
void radioSetFrequency(uint32_t f_in, bool Tx)
|
|
{
|
|
// G4EML. Hack to fix the -3KHz offset on transmit on the MDUV380
|
|
// Believed to be caused by something in the AT1846S configuration.
|
|
// If we ever fix what is causing it then this hack can be removed.
|
|
if (Tx)
|
|
{
|
|
if (currentRadioDevice->currentBandWidthIs25kHz)
|
|
{
|
|
#warning Hack for FM 25khz bandwidth, somehow needed after changes to activate both AT1846S. Needs more investigation, as it may be masking another problem
|
|
f_in = f_in + 615; //add 6.15Khz to Tx frequency
|
|
}
|
|
else
|
|
{
|
|
f_in = f_in + 300; //add 3Khz to Tx frequency
|
|
}
|
|
}
|
|
//
|
|
|
|
if (currentChannelData->libreDMR_Power != 0x00)
|
|
{
|
|
currentRadioDevice->txPowerLevel = currentChannelData->libreDMR_Power - 1;
|
|
}
|
|
else
|
|
{
|
|
currentRadioDevice->txPowerLevel = nonVolatileSettings.txPowerLevel;
|
|
}
|
|
|
|
if (Tx)
|
|
{
|
|
currentRadioDevice->trxCurrentBand[TRX_TX_FREQ_BAND] = trxGetBandFromFrequency(f_in);
|
|
}
|
|
else
|
|
{
|
|
currentRadioDevice->trxCurrentBand[TRX_RX_FREQ_BAND] = trxGetBandFromFrequency(f_in);
|
|
radioSetRxLNAForDevice(currentRadioDeviceId);
|
|
}
|
|
|
|
uint32_t f = f_in * 0.16f;
|
|
fl_l = (f & 0x000000ff) >> 0;
|
|
fl_h = (f & 0x0000ff00) >> 8;
|
|
fh_l = (f & 0x00ff0000) >> 16;
|
|
fh_h = (f & 0xff000000) >> 24;
|
|
|
|
if (currentRadioDevice->currentBandWidthIs25kHz)
|
|
{
|
|
// 25 kHz settings
|
|
radioWriteReg2byte(0x30, 0x70, 0x06); // RX off
|
|
}
|
|
else
|
|
{
|
|
// 12.5 kHz settings
|
|
radioWriteReg2byte(0x30, 0x60, 0x06); // RX off
|
|
}
|
|
radioWriteReg2byte(0x05, 0x87, 0x63); // select 'normal' frequency mode
|
|
|
|
radioWriteReg2byte(0x29, fh_h, fh_l);
|
|
radioWriteReg2byte(0x2a, fl_h, fl_l);
|
|
radioWriteReg2byte(0x49, 0x0C, 0x15); // setting SQ open and shut threshold
|
|
|
|
if (currentRadioDevice->currentBandWidthIs25kHz)
|
|
{
|
|
// 25 kHz settings
|
|
radioWriteReg2byte(0x30, 0x70, 0x26); // RX on
|
|
}
|
|
else
|
|
{
|
|
// 12.5 kHz settings
|
|
radioWriteReg2byte(0x30, 0x60, 0x26); // RX on
|
|
}
|
|
|
|
trxUpdateAT1846SCalibration();
|
|
|
|
|
|
if (Tx) //We have just set the Tx frequency so we are about to transmit. Set the Tx Power Control DAC (Shared with VHF Receive Tuning)
|
|
{
|
|
dacOut(1, txDACDrivePower);
|
|
}
|
|
else
|
|
{
|
|
dacOut(1, 0);
|
|
}
|
|
}
|
|
|
|
void radioSetIF(int band, bool wide)
|
|
{
|
|
UNUSED_PARAMETER(band);
|
|
|
|
radioSetBandwidth(wide);
|
|
}
|
|
|
|
void radioSetTx(uint8_t band)
|
|
{
|
|
//Turn off receiver voltages. (thats what the TYT firmware does, both receivers are on or off together)
|
|
HAL_GPIO_WritePin(R5_V_SW_GPIO_Port, R5_V_SW_Pin, GPIO_PIN_RESET);
|
|
HAL_GPIO_WritePin(R5_U_SW_GPIO_Port, R5_U_SW_Pin, GPIO_PIN_RESET);
|
|
|
|
//Configure HRC-6000 for transmit
|
|
if (trxGetMode() == RADIO_MODE_ANALOG)
|
|
{
|
|
HRC6000SetFMTx();
|
|
|
|
if (currentRadioDevice->currentBandWidthIs25kHz)
|
|
{
|
|
radioWriteReg2byte(0x30, 0x70, 0x46); // 25 kHz settings // RX on
|
|
}
|
|
else
|
|
{
|
|
radioWriteReg2byte(0x30, 0x60, 0x46); // 12.5 kHz settings // RX on
|
|
}
|
|
|
|
trxSelectVoiceChannel(AT1846_VOICE_CHANNEL_MIC);// For 1750 tone burst
|
|
//trxSelectVoiceChannel(AT1846_VOICE_CHANNEL_NONE);// the MDUV380 does not use the AT1846S for modulation.
|
|
trxSetMicGainFM(nonVolatileSettings.micGainFM);
|
|
}
|
|
else
|
|
{
|
|
HRC6000SetDMR();
|
|
|
|
radioWriteReg2byte(0x30, 0x60, 0xC6); // Digital Tx
|
|
}
|
|
|
|
//Turn on Tx Voltage for the current band.
|
|
HAL_GPIO_WritePin(PA_EN_1_GPIO_Port, PA_EN_1_Pin, GPIO_PIN_SET);
|
|
|
|
if (band == RADIO_BAND_VHF)
|
|
{
|
|
HAL_GPIO_WritePin(PA_SEL_SW_GPIO_Port, PA_SEL_SW_Pin, GPIO_PIN_RESET);
|
|
}
|
|
else
|
|
{
|
|
HAL_GPIO_WritePin(PA_SEL_SW_GPIO_Port, PA_SEL_SW_Pin, GPIO_PIN_SET);
|
|
}
|
|
|
|
//Turn on the power control circuit
|
|
|
|
HAL_GPIO_WritePin(PA_EN_2_GPIO_Port, PA_EN_2_Pin, GPIO_PIN_SET);
|
|
trxIsTransmitting = true;
|
|
}
|
|
|
|
//just enable or disable the RF output . doesn't change back to receive
|
|
void radioFastTx(bool tx)
|
|
{
|
|
if (tx)
|
|
{
|
|
radioWriteReg2byte(0x30, 0x60, 0xC6); // Digital Tx
|
|
|
|
HAL_GPIO_WritePin(PA_EN_1_GPIO_Port, PA_EN_1_Pin, GPIO_PIN_SET);
|
|
HAL_GPIO_WritePin(PA_EN_2_GPIO_Port, PA_EN_2_Pin, GPIO_PIN_SET);
|
|
}
|
|
else
|
|
{
|
|
//Turn off Tx Voltages to prevent transmission.
|
|
|
|
HAL_GPIO_WritePin(PA_EN_1_GPIO_Port, PA_EN_1_Pin, GPIO_PIN_RESET);
|
|
HAL_GPIO_WritePin(PA_EN_2_GPIO_Port, PA_EN_2_Pin, GPIO_PIN_RESET);
|
|
|
|
if (currentRadioDevice->currentBandWidthIs25kHz)
|
|
{
|
|
// 25 kHz settings
|
|
radioWriteReg2byte(0x30, 0x70, 0x26); // RX on
|
|
}
|
|
else
|
|
{
|
|
// 12.5 kHz settings
|
|
radioWriteReg2byte(0x30, 0x60, 0x26); // RX on
|
|
}
|
|
}
|
|
}
|
|
|
|
void radioSetRx(uint8_t band)
|
|
{
|
|
//Turn off the power control circuit
|
|
//HAL_GPIO_WritePin(RF_APC_SW_GPIO_Port, RF_APC_SW_Pin, GPIO_PIN_RESET);
|
|
|
|
//Turn off Tx Voltages to prevent transmission.
|
|
|
|
HAL_GPIO_WritePin(PA_EN_1_GPIO_Port, PA_EN_1_Pin, GPIO_PIN_RESET);
|
|
HAL_GPIO_WritePin(PA_EN_2_GPIO_Port, PA_EN_2_Pin, GPIO_PIN_RESET);
|
|
|
|
//Turn on receiver voltages. (thats what the TYT firmware does, both receivers are on together)
|
|
radioSetRxLNAForDevice(currentRadioDeviceId);
|
|
|
|
trxIsTransmitting = false;
|
|
|
|
if (currentRadioDevice->currentBandWidthIs25kHz)
|
|
{
|
|
// 25 kHz settings
|
|
radioWriteReg2byte(0x30, 0x70, 0x26); // RX on
|
|
}
|
|
else
|
|
{
|
|
// 12.5 kHz settings
|
|
radioWriteReg2byte(0x30, 0x60, 0x26); // RX on
|
|
}
|
|
|
|
if (trxGetMode() == RADIO_MODE_ANALOG)
|
|
{
|
|
HRC6000SetFMRx();
|
|
}
|
|
else
|
|
{
|
|
HRC6000SetDMR();
|
|
}
|
|
}
|
|
|
|
void radioReadRSSIAndNoiseForBand(uint8_t band)
|
|
{
|
|
uint8_t val1, val2;
|
|
|
|
UNUSED_PARAMETER(band);// not band specific on the MDUV380
|
|
|
|
if (rxPowerSavingIsRxOn())
|
|
{
|
|
taskENTER_CRITICAL();
|
|
if (radioReadReg2byte(0x1b, &val1, &val2))
|
|
{
|
|
currentRadioDevice->trxRxSignal = val1;
|
|
currentRadioDevice->trxRxNoise = val2;
|
|
}
|
|
taskEXIT_CRITICAL();
|
|
trxDMRSynchronisedRSSIReadPending = false;
|
|
}
|
|
}
|
|
|
|
#if defined(PLATFORM_MD9600)
|
|
static int getCSSToneIndex(uint16_t tone)
|
|
{
|
|
//the TYT firmware uses a PWM output to directly generate the CTCSS Tone.
|
|
//however the HR-C6000 can also generate tones so we will use that instead
|
|
//this uses a table so we need to convert the CTCSS tone to the Table Index.
|
|
uint8_t HRCToneIndex = 1;
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(HRC_CTCSSTones); i++)
|
|
{
|
|
if (HRC_CTCSSTones[i] == tone)
|
|
{
|
|
HRCToneIndex = i + 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return HRCToneIndex;
|
|
}
|
|
#endif
|
|
|
|
void radioTxCSSOff(void)
|
|
{
|
|
AT1846sSetTxCTCSS(0);
|
|
}
|
|
|
|
void radioTxCTCSOn(uint16_t tone)
|
|
{
|
|
AT1846sSetTxCTCSS(tone);
|
|
}
|
|
|
|
void radioTxDCSOn(uint16_t code, bool inverted)
|
|
{
|
|
#if defined(PLATFORM_MDUV380) || defined(PLATFORM_RT84_DM1701) || defined(PLATFORM_MD2017)
|
|
AT1846sSetTxDCS(code, inverted);
|
|
#elif defined(PLATFORM_MD9600)
|
|
HRC6000SetTxDCS(code, inverted);
|
|
#else
|
|
#error UNSUPPORTED PLATFORM
|
|
#endif
|
|
}
|
|
|
|
void radioRxCSSOff(RadioDevice_t deviceId)
|
|
{
|
|
AT1846sSetRxCSSOff(deviceId);
|
|
}
|
|
|
|
void radioRxCTCSOn(RadioDevice_t deviceId, uint16_t tone)
|
|
{
|
|
AT1846sSetRxCTCSS(deviceId, tone);
|
|
}
|
|
|
|
void radioRxDCSOn(RadioDevice_t deviceId, uint16_t code, bool inverted)
|
|
{
|
|
AT1846sSetRxDCS(deviceId, code, inverted);
|
|
}
|
|
|
|
bool radioCheckCSS(uint16_t tone, CodeplugCSSTypes_t type)
|
|
{
|
|
return AT1846sCheckCSS(tone, type);
|
|
}
|
|
|
|
void radioSetTone1(int tonefreq)
|
|
{
|
|
if(tonefreq > 0)
|
|
{
|
|
trxSelectVoiceChannel(AT1846_VOICE_CHANNEL_TONE1); //configure AT1846S for tone
|
|
HRC6000SetMic(false); //mute the microphone while sending tone.
|
|
}
|
|
else
|
|
{
|
|
trxSelectVoiceChannel(AT1846_VOICE_CHANNEL_MIC); //reset At1846S
|
|
HRC6000SetMic(true); //enable the mic
|
|
}
|
|
AT1846sWriteTone1Reg(tonefreq * 10);
|
|
}
|
|
|
|
void radioSetMicGainFM(uint8_t gain)
|
|
{
|
|
HRC6000SetMicGainFM(gain);
|
|
}
|
|
|
|
void radioAudioAmp(bool on)
|
|
{
|
|
HAL_GPIO_WritePin(AUDIO_AMP_EN_GPIO_Port, AUDIO_AMP_EN_Pin, (on ? GPIO_PIN_SET : GPIO_PIN_RESET)); //Turn on the audio amp.
|
|
HAL_GPIO_WritePin(SPK_MUTE_GPIO_Port, SPK_MUTE_Pin, (on ? GPIO_PIN_RESET : GPIO_PIN_SET)); //Unmute the speaker
|
|
}
|
|
|
|
void radioSetAudioPath(bool fromFM)
|
|
{
|
|
HRC6000SetFmAudio(fromFM);
|
|
}
|
|
|
|
void radioSelectVoiceChannel(uint8_t channel, uint8_t *voiceGainTx, uint16_t *deviation)
|
|
{
|
|
AT1846sSelectVoiceChannel(channel, voiceGainTx, deviation);
|
|
}
|
|
|
|
|