720 lines
24 KiB
C
720 lines
24 KiB
C
/*
|
|
* Copyright (C) 2019 Kai Ludwig, DG4KLU
|
|
* Copyright (C) 2019-2025 Roger Clark, VK3KYY / G4KYF
|
|
* Daniel Caujolle-Bert, F1RMB
|
|
*
|
|
*
|
|
* 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 "utils.h"
|
|
#include "functions/calibration.h"
|
|
#include "functions/trx.h"
|
|
|
|
const int MAX_PA_DAC_VALUE = 4095;
|
|
|
|
typedef struct
|
|
{
|
|
//0x00
|
|
uint8_t VoxLevel1; //calibration for Vox Setting 1
|
|
uint8_t VoxLevel10; //calibration for Vox Setting 10
|
|
uint8_t RxLowVoltage; //Exact use unknown
|
|
uint8_t RxHighVoltage; //Exact use unknown
|
|
uint8_t RSSI120; //RSSI Calibration for -120dBm
|
|
uint8_t RSSI70; //RSSI Calibration for -70dBm
|
|
uint8_t UnknownBlock1[2]; //Unknown
|
|
//0x08
|
|
uint8_t Unknown1; //Unknown
|
|
uint8_t UHFOscRefTune; //UHF reference tuning
|
|
uint8_t UnknownBlock2[2]; //Unknown
|
|
uint8_t VHFOscRefTune; //UHF reference tuning
|
|
uint8_t UnknownBlock3[3]; //Unknown
|
|
//0x10
|
|
uint8_t UHFHighPowerCal[9]; //UHF High Power Calibration 9 frequencies
|
|
//0x19
|
|
uint8_t VHFHighPowerCal[5]; //VHF High Power Calibration 5 frequencies
|
|
//0x1E
|
|
uint8_t UnknownBlock4[2]; //Unknown
|
|
//0x20
|
|
uint8_t UHFLowPowerCal[9]; //UHF Low Power Calibration 9 frequencies
|
|
//0x29
|
|
uint8_t VHFLowPowerCal[5]; //VHF Low Power Calibration 5 frequencies
|
|
//0x2E
|
|
uint8_t UnknownBlock5[2]; //Unknown
|
|
//0x30
|
|
uint8_t UHFRxTuning[9]; //UHF Rx Front End Tuning 9 frequencies
|
|
//0x39
|
|
uint8_t VHFRxTuning[5]; //VHF Rx Front End Tuning 5 frequencies
|
|
//0x3E
|
|
uint8_t UnknownBlock6[2]; //Unknown
|
|
//0x40
|
|
uint8_t UHFOpenSquelch9[9]; //UHF Squelch Level 9 Opening 9 frequencies
|
|
//0x49
|
|
uint8_t UnknownBlock7[7]; //Unknown
|
|
//0x50
|
|
uint8_t UHFCloseSquelch9[9]; //UHF Squelch Level 9 Closing 9 frequencies
|
|
//0x59
|
|
uint8_t UnknownBlock8[7]; //Unknown
|
|
//0x60
|
|
uint8_t UHFOpenSquelch1[9]; //UHF Squelch Level 1 Opening 9 frequencies
|
|
//0x69
|
|
uint8_t UnknownBlock9[7]; //Unknown
|
|
//0x70
|
|
uint8_t UHFCloseSquelch1[9]; //UHF Squelch Level 1 Closing 9 frequencies
|
|
//0x79
|
|
uint8_t UnknownBlock10[7]; //Unknown
|
|
//0x80
|
|
uint8_t UnknownBlock11[16]; //Unknown
|
|
//0x90
|
|
uint8_t UHFCTC67[9]; //UHF CTCSS Deviation for 67Hz Tone 9 frequencies
|
|
//0x99
|
|
uint8_t UnknownBlock12[2]; //Unknown
|
|
//0x9B
|
|
uint8_t VHFCTC67[5]; //VHF CTCSS Deviation for 67Hz Tone 5 frequencies
|
|
//0xA0
|
|
uint8_t UHFCTC151[9]; //UHF CTCSS Deviation for 151.4Hz Tone 9 frequencies
|
|
//0xA9
|
|
uint8_t UnknownBlock13[2]; //Unknown
|
|
//0x9B
|
|
uint8_t VHFCTC151[5]; //VHF CTCSS Deviation for 151.4Hz Tone 5 frequencies
|
|
//0xB0
|
|
uint8_t UHFCTC254[9]; //UHF CTCSS Deviation for 254.1Hz Tone 9 frequencies
|
|
//0xB9
|
|
uint8_t UnknownBlock14[2]; //Unknown
|
|
//0xBB
|
|
uint8_t VHFCTC254[5]; //VHF CTCSS Deviation for 254.1Hz Tone 5 frequencies
|
|
//0xC0
|
|
uint8_t UnknownBlock15[16]; //Unknown
|
|
//0xD0
|
|
uint8_t UHFDCS[9]; //UHF DCS Deviation 9 frequencies
|
|
//0xD9
|
|
uint8_t UnknownBlock16[2]; //Unknown
|
|
//0xDB
|
|
uint8_t VHFDCS[5]; //VHF DCS Deviation 5 frequencies
|
|
//0xE0
|
|
uint8_t VHFOpenSquelch9[5]; //VHF Squelch Level 9 Opening 5 frequencies
|
|
uint8_t VHFCloseSquelch9[5]; //VHF Squelch Level 9 Closing 5 frequencies
|
|
uint8_t VHFOpenSquelch1[5]; //VHF Squelch Level 1 Opening 5 frequencies
|
|
uint8_t VHFCloseSquelch1[5]; //VHF Squelch Level 1 Closing 5 frequencies
|
|
//0xF4
|
|
uint8_t UnknownBlock17[12]; //Unknown
|
|
//0x100
|
|
uint8_t VHFCalFreqs[10][4]; // VHF Calibration Frequencies 4 BCD bytes per freq, 5 pairs of freqs Rx and Tx
|
|
//0x128
|
|
uint8_t UnknownBlock18[8]; //Unknown
|
|
//0x130
|
|
uint8_t UHFDMRIGain[9]; //UHF I Gain for DMR 9 Frequencies
|
|
//0x139
|
|
uint8_t VHFDMRIGain[5]; //VHF I Gain for DMR 5 Frequencies
|
|
uint8_t UnknownBlock19[2]; //Unknown
|
|
//0x140
|
|
uint8_t UHFDMRQGain[9]; //UHF Q Gain for DMR 9 Frequencies
|
|
//0x149
|
|
uint8_t VHFDMRQGain[5]; //VHF Q Gain for DMR 5 Frequencies
|
|
uint8_t UnknownBlock20[2]; //Unknown
|
|
//0x150
|
|
uint8_t UnknownBlock21[32]; //Unknown
|
|
//0x170
|
|
uint8_t UHFFMIGain[9]; //UHF I Gain for FM 9 Frequencies
|
|
//0x179
|
|
uint8_t VHFFMIGain[5]; //VHF I Gain for FM 5 Frequencies
|
|
uint8_t UnknownBlock22[2]; //Unknown
|
|
//0x180
|
|
uint8_t UHFFMQGain[9]; //UHF Q Gain for FM 9 Frequencies
|
|
//0x189
|
|
uint8_t VHFFMQGain[5]; //VHF Q Gain for FM 5 Frequencies
|
|
uint8_t UnknownBlock23[2]; //Unknown
|
|
//0x190
|
|
uint8_t UHFMidPowerCal[9]; //UHF Mid Power Calibration 9 frequencies
|
|
//0x199
|
|
uint8_t VHFMidPowerCal[5]; //VHF Mid Power Calibration 5 frequencies
|
|
//0x19E
|
|
uint8_t UnknownBlock24[2]; //Unknown
|
|
//0x1A0
|
|
uint8_t UHFVeryLowPowerCal[9]; //UHF VeryLow Power Calibration 9 frequencies (not used or initialised by official firmware)
|
|
//0x1A9
|
|
uint8_t VHFVeryLowPowerCal[5]; //VHF VeryLow Power Calibration 5 frequencies (not used or initialised by official firmware)
|
|
//0x1AE
|
|
uint8_t UnknownBlock25[2]; //Unknown
|
|
//0x1B0
|
|
uint8_t UHFCalFreqs[18][4]; // UHF Calibration Frequencies 4 BCD bytes per freq, 9 pairs of freqs Rx and Tx
|
|
uint8_t UnknownBlock26[8]; //Unknown
|
|
//0x200
|
|
} CalibrationData_t;
|
|
|
|
#define CALIBRATION_TABLE_LENGTH 0x200 // Calibration table is 512 bytes long
|
|
static __attribute__((section(".ccmram"))) CalibrationData_t calibrationData;
|
|
#define CALIBRATION_TABLE_LOCAL_COPY_ADDRESS 0x10000 //Flash address for local calibration copy.
|
|
|
|
const int MARKER_BYTES_LENGTH = 8; // we will use the 8 bytes of the first UHF calibration frequency as a marker
|
|
const uint8_t MARKER_BYTES[] = {0x00, 0x25, 0x00, 0x40, 0x00, 0x45, 0x01, 0x40}; // 400.02500 400.145
|
|
|
|
void calibrationInit(void)
|
|
{
|
|
calibrationReadLocal(); //first try to read the local copy of the calibration table
|
|
|
|
if(memcmp(MARKER_BYTES, calibrationData.UHFCalFreqs[0], MARKER_BYTES_LENGTH) != 0) //do we have a good local copy?
|
|
{
|
|
calibrationReadFactory(true); //no so copy the factory values
|
|
calibrationSaveLocal(); //to the local copy
|
|
}
|
|
}
|
|
|
|
void calibrationReadLocal(void)
|
|
{
|
|
(void)SPI_Flash_read(CALIBRATION_TABLE_LOCAL_COPY_ADDRESS , (uint8_t *)&calibrationData, CALIBRATION_TABLE_LENGTH);
|
|
}
|
|
|
|
void calibrationSaveLocal(void)
|
|
{
|
|
(void)SPI_Flash_write(CALIBRATION_TABLE_LOCAL_COPY_ADDRESS , (uint8_t *)&calibrationData, CALIBRATION_TABLE_LENGTH);
|
|
}
|
|
|
|
void calibrationReadFactory(bool applyConversion)
|
|
{
|
|
static const float fractionalPowers[2][4] = {
|
|
#if defined(PLATFORM_RT84_DM1701)
|
|
// DM1701 or RT84 which have same RF hardware
|
|
{0.61f, 1.00f, 0.85f, 1.30f},// VHF
|
|
{0.65f, 1.00f, 0.86f, 1.70f},// UHF
|
|
#else
|
|
#if defined(PLATFORM_VARIANT_UV380_PLUS_10W)
|
|
// 10W UV380
|
|
{0.35f, 0.65f, 1.25f, 1.40f},// VHF
|
|
{0.40f, 0.70f, 1.20f, 1.35f},// UHF
|
|
#else
|
|
// 5W UV380
|
|
{0.63f, 1.00f, 1.00f, 1.10f},// VHF
|
|
{0.72f, 1.00f, 1.05f, 1.25f},// UHF
|
|
#endif
|
|
#endif
|
|
};//fractionalPowers
|
|
|
|
(void)SPI_Flash_readSecurityRegisters(0, (uint8_t *)&calibrationData, CALIBRATION_TABLE_LENGTH);
|
|
|
|
memcpy(calibrationData.UHFCalFreqs[0] , MARKER_BYTES , MARKER_BYTES_LENGTH);
|
|
//add the marker bytes just in case they are different in this radio.
|
|
|
|
for(uint8_t freqRangeIndex = 0; freqRangeIndex < 5 ; freqRangeIndex++)
|
|
{
|
|
calibrationData.VHFVeryLowPowerCal[freqRangeIndex] = calibrationData.VHFLowPowerCal[freqRangeIndex] * fractionalPowers[0][0];
|
|
if (applyConversion)
|
|
{
|
|
calibrationData.VHFLowPowerCal[freqRangeIndex] *= fractionalPowers[0][1];
|
|
calibrationData.VHFMidPowerCal[freqRangeIndex] *= fractionalPowers[0][2];
|
|
calibrationData.VHFHighPowerCal[freqRangeIndex] *= fractionalPowers[0][3];
|
|
}
|
|
}
|
|
|
|
for(uint8_t freqRangeIndex = 0; freqRangeIndex < 9; freqRangeIndex++)
|
|
{
|
|
calibrationData.UHFVeryLowPowerCal[freqRangeIndex] = calibrationData.UHFLowPowerCal[freqRangeIndex] * fractionalPowers[1][0];
|
|
|
|
if (applyConversion)
|
|
{
|
|
calibrationData.UHFLowPowerCal[freqRangeIndex] *= fractionalPowers[1][1];
|
|
calibrationData.UHFMidPowerCal[freqRangeIndex] *= fractionalPowers[1][2];
|
|
calibrationData.UHFHighPowerCal[freqRangeIndex] *= fractionalPowers[1][3];
|
|
}
|
|
}
|
|
}
|
|
|
|
//look up the tuning voltage and interpolate between points (not used on MDuV380 but retained for MD-9600)
|
|
uint16_t calibrationGetRxTuneForFrequency(int freq)
|
|
{
|
|
int index;
|
|
int offset;
|
|
int limit;
|
|
int upper;
|
|
int lower;
|
|
|
|
if (freq > 30000000)
|
|
{
|
|
index = (freq - RADIO_HARDWARE_FREQUENCY_BANDS[RADIO_BAND_UHF].calIQTableMinFreq) / 1000000;
|
|
offset= (freq - RADIO_HARDWARE_FREQUENCY_BANDS[RADIO_BAND_UHF].calIQTableMinFreq) % 1000000;
|
|
limit = 8;
|
|
index = CLAMP(index, 0, limit);
|
|
lower = calibrationData.UHFRxTuning[index] << 4; //get the lower lookup point and scale it to 12 bits
|
|
|
|
if (index < limit)
|
|
{
|
|
upper = calibrationData.UHFRxTuning[index + 1] << 4; //get the higher lookup point and scale it to 12 bits
|
|
}
|
|
else
|
|
{
|
|
upper = lower + (lower - (calibrationData.UHFRxTuning[index - 1] << 4)); //extrapolate outside top point using the same slope
|
|
}
|
|
|
|
return CLAMP(interpolate(lower, upper, offset, 1000000), 0, 4095);
|
|
}
|
|
|
|
index = (freq - RADIO_HARDWARE_FREQUENCY_BANDS[RADIO_BAND_VHF].calIQTableMinFreq) / 950000;
|
|
offset= (freq - RADIO_HARDWARE_FREQUENCY_BANDS[RADIO_BAND_VHF].calIQTableMinFreq) % 950000;
|
|
limit = 4;
|
|
index = CLAMP(index, 0, limit);
|
|
lower = calibrationData.VHFRxTuning[index] << 4; //get the lower lookup point and scale it to 12 bits
|
|
|
|
if (index < limit)
|
|
{
|
|
upper = calibrationData.VHFRxTuning[index + 1] << 4; //get the higher lookup point and scale it to 12 bits
|
|
}
|
|
else
|
|
{
|
|
upper = lower + (lower - (calibrationData.VHFRxTuning[index - 1] << 4)); //extrapolate outside top point using the same slope
|
|
}
|
|
|
|
return CLAMP(interpolate(lower, upper, offset, 950000), 0, 4095);
|
|
}
|
|
|
|
uint8_t calibrationGetAnalogIGainForFrequency(int freq)
|
|
{
|
|
int index;
|
|
int offset;
|
|
int limit;
|
|
int upper;
|
|
int lower;
|
|
|
|
if (freq > 30000000)
|
|
{
|
|
index = (freq - RADIO_HARDWARE_FREQUENCY_BANDS[RADIO_BAND_UHF].calIQTableMinFreq) / 1000000;
|
|
offset = (freq - RADIO_HARDWARE_FREQUENCY_BANDS[RADIO_BAND_UHF].calIQTableMinFreq) % 1000000;
|
|
limit = 8;
|
|
index = CLAMP(index, 0, limit);
|
|
lower = calibrationData.UHFFMIGain[index]; //get the lower lookup point and scale it to 12 bits
|
|
|
|
if (index < limit)
|
|
{
|
|
upper = calibrationData.UHFFMIGain[index + 1]; //get the higher lookup point and scale it to 12 bits
|
|
}
|
|
else
|
|
{
|
|
upper = lower + (lower - (calibrationData.UHFFMIGain[index - 1])); //extrapolate outside top point using the same slope
|
|
}
|
|
|
|
return CLAMP(interpolate(lower, upper, offset, 1000000), 0, 255);
|
|
}
|
|
|
|
index = (freq - RADIO_HARDWARE_FREQUENCY_BANDS[RADIO_BAND_VHF].calIQTableMinFreq) / 950000;
|
|
offset = (freq - RADIO_HARDWARE_FREQUENCY_BANDS[RADIO_BAND_VHF].calIQTableMinFreq) % 950000;
|
|
limit = 4;
|
|
index = CLAMP(index, 0, limit);
|
|
lower = calibrationData.VHFFMIGain[index]; //get the lower lookup point and scale it to 12 bits
|
|
|
|
if (index < limit)
|
|
{
|
|
upper = calibrationData.VHFFMIGain[index + 1]; //get the higher lookup point and scale it to 12 bits
|
|
}
|
|
else
|
|
{
|
|
upper = lower + (lower - (calibrationData.VHFFMIGain[index - 1])); //extrapolate outside top point using the same slope
|
|
}
|
|
|
|
return CLAMP(interpolate(lower, upper, offset, 950000), 0, 255);
|
|
}
|
|
|
|
uint8_t calibrationGetAnalogQGainForFrequency(int freq)
|
|
{
|
|
int index;
|
|
int offset;
|
|
int limit;
|
|
int upper;
|
|
int lower;
|
|
|
|
if (freq > 30000000)
|
|
{
|
|
index = (freq - RADIO_HARDWARE_FREQUENCY_BANDS[RADIO_BAND_UHF].calIQTableMinFreq) / 1000000;
|
|
offset = (freq - RADIO_HARDWARE_FREQUENCY_BANDS[RADIO_BAND_UHF].calIQTableMinFreq) % 1000000;
|
|
limit = 8;
|
|
index = CLAMP(index, 0, limit);
|
|
lower = calibrationData.UHFFMQGain[index]; //get the lower lookup point and scale it to 12 bits
|
|
|
|
if (index < limit)
|
|
{
|
|
upper = calibrationData.UHFFMQGain[index + 1]; //get the higher lookup point and scale it to 12 bits
|
|
}
|
|
else
|
|
{
|
|
upper = lower + (lower - (calibrationData.UHFFMQGain[index - 1])); //extrapolate outside top point using the same slope
|
|
}
|
|
|
|
return CLAMP(interpolate(lower, upper, offset, 1000000), 0, 255);
|
|
}
|
|
|
|
index = (freq - RADIO_HARDWARE_FREQUENCY_BANDS[RADIO_BAND_VHF].calIQTableMinFreq) / 950000;
|
|
offset = (freq - RADIO_HARDWARE_FREQUENCY_BANDS[RADIO_BAND_VHF].calIQTableMinFreq) % 950000;
|
|
limit = 4;
|
|
index = CLAMP(index, 0, limit);
|
|
lower = calibrationData.VHFFMQGain[index]; //get the lower lookup point and scale it to 12 bits
|
|
|
|
if (index < limit)
|
|
{
|
|
upper = calibrationData.VHFFMQGain[index + 1]; //get the higher lookup point and scale it to 12 bits
|
|
}
|
|
else
|
|
{
|
|
upper = lower + (lower - (calibrationData.VHFFMQGain[index - 1])); //extrapolate outside top point using the same slope
|
|
}
|
|
|
|
return CLAMP(interpolate(lower, upper, offset, 950000), 0, 255);
|
|
}
|
|
|
|
uint8_t calibrationGetDigitalIGainForFrequency(int freq)
|
|
{
|
|
int index;
|
|
int offset;
|
|
int limit;
|
|
int upper;
|
|
int lower;
|
|
|
|
if (freq > 30000000)
|
|
{
|
|
index = (freq - RADIO_HARDWARE_FREQUENCY_BANDS[RADIO_BAND_UHF].calIQTableMinFreq) / 1000000;
|
|
offset = (freq - RADIO_HARDWARE_FREQUENCY_BANDS[RADIO_BAND_UHF].calIQTableMinFreq) % 1000000;
|
|
limit = 8;
|
|
index = CLAMP(index, 0, limit);
|
|
lower = calibrationData.UHFDMRIGain[index]; //get the lower lookup point and scale it to 12 bits
|
|
|
|
if (index < limit)
|
|
{
|
|
upper = calibrationData.UHFDMRIGain[index + 1]; //get the higher lookup point and scale it to 12 bits
|
|
}
|
|
else
|
|
{
|
|
upper = lower + (lower - (calibrationData.UHFDMRIGain[index - 1])); //extrapolate outside top point using the same slope
|
|
}
|
|
|
|
return CLAMP(interpolate(lower, upper, offset, 1000000), 0, 255);
|
|
}
|
|
|
|
index = (freq - RADIO_HARDWARE_FREQUENCY_BANDS[RADIO_BAND_VHF].calIQTableMinFreq) / 950000;
|
|
offset = (freq - RADIO_HARDWARE_FREQUENCY_BANDS[RADIO_BAND_VHF].calIQTableMinFreq) % 950000;
|
|
limit = 4;
|
|
index = CLAMP(index, 0, limit);
|
|
lower = calibrationData.VHFDMRIGain[index]; //get the lower lookup point and scale it to 12 bits
|
|
|
|
if (index < limit)
|
|
{
|
|
upper = calibrationData.VHFDMRIGain[index + 1]; //get the higher lookup point and scale it to 12 bits
|
|
}
|
|
else
|
|
{
|
|
upper = lower + (lower - (calibrationData.VHFDMRIGain[index - 1])); //extrapolate outside top point using the same slope
|
|
}
|
|
|
|
return CLAMP(interpolate(lower, upper, offset, 950000), 0, 255);
|
|
}
|
|
|
|
uint8_t calibrationGetDigitalQGainForFrequency(int freq)
|
|
{
|
|
int index;
|
|
int offset;
|
|
int limit;
|
|
int upper;
|
|
int lower;
|
|
|
|
if (freq > 30000000)
|
|
{
|
|
index = (freq - RADIO_HARDWARE_FREQUENCY_BANDS[RADIO_BAND_UHF].calIQTableMinFreq) / 1000000;
|
|
offset = (freq - RADIO_HARDWARE_FREQUENCY_BANDS[RADIO_BAND_UHF].calIQTableMinFreq) % 1000000;
|
|
limit = 8;
|
|
index = CLAMP(index, 0, limit);
|
|
lower = calibrationData.UHFDMRQGain[index]; //get the lower lookup point and scale it to 12 bits
|
|
|
|
if (index < limit)
|
|
{
|
|
upper = calibrationData.UHFDMRQGain[index + 1]; //get the higher lookup point and scale it to 12 bits
|
|
}
|
|
else
|
|
{
|
|
upper = lower + (lower - (calibrationData.UHFDMRQGain[index - 1])); //extrapolate outside top point using the same slope
|
|
}
|
|
|
|
return CLAMP(interpolate(lower, upper, offset, 1000000), 0, 255);
|
|
}
|
|
|
|
index = (freq - RADIO_HARDWARE_FREQUENCY_BANDS[RADIO_BAND_VHF].calIQTableMinFreq) / 950000;
|
|
offset = (freq - RADIO_HARDWARE_FREQUENCY_BANDS[RADIO_BAND_VHF].calIQTableMinFreq) % 950000;
|
|
limit = 4;
|
|
index = CLAMP(index, 0, limit);
|
|
lower = calibrationData.VHFDMRQGain[index]; //get the lower lookup point and scale it to 12 bits
|
|
|
|
if (index < limit)
|
|
{
|
|
upper = calibrationData.VHFDMRQGain[index + 1]; //get the higher lookup point and scale it to 12 bits
|
|
}
|
|
else
|
|
{
|
|
upper = lower + (lower - (calibrationData.VHFDMRQGain[index - 1])); //extrapolate outside top point using the same slope
|
|
}
|
|
|
|
return CLAMP(interpolate(lower, upper, offset, 950000), 0, 255);
|
|
}
|
|
|
|
int interpolate(int lowerpoint, int upperpoint, int numerator, int denominator)
|
|
{
|
|
return lowerpoint + (((upperpoint - lowerpoint) * numerator) / denominator);
|
|
}
|
|
|
|
void calibrationGetPowerForFrequency(int freq, calibrationPowerValues_t *powerSettings)
|
|
{
|
|
int index;
|
|
int offset;
|
|
int limit;
|
|
int upper;
|
|
int lower;
|
|
|
|
if (freq > 30000000)
|
|
{
|
|
index = (freq - RADIO_HARDWARE_FREQUENCY_BANDS[RADIO_BAND_UHF].calPowerTableMinFreq) / 1000000;
|
|
offset = (freq - RADIO_HARDWARE_FREQUENCY_BANDS[RADIO_BAND_UHF].calPowerTableMinFreq) % 1000000;
|
|
limit = 8;
|
|
index = CLAMP(index, 0, limit);
|
|
lower = calibrationData.UHFLowPowerCal[index] << 4; // get the Lower lookup point and scale it to 12 bits
|
|
|
|
if (index < limit)
|
|
{
|
|
upper = calibrationData.UHFLowPowerCal[index + 1] << 4; //get the higher lookup point and scale it to 12 bits
|
|
}
|
|
else
|
|
{
|
|
upper = lower + (lower - (calibrationData.UHFLowPowerCal[index - 1] << 4)); //extrapolate outside top point using the same slope
|
|
}
|
|
|
|
powerSettings->lowPower = CLAMP(interpolate(lower, upper, offset, 1000000), 0, 4096);
|
|
lower = calibrationData.UHFVeryLowPowerCal[index] << 4; // get the Lower lookup point and scale it to 12 bits
|
|
|
|
if (index < limit)
|
|
{
|
|
upper = calibrationData.UHFVeryLowPowerCal[index + 1] << 4; //get the higher lookup point and scale it to 12 bits
|
|
}
|
|
else
|
|
{
|
|
upper = lower + (lower - (calibrationData.UHFVeryLowPowerCal[index - 1] << 4)); //extrapolate outside top point using the same slope
|
|
}
|
|
|
|
powerSettings->veryLowPower = CLAMP(interpolate(lower, upper, offset, 1000000), 0, 4096);
|
|
lower = calibrationData.UHFMidPowerCal[index] << 4; // get the Lower lookup point and scale it to 12 bits
|
|
|
|
if (index < limit)
|
|
{
|
|
upper = calibrationData.UHFMidPowerCal[index + 1] << 4; //get the higher lookup point and scale it to 12 bits
|
|
}
|
|
else
|
|
{
|
|
upper = lower + (lower - (calibrationData.UHFMidPowerCal[index - 1] << 4)); //extrapolate outside top point using the same slope
|
|
}
|
|
|
|
powerSettings->midPower = CLAMP(interpolate(lower, upper, offset, 1000000), 0, 4096);
|
|
lower = calibrationData.UHFHighPowerCal[index] << 4; // get the Lower lookup point and scale it to 12 bits
|
|
|
|
if (index < limit)
|
|
{
|
|
upper = calibrationData.UHFHighPowerCal[index + 1] << 4; //get the higher lookup point and scale it to 12 bits
|
|
}
|
|
else
|
|
{
|
|
upper = lower + (lower - (calibrationData.UHFHighPowerCal[index - 1] << 4)); //extrapolate outside top point using the same slope
|
|
}
|
|
|
|
powerSettings->highPower = CLAMP(interpolate(lower, upper, offset, 1000000), 0, 4096);
|
|
|
|
return;
|
|
}
|
|
|
|
index = (freq - RADIO_HARDWARE_FREQUENCY_BANDS[RADIO_BAND_VHF].calPowerTableMinFreq) / 1000000;
|
|
offset = (freq - RADIO_HARDWARE_FREQUENCY_BANDS[RADIO_BAND_VHF].calPowerTableMinFreq) % 1000000;
|
|
limit = 4;
|
|
index = CLAMP(index, 0, limit);
|
|
lower = calibrationData.VHFLowPowerCal[index] << 4; // get the Lower lookup point and scale it to 12 bits
|
|
|
|
if (index < limit)
|
|
{
|
|
upper = calibrationData.VHFLowPowerCal[index + 1] << 4; //get the higher lookup point and scale it to 12 bits
|
|
}
|
|
else
|
|
{
|
|
upper = lower + (lower - (calibrationData.VHFLowPowerCal[index - 1] << 4)); //extrapolate outside top point using the same slope
|
|
}
|
|
|
|
powerSettings->lowPower = CLAMP(interpolate(lower, upper, offset, 1000000), 0, 4096);
|
|
lower = calibrationData.VHFVeryLowPowerCal[index] << 4; // get the Lower lookup point and scale it to 12 bits
|
|
|
|
if (index < limit)
|
|
{
|
|
upper = calibrationData.VHFVeryLowPowerCal[index + 1] << 4; //get the higher lookup point and scale it to 12 bits
|
|
}
|
|
else
|
|
{
|
|
upper = lower + (lower - (calibrationData.VHFVeryLowPowerCal[index - 1] << 4)); //extrapolate outside top point using the same slope
|
|
}
|
|
|
|
powerSettings->veryLowPower = CLAMP(interpolate(lower, upper, offset, 1000000), 0, 4096);
|
|
lower = calibrationData.VHFMidPowerCal[index] << 4; // get the Lower lookup point and scale it to 12 bits
|
|
|
|
if (index < limit)
|
|
{
|
|
upper = calibrationData.VHFMidPowerCal[index + 1] << 4; //get the higher lookup point and scale it to 12 bits
|
|
}
|
|
else
|
|
{
|
|
upper = lower + (lower - (calibrationData.VHFMidPowerCal[index - 1] << 4)); //extrapolate outside top point using the same slope
|
|
}
|
|
|
|
powerSettings->midPower = CLAMP(interpolate(lower, upper, offset, 1000000), 0, 4096);
|
|
lower = calibrationData.VHFHighPowerCal[index] << 4; // get the Lower lookup point and scale it to 12 bits
|
|
|
|
if (index < limit)
|
|
{
|
|
upper = calibrationData.VHFHighPowerCal[index + 1] << 4; //get the higher lookup point and scale it to 12 bits
|
|
}
|
|
else
|
|
{
|
|
upper = lower + (lower - (calibrationData.VHFHighPowerCal[index - 1] << 4)); //extrapolate outside top point using the same slope
|
|
}
|
|
|
|
powerSettings->highPower = CLAMP(interpolate(lower, upper, offset, 1000000), 0, 4096);
|
|
}
|
|
|
|
int8_t calibrationGetMod2Offset(int band)
|
|
{
|
|
return (int8_t)(((band == RADIO_BAND_VHF) ? calibrationData.VHFOscRefTune : calibrationData.UHFOscRefTune) - 128);
|
|
}
|
|
|
|
void calibrationSetMod2Offset(int band, int8_t value)
|
|
{
|
|
if (band == RADIO_BAND_VHF)
|
|
{
|
|
calibrationData.VHFOscRefTune = (int)value + 128;
|
|
}
|
|
else
|
|
{
|
|
calibrationData.UHFOscRefTune = (int)value + 128;
|
|
}
|
|
}
|
|
|
|
//(Not Used)
|
|
bool calibrationGetRSSIMeterParams(calibrationRSSIMeter_t *rssiMeterValues)
|
|
{
|
|
rssiMeterValues->minVal = calibrationData.RSSI120;
|
|
rssiMeterValues->rangeVal = calibrationData.RSSI70;
|
|
|
|
return true;
|
|
}
|
|
|
|
uint8_t calibrationGetVHFOscTune(void)
|
|
{
|
|
return calibrationData.VHFOscRefTune;
|
|
}
|
|
|
|
void calibrationPutVHFOscTune(uint8_t val)
|
|
{
|
|
calibrationData.VHFOscRefTune = val;
|
|
}
|
|
|
|
uint8_t calibrationGetPower(int freqindex, int powerindex)
|
|
{
|
|
|
|
if (freqindex < 5) //VHF calibration values
|
|
{
|
|
switch(powerindex)
|
|
{
|
|
case 0:
|
|
return calibrationData.VHFVeryLowPowerCal[freqindex];
|
|
break;
|
|
case 1:
|
|
return calibrationData.VHFLowPowerCal[freqindex];
|
|
break;
|
|
case 2:
|
|
return calibrationData.VHFMidPowerCal[freqindex];
|
|
break;
|
|
case 3:
|
|
return calibrationData.VHFHighPowerCal[freqindex];
|
|
break;
|
|
}
|
|
}
|
|
else //UHF calibration values
|
|
{
|
|
switch(powerindex)
|
|
{
|
|
case 0:
|
|
return calibrationData.UHFVeryLowPowerCal[freqindex - 5];
|
|
break;
|
|
case 1:
|
|
return calibrationData.UHFLowPowerCal[freqindex - 5];
|
|
break;
|
|
case 2:
|
|
return calibrationData.UHFMidPowerCal[freqindex - 5];
|
|
break;
|
|
case 3:
|
|
return calibrationData.UHFHighPowerCal[freqindex - 5];
|
|
break;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void calibrationPutPower(int freqindex, int powerindex, uint8_t val)
|
|
{
|
|
if (freqindex < 5) //VHF calibration values
|
|
{
|
|
switch(powerindex)
|
|
{
|
|
case 0:
|
|
calibrationData.VHFVeryLowPowerCal[freqindex] = val;
|
|
break;
|
|
case 1:
|
|
calibrationData.VHFLowPowerCal[freqindex] = val;
|
|
break;
|
|
case 2:
|
|
calibrationData.VHFMidPowerCal[freqindex] = val;
|
|
break;
|
|
case 3:
|
|
calibrationData.VHFHighPowerCal[freqindex] = val;
|
|
break;
|
|
}
|
|
}
|
|
else //UHF calibration values
|
|
{
|
|
switch(powerindex)
|
|
{
|
|
case 0:
|
|
calibrationData.UHFVeryLowPowerCal[freqindex - 5] = val;
|
|
break;
|
|
case 1:
|
|
calibrationData.UHFLowPowerCal[freqindex - 5] = val;
|
|
break;
|
|
case 2:
|
|
calibrationData.UHFMidPowerCal[freqindex - 5] = val;
|
|
break;
|
|
case 3:
|
|
calibrationData.UHFHighPowerCal[freqindex - 5] = val;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
uint8_t *calibrationGetLocalDataPointer(void)
|
|
{
|
|
return (uint8_t *)&calibrationData;
|
|
}
|