/* * 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; }