diff --git a/meson.build b/meson.build index 76da2a56..0b0ab1dd 100644 --- a/meson.build +++ b/meson.build @@ -265,7 +265,7 @@ dm1801_src = src + mk22fn512_src + ['platform/targets/DM-1801/platform.c', 'platform/drivers/ADC/ADC0_GDx.c', 'platform/drivers/baseband/rtx_GDx.c', 'platform/drivers/baseband/AT1846S.c', - 'platform/drivers/baseband/HR-C6000.c', + 'platform/drivers/baseband/HR_C6000.c', 'platform/drivers/baseband/interfaces_GDx.c'] dm1801_inc = inc + mk22fn512_inc + ['platform/targets/DM-1801'] @@ -428,7 +428,7 @@ targets = [ 'flashable': true, 'wrap': 'UV3X0', 'load_addr': '0x0800C000'}, - + {'name': 'mduv380g', 'opts': mduv380g_opts, 'flashable': true, @@ -446,7 +446,7 @@ targets = [ 'flashable': true, 'wrap': 'UV3X0', 'load_addr': '0x0800C000'}, - + {'name': 'md9600', 'opts': md9600_opts, 'flashable': true, diff --git a/platform/drivers/baseband/rtx_GDx.c b/platform/drivers/baseband/rtx_GDx.c index 1587485d..e47e9688 100644 --- a/platform/drivers/baseband/rtx_GDx.c +++ b/platform/drivers/baseband/rtx_GDx.c @@ -18,20 +18,212 @@ * along with this program; if not, see * ***************************************************************************/ +#include +#include +#include +#include +#include #include #include -#include #include #include #include -#include -#include +#include "HR_C6000.h" +#include "AT1846S.h" OS_MUTEX *cfgMutex; /* Mutex for incoming config messages */ OS_Q cfgMailbox; /* Queue for incoming config messages */ +const gdxCalibration_t *calData; /* Pointer to calibration data */ + rtxStatus_t rtxStatus; /* RTX driver status */ +/* + * Helper functions to reduce code mess. They all access 'rtxStatus' + * internally. + */ + +int8_t _getBandFromFrequency(freq_t freq) +{ + if((freq >= FREQ_LIMIT_VHF_LO) && (freq <= FREQ_LIMIT_VHF_HI)) return 0; + if((freq >= FREQ_LIMIT_UHF_LO) && (freq <= FREQ_LIMIT_UHF_HI)) return 1; + return -1; +} + +void _setBandwidth() +{ + /* Override bandwidth configuration for digital modes */ + uint8_t bandwidth = BW_12_5; + if(rtxStatus.opMode == FM) bandwidth = rtxStatus.bandwidth; + + switch(bandwidth) + { + case BW_12_5: + AT1846S_setBandwidth(AT1846S_BW_12P5); + break; + + case BW_20: + case BW_25: + AT1846S_setBandwidth(AT1846S_BW_25); + break; + + default: + break; + } +} + +void _setOpMode() +{ + switch(rtxStatus.opMode) + { + case FM: + gpio_setPin(RX_AUDIO_MUX); /* Audio out to amplifier */ + gpio_clearPin(TX_AUDIO_MUX); /* Audio in to microphone */ + AT1846S_setOpMode(AT1846S_OP_FM); + break; + + case DMR: + gpio_clearPin(RX_AUDIO_MUX); /* Audio out to HR_C6000 */ + gpio_setPin(TX_AUDIO_MUX); /* Audio in from HR_C6000 */ + AT1846S_setOpMode(AT1846S_OP_FM); + break; + + default: + break; + } +} + +void _setVcoFrequency() +{ + freq_t freq = rtxStatus.rxFrequency; + if(rtxStatus.opStatus == TX) freq = rtxStatus.txFrequency; + AT1846S_setFrequency(freq); +} + +void _enableTxStage() +{ + if(rtxStatus.txDisable == 1) return; + + gpio_clearPin(VHF_LNA_EN); + gpio_clearPin(UHF_LNA_EN); + gpio_clearPin(VHF_PA_EN); + gpio_clearPin(UHF_PA_EN); + + int8_t band = _getBandFromFrequency(rtxStatus.txFrequency); + if(band < 0) return; + + /* + * Set transmit power. Initial setting is 1W, overridden to 5W if tx power + * is greater than 1W. + * TODO: increase granularity + */ +// const uint8_t *paramPtr = calData->txLowPower; +// if(rtxStatus.txPower > 1.0f) paramPtr = calData->txHighPower; +// uint8_t apc = interpCalParameter(rtxStatus.txFrequency, calData->txFreq, +// paramPtr, 9); +// DAC->DHR12L1 = apc * 0xFF; + + if(band == 0) + { + gpio_setPin(VHF_PA_EN); + } + else + { + gpio_setPin(UHF_PA_EN); + } + + rtxStatus.opStatus = TX; + _setVcoFrequency(); + AT1846S_setFuncMode(AT1846S_TX); +} + +void _enableRxStage() +{ + gpio_clearPin(VHF_LNA_EN); + gpio_clearPin(UHF_LNA_EN); + gpio_clearPin(VHF_PA_EN); + gpio_clearPin(UHF_PA_EN); + + int8_t band = _getBandFromFrequency(rtxStatus.rxFrequency); + if(band < 0) return; + + if(band == 0) + { + gpio_setPin(VHF_LNA_EN); + } + else + { + gpio_setPin(UHF_LNA_EN); + } + + rtxStatus.opStatus = RX; + _setVcoFrequency(); + AT1846S_setFuncMode(AT1846S_RX); +} + +void _disableRtxStages() +{ + gpio_clearPin(VHF_LNA_EN); + gpio_clearPin(UHF_LNA_EN); + gpio_clearPin(VHF_PA_EN); + gpio_clearPin(UHF_PA_EN); + AT1846S_setFuncMode(AT1846S_OFF); + rtxStatus.opStatus = OFF; +} + +void _updateTuningParams() +{ + int8_t band = _getBandFromFrequency(rtxStatus.rxFrequency); + if(band < 0) return; + + const bandCalData_t *cal = &(calData->data[band]); + + AT1846S_setPgaGain(cal->PGA_gain); + AT1846S_setMicGain(cal->analogMicGain); + AT1846S_setTxDeviation(cal->txDev_tone); + AT1846S_setAgcGain(cal->rxAGCgain); + AT1846S_setRxAudioGain(cal->rxAudioGainWideband, cal->rxAudioGainNarrowband); + AT1846S_setPaDrive(cal->PA_drv); + + C6000_setDacRange(cal->dacDataRange); + C6000_setMod2Bias(cal->mod2Offset); + C6000_setModOffset(cal->mod1Bias); + + uint8_t mod1Amp = 0; + uint8_t sqlTresh = 0; + if(band == 0) + { + /* VHF band */ + mod1Amp = interpCalParameter(rtxStatus.txFrequency, calData->vhfCalPoints, + cal->mod1Amplitude, 8); + + sqlTresh = interpCalParameter(rtxStatus.rxFrequency, calData->vhfCalPoints, + cal->analogSqlThresh, 8); + } + else + { + /* UHF band */ + mod1Amp = interpCalParameter(rtxStatus.txFrequency, calData->uhfMod1CalPoints, + cal->mod1Amplitude, 8); + + sqlTresh = interpCalParameter(rtxStatus.rxFrequency, calData->uhfMod1CalPoints, + cal->analogSqlThresh, 8); + } + + C6000_setMod1Amplitude(mod1Amp); + AT1846S_setAnalogSqlThresh(sqlTresh); +} + +void _setCTCSS() +{ + /* TODO */ +} + +void _updateSqlThresholds() +{ + /* TODO */ +} + void rtx_init(OS_MUTEX *m) { /* Initialise mutex for configuration access */ @@ -44,6 +236,41 @@ void rtx_init(OS_MUTEX *m) (OS_MSG_QTY) 1, (OS_ERR *) &err); + /* + * Configure RTX GPIOs + */ + gpio_setMode(VHF_LNA_EN, OUTPUT); + gpio_setMode(UHF_LNA_EN, OUTPUT); + gpio_setMode(VHF_PA_EN, OUTPUT); + gpio_setMode(UHF_PA_EN, OUTPUT); + + gpio_clearPin(VHF_LNA_EN); /* Turn VHF LNA off */ + gpio_clearPin(UHF_LNA_EN); /* Turn UHF LNA off */ + gpio_clearPin(VHF_PA_EN); /* Turn VHF PA off */ + gpio_clearPin(UHF_PA_EN); /* Turn UHF PA off */ + + /* + * Configure audio control GPIOs + */ + gpio_setMode(AUDIO_AMP_EN, OUTPUT); + gpio_setMode(RX_AUDIO_MUX, OUTPUT); + gpio_setMode(TX_AUDIO_MUX, OUTPUT); + + gpio_clearPin(AUDIO_AMP_EN); + gpio_clearPin(RX_AUDIO_MUX); + gpio_clearPin(TX_AUDIO_MUX); + + /* + * Load calibration data + */ + calData = ((const gdxCalibration_t *) platform_getCalibrationData()); + + /* + * Enable and configure both AT1846S and HR_C6000 + */ + AT1846S_init(); + C6000_init(); + /* * Default initialisation for rtx status */ @@ -55,12 +282,17 @@ void rtx_init(OS_MUTEX *m) rtxStatus.txFrequency = 430000000; rtxStatus.txPower = 0.0f; rtxStatus.sqlLevel = 1; + rtxStatus.rxToneEn = 0; rtxStatus.rxTone = 0; + rtxStatus.txToneEn = 0; rtxStatus.txTone = 0; } void rtx_terminate() { + _disableRtxStages(); + gpio_clearPin(AUDIO_AMP_EN); + C6000_terminate(); } void rtx_configure(const rtxStatus_t *cfg) @@ -119,13 +351,58 @@ void rtx_taskFunc() /* Done, release mutex */ OSMutexPost(cfgMutex, OS_OPT_POST_NONE, &err); + + /* Update HW configuration */ + _setOpMode(); + _setBandwidth(); + _updateTuningParams(); + _setCTCSS(); + _updateSqlThresholds(); + _setVcoFrequency(); + + /* TODO: temporarily force to RX mode if rtx is off. */ + if(rtxStatus.opStatus == OFF) _enableRxStage(); + } + } + + if(rtxStatus.opStatus == RX) + { + float sqlLevel = (rtx_getRssi() + 127.0f)/6.0f; + + float sqlThresh = 7.0f; + if(rtxStatus.sqlLevel > 0) sqlThresh = 3.0f; + + if((gpio_readPin(AUDIO_AMP_EN) == 0) && (sqlLevel > (sqlThresh + 0.1f))) + { + gpio_setPin(AUDIO_AMP_EN); + platform_ledOn(GREEN); } - // Do nothing since this is a stub + if((gpio_readPin(AUDIO_AMP_EN) == 1) && (sqlLevel < sqlThresh)) + { + gpio_clearPin(AUDIO_AMP_EN); + platform_ledOff(GREEN); + } } + +// if(platform_getPttStatus() && (rtxStatus.opStatus != TX)) +// { +// _disableRtxStages(); +// _enableTxStage(); +// platform_ledOn(RED); +// } +// +// if(!platform_getPttStatus() && (rtxStatus.opStatus == TX)) +// { +// _disableRtxStages(); +// _enableRxStage(); +// platform_ledOff(RED); +// } } float rtx_getRssi() { - return 0.0; + uint16_t val = AT1846S_readRSSI(); + int8_t rssi = -151 + (val >> 8); + return ((float) rssi); } diff --git a/platform/targets/DM-1801/platform.c b/platform/targets/DM-1801/platform.c index 0cf0d3b7..7db38030 100644 --- a/platform/targets/DM-1801/platform.c +++ b/platform/targets/DM-1801/platform.c @@ -19,8 +19,10 @@ ***************************************************************************/ #include -#include +#include #include +#include +#include #include #include #include "hwconfig.h" @@ -29,6 +31,8 @@ OS_MUTEX adc_mutex; OS_ERR e; +gdxCalibration_t calibration; + void platform_init() { /* Configure GPIOs */ @@ -70,6 +74,12 @@ void platform_init() gpio_setAlternateFunction(I2C_SDA, 3); gpio_setAlternateFunction(I2C_SCL, 3); i2c0_init(); + + /* + * Initialise non volatile memory manager and load calibration data. + */ + nvm_init(); + nvm_readCalibData(&calibration); } void platform_terminate() @@ -169,3 +179,8 @@ void platform_setBacklightLevel(uint8_t level) { FTM0->CONTROLS[3].CnV = level; } + +const void *platform_getCalibrationData() +{ + return ((const void *) &calibration); +}