/* 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 // NULL #include "audio.h" #include "bk4819.h" #include "bsp/dp32g030/gpio.h" #include "bsp/dp32g030/portcon.h" #include "driver/gpio.h" #include "driver/system.h" #include "driver/systick.h" #ifndef ARRAY_SIZE #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) #endif static const uint16_t FSK_RogerTable[7] = {0xF1A2, 0x7446, 0x61A4, 0x6544, 0x4E8A, 0xE044, 0xEA84}; static const uint8_t DTMF_TONE1_GAIN = 65; static const uint8_t DTMF_TONE2_GAIN = 93; static uint16_t gBK4819_GpioOutState; bool gRxIdleMode; __inline uint16_t scale_freq(const uint16_t freq) { // return (((uint32_t)freq * 1032444u) + 50000u) / 100000u; // with rounding return (((uint32_t)freq * 1353245u) + (1u << 16)) >> 17; // with rounding } void BK4819_Init(void) { GPIO_SetBit(&GPIOC->DATA, GPIOC_PIN_BK4819_SCN); GPIO_SetBit(&GPIOC->DATA, GPIOC_PIN_BK4819_SCL); GPIO_SetBit(&GPIOC->DATA, GPIOC_PIN_BK4819_SDA); BK4819_WriteRegister(BK4819_REG_00, 0x8000); BK4819_WriteRegister(BK4819_REG_00, 0x0000); BK4819_WriteRegister(BK4819_REG_37, 0x1D0F); BK4819_WriteRegister(BK4819_REG_36, 0x0022); BK4819_DisableAGC(); // BK4819_EnableAGC(); BK4819_WriteRegister(BK4819_REG_19, 0b0001000001000001); // <15> MIC AGC 1 = disable 0 = enable BK4819_WriteRegister(BK4819_REG_7D, 0xE940); // REG_48 .. RX AF level // // <15:12> 11 ??? 0 to 15 // // <11:10> 0 AF Rx Gain-1 // 0 = 0dB // 1 = -6dB // 2 = -12dB // 3 = -18dB // // <9:4> 60 AF Rx Gain-2 -26dB ~ 5.5dB 0.5dB/step // 63 = max // 0 = mute // // <3:0> 15 AF DAC Gain (after Gain-1 and Gain-2) approx 2dB/step // 15 = max // 0 = min // BK4819_WriteRegister(BK4819_REG_48, // 0xB3A8); // 1011 00 111010 1000 (11u << 12) | // ??? 0..15 ( 0u << 10) | // AF Rx Gain-1 (58u << 4) | // AF Rx Gain-2 ( 8u << 0)); // AF DAC Gain (after Gain-1 and Gain-2) #if 1 const uint8_t dtmf_coeffs[] = {111, 107, 103, 98, 80, 71, 58, 44, 65, 55, 37, 23, 228, 203, 181, 159}; for (unsigned int i = 0; i < ARRAY_SIZE(dtmf_coeffs); i++) BK4819_WriteRegister(BK4819_REG_09, (i << 12) | dtmf_coeffs[i]); #else // original code BK4819_WriteRegister(BK4819_REG_09, 0x006F); // 6F BK4819_WriteRegister(BK4819_REG_09, 0x106B); // 6B BK4819_WriteRegister(BK4819_REG_09, 0x2067); // 67 BK4819_WriteRegister(BK4819_REG_09, 0x3062); // 62 BK4819_WriteRegister(BK4819_REG_09, 0x4050); // 50 BK4819_WriteRegister(BK4819_REG_09, 0x5047); // 47 BK4819_WriteRegister(BK4819_REG_09, 0x603A); // 3A BK4819_WriteRegister(BK4819_REG_09, 0x702C); // 2C BK4819_WriteRegister(BK4819_REG_09, 0x8041); // 41 BK4819_WriteRegister(BK4819_REG_09, 0x9037); // 37 BK4819_WriteRegister(BK4819_REG_09, 0xA025); // 25 BK4819_WriteRegister(BK4819_REG_09, 0xB017); // 17 BK4819_WriteRegister(BK4819_REG_09, 0xC0E4); // E4 BK4819_WriteRegister(BK4819_REG_09, 0xD0CB); // CB BK4819_WriteRegister(BK4819_REG_09, 0xE0B5); // B5 BK4819_WriteRegister(BK4819_REG_09, 0xF09F); // 9F #endif BK4819_WriteRegister(BK4819_REG_1F, 0x5454); BK4819_WriteRegister(BK4819_REG_3E, 0xA037); gBK4819_GpioOutState = 0x9000; BK4819_WriteRegister(BK4819_REG_33, 0x9000); BK4819_WriteRegister(BK4819_REG_3F, 0); } static uint16_t BK4819_ReadU16(void) { unsigned int i; uint16_t Value; PORTCON_PORTC_IE = (PORTCON_PORTC_IE & ~PORTCON_PORTC_IE_C2_MASK) | PORTCON_PORTC_IE_C2_BITS_ENABLE; GPIOC->DIR = (GPIOC->DIR & ~GPIO_DIR_2_MASK) | GPIO_DIR_2_BITS_INPUT; SYSTICK_DelayUs(1); Value = 0; for (i = 0; i < 16; i++) { Value <<= 1; Value |= GPIO_CheckBit(&GPIOC->DATA, GPIOC_PIN_BK4819_SDA); GPIO_SetBit(&GPIOC->DATA, GPIOC_PIN_BK4819_SCL); SYSTICK_DelayUs(1); GPIO_ClearBit(&GPIOC->DATA, GPIOC_PIN_BK4819_SCL); SYSTICK_DelayUs(1); } PORTCON_PORTC_IE = (PORTCON_PORTC_IE & ~PORTCON_PORTC_IE_C2_MASK) | PORTCON_PORTC_IE_C2_BITS_DISABLE; GPIOC->DIR = (GPIOC->DIR & ~GPIO_DIR_2_MASK) | GPIO_DIR_2_BITS_OUTPUT; return Value; } uint16_t BK4819_ReadRegister(BK4819_REGISTER_t Register) { uint16_t Value; GPIO_SetBit(&GPIOC->DATA, GPIOC_PIN_BK4819_SCN); GPIO_ClearBit(&GPIOC->DATA, GPIOC_PIN_BK4819_SCL); SYSTICK_DelayUs(1); GPIO_ClearBit(&GPIOC->DATA, GPIOC_PIN_BK4819_SCN); BK4819_WriteU8(Register | 0x80); Value = BK4819_ReadU16(); GPIO_SetBit(&GPIOC->DATA, GPIOC_PIN_BK4819_SCN); SYSTICK_DelayUs(1); GPIO_SetBit(&GPIOC->DATA, GPIOC_PIN_BK4819_SCL); GPIO_SetBit(&GPIOC->DATA, GPIOC_PIN_BK4819_SDA); return Value; } void BK4819_WriteRegister(BK4819_REGISTER_t Register, uint16_t Data) { GPIO_SetBit(&GPIOC->DATA, GPIOC_PIN_BK4819_SCN); GPIO_ClearBit(&GPIOC->DATA, GPIOC_PIN_BK4819_SCL); SYSTICK_DelayUs(1); GPIO_ClearBit(&GPIOC->DATA, GPIOC_PIN_BK4819_SCN); BK4819_WriteU8(Register); SYSTICK_DelayUs(1); BK4819_WriteU16(Data); SYSTICK_DelayUs(1); GPIO_SetBit(&GPIOC->DATA, GPIOC_PIN_BK4819_SCN); SYSTICK_DelayUs(1); GPIO_SetBit(&GPIOC->DATA, GPIOC_PIN_BK4819_SCL); GPIO_SetBit(&GPIOC->DATA, GPIOC_PIN_BK4819_SDA); } void BK4819_WriteU8(uint8_t Data) { unsigned int i; GPIO_ClearBit(&GPIOC->DATA, GPIOC_PIN_BK4819_SCL); for (i = 0; i < 8; i++) { if ((Data & 0x80) == 0) GPIO_ClearBit(&GPIOC->DATA, GPIOC_PIN_BK4819_SDA); else GPIO_SetBit(&GPIOC->DATA, GPIOC_PIN_BK4819_SDA); SYSTICK_DelayUs(1); GPIO_SetBit(&GPIOC->DATA, GPIOC_PIN_BK4819_SCL); SYSTICK_DelayUs(1); Data <<= 1; GPIO_ClearBit(&GPIOC->DATA, GPIOC_PIN_BK4819_SCL); SYSTICK_DelayUs(1); } } void BK4819_WriteU16(uint16_t Data) { unsigned int i; GPIO_ClearBit(&GPIOC->DATA, GPIOC_PIN_BK4819_SCL); for (i = 0; i < 16; i++) { if ((Data & 0x8000) == 0) GPIO_ClearBit(&GPIOC->DATA, GPIOC_PIN_BK4819_SDA); else GPIO_SetBit(&GPIOC->DATA, GPIOC_PIN_BK4819_SDA); SYSTICK_DelayUs(1); GPIO_SetBit(&GPIOC->DATA, GPIOC_PIN_BK4819_SCL); Data <<= 1; SYSTICK_DelayUs(1); GPIO_ClearBit(&GPIOC->DATA, GPIOC_PIN_BK4819_SCL); SYSTICK_DelayUs(1); } } void BK4819_DisableAGC() { // REG_10 // // 0x0038 Rx AGC Gain Table[0]. (Index Max->Min is 3,2,1,0,-1) // // <15:10> ??? // // <9:8> LNA Gain Short // 3 = 0dB <<< // 2 = -24dB // was -11 // 1 = -30dB // was -16 // 0 = -33dB // was -19 // // <7:5> LNA Gain // 7 = 0dB // 6 = -2dB // 5 = -4dB // 4 = -6dB // 3 = -9dB // 2 = -14dB <<< // 1 = -19dB // 0 = -24dB // // <4:3> MIXER Gain // 3 = 0dB <<< // 2 = -3dB // 1 = -6dB // 0 = -8dB // // <2:0> PGA Gain // 7 = 0dB // 6 = -3dB <<< // 5 = -6dB // 4 = -9dB // 3 = -15dB // 2 = -21dB // 1 = -27dB // 0 = -33dB // BK4819_WriteRegister(BK4819_REG_13, (3u << 8) | (5u << 5) | (3u << 3) | (6u << 0)); // 000000 11 101 11 110 BK4819_WriteRegister(BK4819_REG_12, 0x037B); // 000000 11 011 11 011 BK4819_WriteRegister(BK4819_REG_11, 0x027B); // 000000 10 011 11 011 BK4819_WriteRegister(BK4819_REG_10, 0x007A); // 000000 00 011 11 010 BK4819_WriteRegister(BK4819_REG_14, 0x0019); // 000000 00 000 11 001 BK4819_WriteRegister(BK4819_REG_49, 0x2A38); BK4819_WriteRegister(BK4819_REG_7B, 0x8420); } void BK4819_EnableAGC() { // REG_10 // // 0x0038 Rx AGC Gain Table[0]. (Index Max->Min is 3,2,1,0,-1) // // (15:10> ??? // // <9:8> LNA Gain Short // 3 = 0dB << original // 2 = -24dB // was -11 // 1 = -30dB // was -16 // 0 = -33dB // was -19 // // <7:5> LNA Gain // 7 = 0dB // 6 = -2dB // 5 = -4dB // 4 = -6dB // 3 = -9dB // 2 = -14dB << original // 1 = -19dB // 0 = -24dB // // <4:3> MIXER Gain // 3 = 0dB << original // 2 = -3dB // 1 = -6dB // 0 = -8dB // // <2:0> PGA Gain // 7 = 0dB // 6 = -3dB << original // 5 = -6dB // 4 = -9dB // 3 = -15dB // 2 = -21dB // 1 = -27dB // 0 = -33dB // BK4819_WriteRegister(BK4819_REG_13, (3u << 8) | (5u << 5) | (3u << 3) | (6u << 0)); BK4819_WriteRegister(BK4819_REG_12, 0x037C); // 000000 11 011 11 100 BK4819_WriteRegister(BK4819_REG_11, 0x027B); // 000000 10 011 11 011 BK4819_WriteRegister(BK4819_REG_10, 0x007A); // 000000 00 011 11 010 BK4819_WriteRegister(BK4819_REG_14, 0x0018); // 000000 00 000 11 000 BK4819_WriteRegister(BK4819_REG_49, 0x2A38); BK4819_WriteRegister(BK4819_REG_7B, 0x318C); BK4819_WriteRegister(BK4819_REG_7C, 0x595E); BK4819_WriteRegister(BK4819_REG_20, 0x8DEF); for (uint8_t i = 0; i < 8; i++) { //BK4819_WriteRegister(BK4819_REG_06, ((i << 13) | 0x2500u) + 0x036u); BK4819_WriteRegister(BK4819_REG_06, (i & 7) << 13 | 0x4A << 7 | 0x36); } } void BK4819_ToggleGpioOut(BK4819_GPIO_PIN_t Pin, bool bSet) { if (bSet) gBK4819_GpioOutState |= (0x40u >> Pin); else gBK4819_GpioOutState &= ~(0x40u >> Pin); BK4819_WriteRegister(BK4819_REG_33, gBK4819_GpioOutState); } void BK4819_SetCDCSSCodeWord(uint32_t CodeWord) { // REG_51 // // <15> 0 // 1 = Enable TxCTCSS/CDCSS // 0 = Disable // // <14> 0 // 1 = GPIO0Input for CDCSS // 0 = Normal Mode (for BK4819 v3) // // <13> 0 // 1 = Transmit negative CDCSS code // 0 = Transmit positive CDCSS code // // <12> 0 CTCSS/CDCSS mode selection // 1 = CTCSS // 0 = CDCSS // // <11> 0 CDCSS 24/23bit selection // 1 = 24bit // 0 = 23bit // // <10> 0 1050HzDetectionMode // 1 = 1050/4 Detect Enable, CTC1 should be set to 1050/4 Hz // // <9> 0 Auto CDCSS Bw Mode // 1 = Disable // 0 = Enable // // <8> 0 Auto CTCSS Bw Mode // 0 = Enable // 1 = Disable // // <6:0> 0 CTCSS/CDCSS Tx Gain1 Tuning // 0 = min // 127 = max // Enable CDCSS // Transmit positive CDCSS code // CDCSS Mode // CDCSS 23bit // Enable Auto CDCSS Bw Mode // Enable Auto CTCSS Bw Mode // CTCSS/CDCSS Tx Gain1 Tuning = 51 // BK4819_WriteRegister(BK4819_REG_51, BK4819_REG_51_ENABLE_CxCSS | BK4819_REG_51_GPIO6_PIN2_NORMAL | BK4819_REG_51_TX_CDCSS_POSITIVE | BK4819_REG_51_MODE_CDCSS | BK4819_REG_51_CDCSS_23_BIT | BK4819_REG_51_1050HZ_NO_DETECTION | BK4819_REG_51_AUTO_CDCSS_BW_ENABLE | BK4819_REG_51_AUTO_CTCSS_BW_ENABLE | (51u << BK4819_REG_51_SHIFT_CxCSS_TX_GAIN1)); // REG_07 <15:0> // // When <13> = 0 for CTC1 // <12:0> = CTC1 frequency control word = // freq(Hz) * 20.64888 for XTAL 13M/26M or // freq(Hz) * 20.97152 for XTAL 12.8M/19.2M/25.6M/38.4M // // When <13> = 1 for CTC2 (Tail 55Hz Rx detection) // <12:0> = CTC2 (should below 100Hz) frequency control word = // 25391 / freq(Hz) for XTAL 13M/26M or // 25000 / freq(Hz) for XTAL 12.8M/19.2M/25.6M/38.4M // // When <13> = 2 for CDCSS 134.4Hz // <12:0> = CDCSS baud rate frequency (134.4Hz) control word = // freq(Hz) * 20.64888 for XTAL 13M/26M or // freq(Hz) * 20.97152 for XTAL 12.8M/19.2M/25.6M/38.4M // BK4819_WriteRegister(BK4819_REG_07, BK4819_REG_07_MODE_CTC1 | 2775u); // REG_08 <15:0> <15> = 1 for CDCSS high 12bit // <15> = 0 for CDCSS low 12bit // <11:0> = CDCSShigh/low 12bit code // BK4819_WriteRegister(BK4819_REG_08, (0u << 15) | ((CodeWord >> 0) & 0x0FFF)); // LS 12-bits BK4819_WriteRegister(BK4819_REG_08, (1u << 15) | ((CodeWord >> 12) & 0x0FFF)); // MS 12-bits } void BK4819_SetCTCSSFrequency(uint32_t FreqControlWord) { // REG_51 <15> 0 1 = Enable TxCTCSS/CDCSS 0 = Disable // REG_51 <14> 0 1 = GPIO0Input for CDCSS 0 = Normal Mode.(for BK4819v3) // REG_51 <13> 0 1 = Transmit negative CDCSS code 0 = Transmit positive CDCSScode // REG_51 <12> 0 CTCSS/CDCSS mode selection 1 = CTCSS 0 = CDCSS // REG_51 <11> 0 CDCSS 24/23bit selection 1 = 24bit 0 = 23bit // REG_51 <10> 0 1050HzDetectionMode 1 = 1050/4 Detect Enable, CTC1 should be set to 1050/4 Hz // REG_51 <9> 0 Auto CDCSS Bw Mode 1 = Disable 0 = Enable. // REG_51 <8> 0 Auto CTCSS Bw Mode 0 = Enable 1 = Disable // REG_51 <6:0> 0 CTCSS/CDCSS Tx Gain1 Tuning 0 = min 127 = max uint16_t Config; if (FreqControlWord == 2625) { // Enables 1050Hz detection mode // Enable TxCTCSS // CTCSS Mode // 1050/4 Detect Enable // Enable Auto CDCSS Bw Mode // Enable Auto CTCSS Bw Mode // CTCSS/CDCSS Tx Gain1 Tuning = 74 // Config = 0x944A; // 1 0 0 1 0 1 0 0 0 1001010 } else { // Enable TxCTCSS // CTCSS Mode // Enable Auto CDCSS Bw Mode // Enable Auto CTCSS Bw Mode // CTCSS/CDCSS Tx Gain1 Tuning = 74 // Config = 0x904A; // 1 0 0 1 0 0 0 0 0 1001010 } BK4819_WriteRegister(BK4819_REG_51, Config); // REG_07 <15:0> // // When <13> = 0 for CTC1 // <12:0> = CTC1 frequency control word = // freq(Hz) * 20.64888 for XTAL 13M/26M or // freq(Hz) * 20.97152 for XTAL 12.8M/19.2M/25.6M/38.4M // // When <13> = 1 for CTC2 (Tail RX detection) // <12:0> = CTC2 (should below 100Hz) frequency control word = // 25391 / freq(Hz) for XTAL 13M/26M or // 25000 / freq(Hz) for XTAL 12.8M/19.2M/25.6M/38.4M // // When <13> = 2 for CDCSS 134.4Hz // <12:0> = CDCSS baud rate frequency (134.4Hz) control word = // freq(Hz) * 20.64888 for XTAL 13M/26M or // freq(Hz) * 20.97152 for XTAL 12.8M/19.2M/25.6M/38.4M // BK4819_WriteRegister(BK4819_REG_07, BK4819_REG_07_MODE_CTC1 | (((FreqControlWord * 206488u) + 50000u) / 100000u)); // with rounding } // freq_10Hz is CTCSS Hz * 10 void BK4819_SetTailDetection(const uint32_t freq_10Hz) { // REG_07 <15:0> // // When <13> = 0 for CTC1 // <12:0> = CTC1 frequency control word = // freq(Hz) * 20.64888 for XTAL 13M/26M or // freq(Hz) * 20.97152 for XTAL 12.8M/19.2M/25.6M/38.4M // // When <13> = 1 for CTC2 (Tail RX detection) // <12:0> = CTC2 (should below 100Hz) frequency control word = // 25391 / freq(Hz) for XTAL 13M/26M or // 25000 / freq(Hz) for XTAL 12.8M/19.2M/25.6M/38.4M // // When <13> = 2 for CDCSS 134.4Hz // <12:0> = CDCSS baud rate frequency (134.4Hz) control word = // freq(Hz) * 20.64888 for XTAL 13M/26M or // freq(Hz) * 20.97152 for XTAL 12.8M/19.2M/25.6M/38.4M // BK4819_WriteRegister(BK4819_REG_07, BK4819_REG_07_MODE_CTC2 | ((253910 + (freq_10Hz / 2)) / freq_10Hz)); // with rounding } void BK4819_EnableVox(uint16_t VoxEnableThreshold, uint16_t VoxDisableThreshold) { //VOX Algorithm //if (voxamp>VoxEnableThreshold) VOX = 1; //else //if (voxamp 0 ??? // // <14:12> 4 RF filter bandwidth // 0 = 1.7 kHz // 1 = 2.0 kHz // 2 = 2.5 kHz // 3 = 3.0 kHz // 4 = 3.75 kHz // 5 = 4.0 kHz // 6 = 4.25 kHz // 7 = 4.5 kHz // if <5> == 1, RF filter bandwidth * 2 // // <11:9> 0 RF filter bandwidth when signal is weak // 0 = 1.7 kHz // 1 = 2.0 kHz // 2 = 2.5 kHz // 3 = 3.0 kHz // 4 = 3.75 kHz // 5 = 4.0 kHz // 6 = 4.25 kHz // 7 = 4.5 kHz // if <5> == 1, RF filter bandwidth * 2 // // <8:6> 1 AFTxLPF2 filter Band Width // 1 = 2.5 kHz (for 12.5k channel space) // 2 = 2.75 kHz // 0 = 3.0 kHz (for 25k channel space) // 3 = 3.5 kHz // 4 = 4.5 kHz // 5 = 4.25 kHz // 6 = 4.0 kHz // 7 = 3.75 kHz // // <5:4> 0 BW Mode Selection // 0 = 12.5k // 1 = 6.25k // 2 = 25k/20k // // <3> 1 ??? // // <2> 0 Gain after FM Demodulation // 0 = 0dB // 1 = 6dB // // <1:0> 0 ??? uint16_t val; switch (Bandwidth) { default: case BK4819_FILTER_BW_WIDE: // 25kHz if (weak_no_different) { // make the RX bandwidth the same with weak signals val = (0u << 15) | // 0 (4u << 12) | // *3 RF filter bandwidth (4u << 9) | // *0 RF filter bandwidth when signal is weak (6u << 6) | // *0 AFTxLPF2 filter Band Width (2u << 4) | // 2 BW Mode Selection (1u << 3) | // 1 (0u << 2) | // 0 Gain after FM Demodulation (0u << 0); // 0 } else { // with weak RX signals the RX bandwidth is reduced val = // 0x3028); // 0 011 000 000 10 1 0 00 (0u << 15) | // 0 (4u << 12) | // *3 RF filter bandwidth (2u << 9) | // *0 RF filter bandwidth when signal is weak (6u << 6) | // *0 AFTxLPF2 filter Band Width (2u << 4) | // 2 BW Mode Selection (1u << 3) | // 1 (0u << 2) | // 0 Gain after FM Demodulation (0u << 0); // 0 } break; case BK4819_FILTER_BW_NARROW: // 12.5kHz if (weak_no_different) { val = (0u << 15) | // 0 (4u << 12) | // *4 RF filter bandwidth (4u << 9) | // *0 RF filter bandwidth when signal is weak (0u << 6) | // *1 AFTxLPF2 filter Band Width (0u << 4) | // 0 BW Mode Selection (1u << 3) | // 1 (0u << 2) | // 0 Gain after FM Demodulation (0u << 0); // 0 } else { val = // 0x4048); // 0 100 000 001 00 1 0 00 (0u << 15) | // 0 (4u << 12) | // *4 RF filter bandwidth (2u << 9) | // *0 RF filter bandwidth when signal is weak (0u << 6) | // *1 AFTxLPF2 filter Band Width (0u << 4) | // 0 BW Mode Selection (1u << 3) | // 1 (0u << 2) | // 0 Gain after FM Demodulation (0u << 0); // 0 } break; case BK4819_FILTER_BW_NARROWER: // 6.25kHz if (weak_no_different) { val = (0u << 15) | // 0 (3u << 12) | // 3 RF filter bandwidth (3u << 9) | // *0 RF filter bandwidth when signal is weak (1u << 6) | // 1 AFTxLPF2 filter Band Width (1u << 4) | // 1 BW Mode Selection (1u << 3) | // 1 (0u << 2) | // 0 Gain after FM Demodulation (0u << 0); // 0 } else { val = (0u << 15) | // 0 (3u << 12) | // 3 RF filter bandwidth (0u << 9) | // 0 RF filter bandwidth when signal is weak (1u << 6) | // 1 AFTxLPF2 filter Band Width (1u << 4) | // 1 BW Mode Selection (1u << 3) | // 1 (0u << 2) | // 1 Gain after FM Demodulation (0u << 0); // 0 } break; } BK4819_WriteRegister(BK4819_REG_43, val); } void BK4819_SetupPowerAmplifier(const uint8_t bias, const uint32_t frequency) { // REG_36 <15:8> 0 PA Bias output 0 ~ 3.2V // 255 = 3.2V // 0 = 0V // // REG_36 <7> 0 // 1 = Enable PA-CTL output // 0 = Disable (Output 0 V) // // REG_36 <5:3> 7 PA gain 1 tuning // 7 = max // 0 = min // // REG_36 <2:0> 7 PA gain 2 tuning // 7 = max // 0 = min // // 280MHz gain 1 = 1 gain 2 = 0 gain 1 = 4 gain 2 = 2 const uint8_t gain = (frequency < 28000000) ? (1u << 3) | (0u << 0) : (4u << 3) | (2u << 0); const uint8_t enable = 1; BK4819_WriteRegister(BK4819_REG_36, (bias << 8) | (enable << 7) | (gain << 0)); } void BK4819_SetFrequency(uint32_t Frequency) { BK4819_WriteRegister(BK4819_REG_38, (Frequency >> 0) & 0xFFFF); BK4819_WriteRegister(BK4819_REG_39, (Frequency >> 16) & 0xFFFF); } void BK4819_SetupSquelch( uint8_t SquelchOpenRSSIThresh, uint8_t SquelchCloseRSSIThresh, uint8_t SquelchOpenNoiseThresh, uint8_t SquelchCloseNoiseThresh, uint8_t SquelchCloseGlitchThresh, uint8_t SquelchOpenGlitchThresh) { // REG_70 // // <15> 0 Enable TONE1 // 1 = Enable // 0 = Disable // // <14:8> 0 TONE1 tuning gain // 0 ~ 127 // // <7> 0 Enable TONE2 // 1 = Enable // 0 = Disable // // <6:0> 0 TONE2/FSK tuning gain // 0 ~ 127 // BK4819_WriteRegister(BK4819_REG_70, 0); // Glitch threshold for Squelch = close // // 0 ~ 255 // BK4819_WriteRegister(BK4819_REG_4D, 0xA000 | SquelchCloseGlitchThresh); // REG_4E // // <15:14> 1 ??? // // <13:11> 5 Squelch = open Delay Setting // 0 ~ 7 // // <10:9> 7 Squelch = close Delay Setting // 0 ~ 3 // // <8> 0 ??? // // <7:0> 8 Glitch threshold for Squelch = open // 0 ~ 255 // BK4819_WriteRegister(BK4819_REG_4E, // 01 101 11 1 00000000 // original (*) (1u << 14) | // 1 ??? (5u << 11) | // *5 squelch = open delay .. 0 ~ 7 (6u << 9) | // *3 squelch = close delay .. 0 ~ 3 SquelchOpenGlitchThresh); // 0 ~ 255 // REG_4F // // <14:8> 47 Ex-noise threshold for Squelch = close // 0 ~ 127 // // <7> ??? // // <6:0> 46 Ex-noise threshold for Squelch = open // 0 ~ 127 // BK4819_WriteRegister(BK4819_REG_4F, ((uint16_t)SquelchCloseNoiseThresh << 8) | SquelchOpenNoiseThresh); // REG_78 // // <15:8> 72 RSSI threshold for Squelch = open 0.5dB/step // // <7:0> 70 RSSI threshold for Squelch = close 0.5dB/step // BK4819_WriteRegister(BK4819_REG_78, ((uint16_t)SquelchOpenRSSIThresh << 8) | SquelchCloseRSSIThresh); BK4819_SetAF(BK4819_AF_MUTE); BK4819_RX_TurnOn(); } void BK4819_SetAF(BK4819_AF_Type_t AF) { // AF Output Inverse Mode = Inverse // Undocumented bits 0x2040 // // BK4819_WriteRegister(BK4819_REG_47, 0x6040 | (AF << 8)); BK4819_WriteRegister(BK4819_REG_47, (6u << 12) | (AF << 8) | (1u << 6)); } void BK4819_SetRegValue(RegisterSpec s, uint16_t v) { uint16_t reg = BK4819_ReadRegister(s.num); reg &= ~(s.mask << s.offset); BK4819_WriteRegister(s.num, reg | (v << s.offset)); } void BK4819_RX_TurnOn(void) { // DSP Voltage Setting = 1 // ANA LDO = 2.7v // VCO LDO = 2.7v // RF LDO = 2.7v // PLL LDO = 2.7v // ANA LDO bypass // VCO LDO bypass // RF LDO bypass // PLL LDO bypass // Reserved bit is 1 instead of 0 // Enable DSP // Enable XTAL // Enable Band Gap // BK4819_WriteRegister(BK4819_REG_37, 0x1F0F); // 0001111100001111 // Turn off everything BK4819_WriteRegister(BK4819_REG_30, 0); // Enable VCO Calibration // Enable RX Link // Enable AF DAC // Enable PLL/VCO // Disable PA Gain // Disable MIC ADC // Disable TX DSP // Enable RX DSP // BK4819_WriteRegister(BK4819_REG_30, 0b1011111111110001); // 1 0 1111 1 1 1111 0 0 0 1 } void BK4819_PickRXFilterPathBasedOnFrequency(uint32_t Frequency) { if (Frequency < 28000000) { // VHF BK4819_ToggleGpioOut(BK4819_GPIO4_PIN32_VHF_LNA, true); BK4819_ToggleGpioOut(BK4819_GPIO3_PIN31_UHF_LNA, false); } else if (Frequency == 0xFFFFFFFF) { // OFF BK4819_ToggleGpioOut(BK4819_GPIO4_PIN32_VHF_LNA, false); BK4819_ToggleGpioOut(BK4819_GPIO3_PIN31_UHF_LNA, false); } else { // UHF BK4819_ToggleGpioOut(BK4819_GPIO4_PIN32_VHF_LNA, false); BK4819_ToggleGpioOut(BK4819_GPIO3_PIN31_UHF_LNA, true); } } void BK4819_DisableScramble(void) { const uint16_t Value = BK4819_ReadRegister(BK4819_REG_31); BK4819_WriteRegister(BK4819_REG_31, Value & ~(1u << 1)); } void BK4819_EnableScramble(uint8_t Type) { const uint16_t Value = BK4819_ReadRegister(BK4819_REG_31); BK4819_WriteRegister(BK4819_REG_31, Value | (1u << 1)); BK4819_WriteRegister(BK4819_REG_71, 0x68DC + (Type * 1032)); // 0110 1000 1101 1100 } bool BK4819_CompanderEnabled(void) { return (BK4819_ReadRegister(BK4819_REG_31) & (1u << 3)) ? true : false; } void BK4819_SetCompander(const unsigned int mode) { // mode 0 .. OFF // mode 1 .. TX // mode 2 .. RX // mode 3 .. TX and RX const uint16_t r31 = BK4819_ReadRegister(BK4819_REG_31); if (mode == 0) { // disable BK4819_WriteRegister(BK4819_REG_31, r31 & ~(1u << 3)); return; } // REG_29 // // <15:14> 10 Compress (AF Tx) Ratio // 00 = Disable // 01 = 1.333:1 // 10 = 2:1 // 11 = 4:1 // // <13:7> 86 Compress (AF Tx) 0 dB point (dB) // // <6:0> 64 Compress (AF Tx) noise point (dB) // const uint16_t compress_ratio = (mode == 1 || mode >= 3) ? 2 : 0; // 2:1 const uint16_t compress_0dB = 86; const uint16_t compress_noise_dB = 64; // AB40 10 1010110 1000000 BK4819_WriteRegister(BK4819_REG_29, // (BK4819_ReadRegister(BK4819_REG_29) & ~(3u << 14)) | (compress_ratio << 14)); (compress_ratio << 14) | (compress_0dB << 7) | (compress_noise_dB << 0)); // REG_28 // // <15:14> 01 Expander (AF Rx) Ratio // 00 = Disable // 01 = 1:2 // 10 = 1:3 // 11 = 1:4 // // <13:7> 86 Expander (AF Rx) 0 dB point (dB) // // <6:0> 56 Expander (AF Rx) noise point (dB) // const uint16_t expand_ratio = (mode >= 2) ? 1 : 0; // 1:2 const uint16_t expand_0dB = 86; const uint16_t expand_noise_dB = 56; // 6B38 01 1010110 0111000 BK4819_WriteRegister(BK4819_REG_28, // (BK4819_ReadRegister(BK4819_REG_28) & ~(3u << 14)) | (expand_ratio << 14)); (expand_ratio << 14) | (expand_0dB << 7) | (expand_noise_dB << 0)); // enable BK4819_WriteRegister(BK4819_REG_31, r31 | (1u << 3)); } void BK4819_DisableVox(void) { const uint16_t Value = BK4819_ReadRegister(BK4819_REG_31); BK4819_WriteRegister(BK4819_REG_31, Value & 0xFFFB); } void BK4819_DisableDTMF(void) { BK4819_WriteRegister(BK4819_REG_24, 0); } void BK4819_EnableDTMF(void) { // no idea what this does BK4819_WriteRegister(BK4819_REG_21, 0x06D8); // 0000 0110 1101 1000 // REG_24 // // <15> 1 ??? // // <14:7> 24 Threshold // // <6> 1 ??? // // <5> 0 DTMF/SelCall enable // 1 = Enable // 0 = Disable // // <4> 1 DTMF or SelCall detection mode // 1 = for DTMF // 0 = for SelCall // // <3:0> 14 Max symbol number for SelCall detection // // const uint16_t threshold = 24; // default, but doesn't decode non-QS radios const uint16_t threshold = 130; // but 128 ~ 247 does BK4819_WriteRegister(BK4819_REG_24, // 1 00011000 1 1 1 1110 (1u << BK4819_REG_24_SHIFT_UNKNOWN_15) | (threshold << BK4819_REG_24_SHIFT_THRESHOLD) | // 0 ~ 255 (1u << BK4819_REG_24_SHIFT_UNKNOWN_6) | BK4819_REG_24_ENABLE | BK4819_REG_24_SELECT_DTMF | (15u << BK4819_REG_24_SHIFT_MAX_SYMBOLS)); // 0 ~ 15 } void BK4819_PlayTone(uint16_t Frequency, bool bTuningGainSwitch) { uint16_t ToneConfig = BK4819_REG_70_ENABLE_TONE1; BK4819_EnterTxMute(); BK4819_SetAF(BK4819_AF_BEEP); if (bTuningGainSwitch == 0) ToneConfig |= 96u << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN; else ToneConfig |= 28u << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN; BK4819_WriteRegister(BK4819_REG_70, ToneConfig); BK4819_WriteRegister(BK4819_REG_30, 0); BK4819_WriteRegister(BK4819_REG_30, BK4819_REG_30_ENABLE_AF_DAC | BK4819_REG_30_ENABLE_DISC_MODE | BK4819_REG_30_ENABLE_TX_DSP); BK4819_WriteRegister(BK4819_REG_71, scale_freq(Frequency)); } void BK4819_PlaySingleTone(const unsigned int tone_Hz, const unsigned int delay, const unsigned int level, const bool play_speaker) { BK4819_EnterTxMute(); if (play_speaker) { AUDIO_AudioPathOn(); BK4819_SetAF(BK4819_AF_BEEP); } else BK4819_SetAF(BK4819_AF_MUTE); // level 0 ~ 127 // BK4819_WriteRegister(BK4819_REG_70, BK4819_REG_70_ENABLE_TONE1 | (96u << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN)); // BK4819_WriteRegister(BK4819_REG_70, BK4819_REG_70_ENABLE_TONE1 | (28u << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN)); BK4819_WriteRegister(BK4819_REG_70, BK4819_REG_70_ENABLE_TONE1 | ((level & 0x7f) << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN)); BK4819_EnableTXLink(); SYSTEM_DelayMs(50); BK4819_WriteRegister(BK4819_REG_71, scale_freq(tone_Hz)); BK4819_ExitTxMute(); SYSTEM_DelayMs(delay); BK4819_EnterTxMute(); if (play_speaker) { AUDIO_AudioPathOff(); BK4819_SetAF(BK4819_AF_MUTE); } BK4819_WriteRegister(BK4819_REG_70, 0x0000); BK4819_WriteRegister(BK4819_REG_30, 0xC1FE); BK4819_ExitTxMute(); } void BK4819_EnterTxMute(void) { BK4819_WriteRegister(BK4819_REG_50, 0xBB20); } void BK4819_ExitTxMute(void) { BK4819_WriteRegister(BK4819_REG_50, 0x3B20); } void BK4819_Sleep(void) { BK4819_WriteRegister(BK4819_REG_30, 0); BK4819_WriteRegister(BK4819_REG_37, 0x1D00); } void BK4819_TurnsOffTones_TurnsOnRX(void) { BK4819_WriteRegister(BK4819_REG_70, 0); BK4819_SetAF(BK4819_AF_MUTE); BK4819_ExitTxMute(); BK4819_WriteRegister(BK4819_REG_30, 0); BK4819_WriteRegister(BK4819_REG_30, BK4819_REG_30_ENABLE_VCO_CALIB | BK4819_REG_30_ENABLE_RX_LINK | BK4819_REG_30_ENABLE_AF_DAC | BK4819_REG_30_ENABLE_DISC_MODE | BK4819_REG_30_ENABLE_PLL_VCO | BK4819_REG_30_ENABLE_RX_DSP); } #ifdef ENABLE_AIRCOPY void BK4819_SetupAircopy(void) { BK4819_WriteRegister(BK4819_REG_70, 0x00E0); // Enable Tone2, tuning gain 48 BK4819_WriteRegister(BK4819_REG_72, 0x3065); // Tone2 baudrate 1200 BK4819_WriteRegister(BK4819_REG_58, 0x00C1); // FSK Enable, FSK 1.2K RX Bandwidth, Preamble 0xAA or 0x55, RX Gain 0, RX Mode // (FSK1.2K, FSK2.4K Rx and NOAA SAME Rx), TX Mode FSK 1.2K and FSK 2.4K Tx BK4819_WriteRegister(BK4819_REG_5C, 0x5665); // Enable CRC among other things we don't know yet BK4819_WriteRegister(BK4819_REG_5D, 0x4700); // FSK Data Length 72 Bytes (0xabcd + 2 byte length + 64 byte payload + 2 byte CRC + 0xdcba) } #endif void BK4819_ResetFSK(void) { BK4819_WriteRegister(BK4819_REG_3F, 0x0000); // Disable interrupts BK4819_WriteRegister(BK4819_REG_59, 0x0068); // Sync length 4 bytes, 7 byte preamble SYSTEM_DelayMs(30); BK4819_Idle(); } void BK4819_Idle(void) { BK4819_WriteRegister(BK4819_REG_30, 0x0000); } void BK4819_ExitBypass(void) { BK4819_SetAF(BK4819_AF_MUTE); // REG_7E // // <15> 0 AGC fix mode // 1 = fix // 0 = auto // // <14:12> 3 AGC fix index // 3 ( 3) = max // 2 ( 2) // 1 ( 1) // 0 ( 0) // 7 (-1) // 6 (-2) // 5 (-3) // 4 (-4) = min // // <11:6> 0 ??? // // <5:3> 5 DC filter band width for Tx (MIC In) // 0 ~ 7 // 0 = bypass DC filter // // <2:0> 6 DC filter band width for Rx (I.F In) // 0 ~ 7 // 0 = bypass DC filter // BK4819_WriteRegister(BK4819_REG_7E, // 0x302E); // 0 011 000000 101 110 (0u << 15) | // 0 AGC fix mode (3u << 12) | // 3 AGC fix index (5u << 3) | // 5 DC Filter band width for Tx (MIC In) (6u << 0)); // 6 DC Filter band width for Rx (I.F In) } void BK4819_PrepareTransmit(void) { BK4819_ExitBypass(); BK4819_ExitTxMute(); BK4819_TxOn_Beep(); } void BK4819_TxOn_Beep(void) { BK4819_WriteRegister(BK4819_REG_37, 0x1D0F); BK4819_WriteRegister(BK4819_REG_52, 0x028F); BK4819_WriteRegister(BK4819_REG_30, 0x0000); BK4819_WriteRegister(BK4819_REG_30, 0xC1FE); } void BK4819_ExitSubAu(void) { // REG_51 // // <15> 0 // 1 = Enable TxCTCSS/CDCSS // 0 = Disable // // <14> 0 // 1 = GPIO0Input for CDCSS // 0 = Normal Mode (for BK4819 v3) // // <13> 0 // 1 = Transmit negative CDCSS code // 0 = Transmit positive CDCSS code // // <12> 0 CTCSS/CDCSS mode selection // 1 = CTCSS // 0 = CDCSS // // <11> 0 CDCSS 24/23bit selection // 1 = 24bit // 0 = 23bit // // <10> 0 1050HzDetectionMode // 1 = 1050/4 Detect Enable, CTC1 should be set to 1050/4 Hz // // <9> 0 Auto CDCSS Bw Mode // 1 = Disable // 0 = Enable // // <8> 0 Auto CTCSS Bw Mode // 0 = Enable // 1 = Disable // // <6:0> 0 CTCSS/CDCSS Tx Gain1 Tuning // 0 = min // 127 = max // BK4819_WriteRegister(BK4819_REG_51, 0x0000); } void BK4819_Conditional_RX_TurnOn_and_GPIO6_Enable(void) { if (gRxIdleMode) { BK4819_ToggleGpioOut(BK4819_GPIO0_PIN28_RX_ENABLE, true); BK4819_RX_TurnOn(); } } void BK4819_EnterDTMF_TX(bool bLocalLoopback) { BK4819_EnableDTMF(); BK4819_EnterTxMute(); BK4819_SetAF(bLocalLoopback ? BK4819_AF_BEEP : BK4819_AF_MUTE); BK4819_WriteRegister(BK4819_REG_70, BK4819_REG_70_MASK_ENABLE_TONE1 | // (83u << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN) | (DTMF_TONE1_GAIN << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN) | BK4819_REG_70_MASK_ENABLE_TONE2 | // (83u << BK4819_REG_70_SHIFT_TONE2_TUNING_GAIN)); (DTMF_TONE2_GAIN << BK4819_REG_70_SHIFT_TONE2_TUNING_GAIN)); BK4819_EnableTXLink(); } void BK4819_ExitDTMF_TX(bool bKeep) { BK4819_EnterTxMute(); BK4819_SetAF(BK4819_AF_MUTE); BK4819_WriteRegister(BK4819_REG_70, 0x0000); BK4819_DisableDTMF(); BK4819_WriteRegister(BK4819_REG_30, 0xC1FE); if (!bKeep) BK4819_ExitTxMute(); } void BK4819_EnableTXLink(void) { BK4819_WriteRegister(BK4819_REG_30, BK4819_REG_30_ENABLE_VCO_CALIB | BK4819_REG_30_ENABLE_UNKNOWN | BK4819_REG_30_DISABLE_RX_LINK | BK4819_REG_30_ENABLE_AF_DAC | BK4819_REG_30_ENABLE_DISC_MODE | BK4819_REG_30_ENABLE_PLL_VCO | BK4819_REG_30_ENABLE_PA_GAIN | BK4819_REG_30_DISABLE_MIC_ADC | BK4819_REG_30_ENABLE_TX_DSP | BK4819_REG_30_DISABLE_RX_DSP); } void BK4819_PlayDTMF(char Code) { uint16_t tone1 = 0; uint16_t tone2 = 0; switch (Code) { case '0': tone1 = 941; tone2 = 1336; break; // case '1': tone1 = 679; tone2 = 1209; break; case '1': tone1 = 697; tone2 = 1209; break; case '2': tone1 = 697; tone2 = 1336; break; // case '3': tone1 = 679; tone2 = 1477; break; case '3': tone1 = 697; tone2 = 1477; break; case '4': tone1 = 770; tone2 = 1209; break; case '5': tone1 = 770; tone2 = 1336; break; case '6': tone1 = 770; tone2 = 1477; break; case '7': tone1 = 852; tone2 = 1209; break; case '8': tone1 = 852; tone2 = 1336; break; case '9': tone1 = 852; tone2 = 1477; break; // case 'A': tone1 = 679; tone2 = 1633; break; case 'A': tone1 = 697; tone2 = 1633; break; case 'B': tone1 = 770; tone2 = 1633; break; case 'C': tone1 = 852; tone2 = 1633; break; case 'D': tone1 = 941; tone2 = 1633; break; case '*': tone1 = 941; tone2 = 1209; break; case '#': tone1 = 941; tone2 = 1477; break; } if (tone1 > 0) BK4819_WriteRegister(BK4819_REG_71, (((uint32_t)tone1 * 103244) + 5000) / 10000); // with rounding if (tone2 > 0) BK4819_WriteRegister(BK4819_REG_72, (((uint32_t)tone2 * 103244) + 5000) / 10000); // with rounding } void BK4819_PlayDTMFString(const char *pString, bool bDelayFirst, uint16_t FirstCodePersistTime, uint16_t HashCodePersistTime, uint16_t CodePersistTime, uint16_t CodeInternalTime) { unsigned int i; if (pString == NULL) return; for (i = 0; pString[i]; i++) { uint16_t Delay; BK4819_PlayDTMF(pString[i]); BK4819_ExitTxMute(); if (bDelayFirst && i == 0) Delay = FirstCodePersistTime; else if (pString[i] == '*' || pString[i] == '#') Delay = HashCodePersistTime; else Delay = CodePersistTime; SYSTEM_DelayMs(Delay); BK4819_EnterTxMute(); SYSTEM_DelayMs(CodeInternalTime); } } void BK4819_TransmitTone(bool bLocalLoopback, uint32_t Frequency) { BK4819_EnterTxMute(); // REG_70 // // <15> 0 Enable TONE1 // 1 = Enable // 0 = Disable // // <14:8> 0 TONE1 tuning gain // 0 ~ 127 // // <7> 0 Enable TONE2 // 1 = Enable // 0 = Disable // // <6:0> 0 TONE2/FSK amplitude // 0 ~ 127 // // set the tone amplitude // // BK4819_WriteRegister(BK4819_REG_70, BK4819_REG_70_MASK_ENABLE_TONE1 | (96u << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN)); BK4819_WriteRegister(BK4819_REG_70, BK4819_REG_70_MASK_ENABLE_TONE1 | (66u << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN)); BK4819_WriteRegister(BK4819_REG_71, scale_freq(Frequency)); BK4819_SetAF(bLocalLoopback ? BK4819_AF_BEEP : BK4819_AF_MUTE); BK4819_EnableTXLink(); SYSTEM_DelayMs(50); BK4819_ExitTxMute(); } void BK4819_GenTail(uint8_t Tail) { // REG_52 // // <15> 0 Enable 120/180/240 degree shift CTCSS or 134.4Hz Tail when CDCSS mode // 0 = Normal // 1 = Enable // // <14:13> 0 CTCSS tail mode selection (only valid when REG_52 <15> = 1) // 00 = for 134.4Hz CTCSS Tail when CDCSS mode // 01 = CTCSS0 120° phase shift // 10 = CTCSS0 180° phase shift // 11 = CTCSS0 240° phase shift // // <12> 0 CTCSSDetectionThreshold Mode // 1 = ~0.1% // 0 = 0.1 Hz // // <11:6> 0x0A CTCSS found detect threshold // // <5:0> 0x0F CTCSS lost detect threshold // REG_07 <15:0> // // When <13> = 0 for CTC1 // <12:0> = CTC1 frequency control word = // freq(Hz) * 20.64888 for XTAL 13M/26M or // freq(Hz) * 20.97152 for XTAL 12.8M/19.2M/25.6M/38.4M // // When <13> = 1 for CTC2 (Tail 55Hz Rx detection) // <12:0> = CTC2 (should below 100Hz) frequency control word = // 25391 / freq(Hz) for XTAL 13M/26M or // 25000 / freq(Hz) for XTAL 12.8M/19.2M/25.6M/38.4M // // When <13> = 2 for CDCSS 134.4Hz // <12:0> = CDCSS baud rate frequency (134.4Hz) control word = // freq(Hz) * 20.64888 for XTAL 13M/26M or // freq(Hz)*20.97152 for XTAL 12.8M/19.2M/25.6M/38.4M switch (Tail) { case 0: // 134.4Hz CTCSS Tail BK4819_WriteRegister(BK4819_REG_52, 0x828F); // 1 00 0 001010 001111 break; case 1: // 120° phase shift BK4819_WriteRegister(BK4819_REG_52, 0xA28F); // 1 01 0 001010 001111 break; case 2: // 180° phase shift BK4819_WriteRegister(BK4819_REG_52, 0xC28F); // 1 10 0 001010 001111 break; case 3: // 240° phase shift BK4819_WriteRegister(BK4819_REG_52, 0xE28F); // 1 11 0 001010 001111 break; case 4: // 55Hz tone freq BK4819_WriteRegister(BK4819_REG_07, 0x046f); // 0 00 0 010001 101111 break; } } void BK4819_EnableCDCSS(void) { BK4819_GenTail(0); // CTC134 BK4819_WriteRegister(BK4819_REG_51, 0x804A); } void BK4819_EnableCTCSS(void) { #ifdef ENABLE_CTCSS_TAIL_PHASE_SHIFT //BK4819_GenTail(1); // 120° phase shift BK4819_GenTail(2); // 180° phase shift //BK4819_GenTail(3); // 240° phase shift #else BK4819_GenTail(4); // 55Hz tone freq #endif // REG_51 // // <15> 0 // 1 = Enable TxCTCSS/CDCSS // 0 = Disable // // <14> 0 // 1 = GPIO0Input for CDCSS // 0 = Normal Mode (for BK4819 v3) // // <13> 0 // 1 = Transmit negative CDCSS code // 0 = Transmit positive CDCSS code // // <12> 0 CTCSS/CDCSS mode selection // 1 = CTCSS // 0 = CDCSS // // <11> 0 CDCSS 24/23bit selection // 1 = 24bit // 0 = 23bit // // <10> 0 1050HzDetectionMode // 1 = 1050/4 Detect Enable, CTC1 should be set to 1050/4 Hz // // <9> 0 Auto CDCSS Bw Mode // 1 = Disable // 0 = Enable // // <8> 0 Auto CTCSS Bw Mode // 0 = Enable // 1 = Disable // // <6:0> 0 CTCSS/CDCSS Tx Gain1 Tuning // 0 = min // 127 = max BK4819_WriteRegister(BK4819_REG_51, 0x904A); // 1 0 0 1 0 0 0 0 0 1001010 } uint16_t BK4819_GetRSSI(void) { return BK4819_ReadRegister(BK4819_REG_67) & 0x01FF; } uint8_t BK4819_GetGlitchIndicator(void) { return BK4819_ReadRegister(BK4819_REG_63) & 0x00FF; } uint8_t BK4819_GetExNoiceIndicator(void) { return BK4819_ReadRegister(BK4819_REG_65) & 0x007F; } uint16_t BK4819_GetVoiceAmplitudeOut(void) { return BK4819_ReadRegister(BK4819_REG_64); } uint8_t BK4819_GetAfTxRx(void) { return BK4819_ReadRegister(BK4819_REG_6F) & 0x003F; } bool BK4819_GetFrequencyScanResult(uint32_t *pFrequency) { const uint16_t High = BK4819_ReadRegister(BK4819_REG_0D); const bool Finished = (High & 0x8000) == 0; if (Finished) { const uint16_t Low = BK4819_ReadRegister(BK4819_REG_0E); *pFrequency = (uint32_t)((High & 0x7FF) << 16) | Low; } return Finished; } BK4819_CssScanResult_t BK4819_GetCxCSSScanResult(uint32_t *pCdcssFreq, uint16_t *pCtcssFreq) { uint16_t Low; uint16_t High = BK4819_ReadRegister(BK4819_REG_69); if ((High & 0x8000) == 0) { Low = BK4819_ReadRegister(BK4819_REG_6A); *pCdcssFreq = ((High & 0xFFF) << 12) | (Low & 0xFFF); return BK4819_CSS_RESULT_CDCSS; } Low = BK4819_ReadRegister(BK4819_REG_68); if ((Low & 0x8000) == 0) { *pCtcssFreq = ((Low & 0x1FFF) * 4843) / 10000; return BK4819_CSS_RESULT_CTCSS; } return BK4819_CSS_RESULT_NOT_FOUND; } void BK4819_DisableFrequencyScan(void) { // REG_32 // // <15:14> 0 frequency scan time // 0 = 0.2 sec // 1 = 0.4 sec // 2 = 0.8 sec // 3 = 1.6 sec // // <13:1> ??? // // <0> 0 frequency scan enable // 1 = enable // 0 = disable // BK4819_WriteRegister(BK4819_REG_32, // 0x0244); // 00 0000100100010 0 ( 0u << 14) | // 0 frequency scan Time (290u << 1) | // ??? ( 0u << 0)); // 0 frequency scan enable } void BK4819_EnableFrequencyScan(void) { // REG_32 // // <15:14> 0 frequency scan time // 0 = 0.2 sec // 1 = 0.4 sec // 2 = 0.8 sec // 3 = 1.6 sec // // <13:1> ??? // // <0> 0 frequency scan enable // 1 = enable // 0 = disable // BK4819_WriteRegister(BK4819_REG_32, // 0x0245); // 00 0000100100010 1 ( 0u << 14) | // 0 frequency scan time (290u << 1) | // ??? ( 1u << 0)); // 1 frequency scan enable } void BK4819_SetScanFrequency(uint32_t Frequency) { BK4819_SetFrequency(Frequency); // REG_51 // // <15> 0 // 1 = Enable TxCTCSS/CDCSS // 0 = Disable // // <14> 0 // 1 = GPIO0Input for CDCSS // 0 = Normal Mode (for BK4819 v3) // // <13> 0 // 1 = Transmit negative CDCSS code // 0 = Transmit positive CDCSS code // // <12> 0 CTCSS/CDCSS mode selection // 1 = CTCSS // 0 = CDCSS // // <11> 0 CDCSS 24/23bit selection // 1 = 24bit // 0 = 23bit // // <10> 0 1050HzDetectionMode // 1 = 1050/4 Detect Enable, CTC1 should be set to 1050/4 Hz // // <9> 0 Auto CDCSS Bw Mode // 1 = Disable // 0 = Enable // // <8> 0 Auto CTCSS Bw Mode // 0 = Enable // 1 = Disable // // <6:0> 0 CTCSS/CDCSS Tx Gain1 Tuning // 0 = min // 127 = max // BK4819_WriteRegister(BK4819_REG_51, BK4819_REG_51_DISABLE_CxCSS | BK4819_REG_51_GPIO6_PIN2_NORMAL | BK4819_REG_51_TX_CDCSS_POSITIVE | BK4819_REG_51_MODE_CDCSS | BK4819_REG_51_CDCSS_23_BIT | BK4819_REG_51_1050HZ_NO_DETECTION | BK4819_REG_51_AUTO_CDCSS_BW_DISABLE | BK4819_REG_51_AUTO_CTCSS_BW_DISABLE); BK4819_RX_TurnOn(); } void BK4819_Disable(void) { BK4819_WriteRegister(BK4819_REG_30, 0); } void BK4819_StopScan(void) { BK4819_DisableFrequencyScan(); BK4819_Disable(); } uint8_t BK4819_GetDTMF_5TONE_Code(void) { return (BK4819_ReadRegister(BK4819_REG_0B) >> 8) & 0x0F; } uint8_t BK4819_GetCDCSSCodeType(void) { return (BK4819_ReadRegister(BK4819_REG_0C) >> 14) & 3u; } uint8_t BK4819_GetCTCShift(void) { return (BK4819_ReadRegister(BK4819_REG_0C) >> 12) & 3u; } uint8_t BK4819_GetCTCType(void) { return (BK4819_ReadRegister(BK4819_REG_0C) >> 10) & 3u; } void BK4819_SendFSKData(uint16_t *pData) { unsigned int i; uint8_t Timeout = 200; SYSTEM_DelayMs(20); BK4819_WriteRegister(BK4819_REG_3F, BK4819_REG_3F_FSK_TX_FINISHED); BK4819_WriteRegister(BK4819_REG_59, 0x8068); BK4819_WriteRegister(BK4819_REG_59, 0x0068); for (i = 0; i < 36; i++) BK4819_WriteRegister(BK4819_REG_5F, pData[i]); SYSTEM_DelayMs(20); BK4819_WriteRegister(BK4819_REG_59, 0x2868); while (Timeout-- && (BK4819_ReadRegister(BK4819_REG_0C) & 1u) == 0) SYSTEM_DelayMs(5); BK4819_WriteRegister(BK4819_REG_02, 0); SYSTEM_DelayMs(20); BK4819_ResetFSK(); } void BK4819_PrepareFSKReceive(void) { BK4819_ResetFSK(); BK4819_WriteRegister(BK4819_REG_02, 0); BK4819_WriteRegister(BK4819_REG_3F, 0); BK4819_RX_TurnOn(); BK4819_WriteRegister(BK4819_REG_3F, 0 | BK4819_REG_3F_FSK_RX_FINISHED | BK4819_REG_3F_FSK_FIFO_ALMOST_FULL); // Clear RX FIFO // FSK Preamble Length 7 bytes // FSK SyncLength Selection BK4819_WriteRegister(BK4819_REG_59, 0x4068); // Enable FSK Scramble // Enable FSK RX // FSK Preamble Length 7 bytes // FSK SyncLength Selection BK4819_WriteRegister(BK4819_REG_59, 0x3068); } void BK4819_PlayRoger(void) { #if 0 const uint32_t tone1_Hz = 500; const uint32_t tone2_Hz = 700; #else // motorola type const uint32_t tone1_Hz = 1540; const uint32_t tone2_Hz = 1310; #endif BK4819_EnterTxMute(); BK4819_SetAF(BK4819_AF_MUTE); // BK4819_WriteRegister(BK4819_REG_70, BK4819_REG_70_ENABLE_TONE1 | (96u << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN)); BK4819_WriteRegister(BK4819_REG_70, BK4819_REG_70_ENABLE_TONE1 | (66u << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN)); BK4819_EnableTXLink(); SYSTEM_DelayMs(50); BK4819_WriteRegister(BK4819_REG_71, scale_freq(tone1_Hz)); BK4819_ExitTxMute(); SYSTEM_DelayMs(80); BK4819_EnterTxMute(); BK4819_WriteRegister(BK4819_REG_71, scale_freq(tone2_Hz)); BK4819_ExitTxMute(); SYSTEM_DelayMs(80); BK4819_EnterTxMute(); BK4819_WriteRegister(BK4819_REG_70, 0x0000); BK4819_WriteRegister(BK4819_REG_30, 0xC1FE); // 1 1 0000 0 1 1111 1 1 1 0 } void BK4819_PlayRogerMDC(void) { unsigned int i; BK4819_SetAF(BK4819_AF_MUTE); BK4819_WriteRegister(BK4819_REG_58, 0x37C3); // FSK Enable, // RX Bandwidth FFSK 1200/1800 // 0xAA or 0x55 Preamble // 11 RX Gain, // 101 RX Mode // TX FFSK 1200/1800 BK4819_WriteRegister(BK4819_REG_72, 0x3065); // Set Tone-2 to 1200Hz BK4819_WriteRegister(BK4819_REG_70, 0x00E0); // Enable Tone-2 and Set Tone2 Gain BK4819_WriteRegister(BK4819_REG_5D, 0x0D00); // Set FSK data length to 13 bytes BK4819_WriteRegister(BK4819_REG_59, 0x8068); // 4 byte sync length, 6 byte preamble, clear TX FIFO BK4819_WriteRegister(BK4819_REG_59, 0x0068); // Same, but clear TX FIFO is now unset (clearing done) BK4819_WriteRegister(BK4819_REG_5A, 0x5555); // First two sync bytes BK4819_WriteRegister(BK4819_REG_5B, 0x55AA); // End of sync bytes. Total 4 bytes: 555555aa BK4819_WriteRegister(BK4819_REG_5C, 0xAA30); // Disable CRC // Send the data from the roger table for (i = 0; i < 7; i++) BK4819_WriteRegister(BK4819_REG_5F, FSK_RogerTable[i]); SYSTEM_DelayMs(20); // 4 sync bytes, 6 byte preamble, Enable FSK TX BK4819_WriteRegister(BK4819_REG_59, 0x0868); SYSTEM_DelayMs(180); // Stop FSK TX, reset Tone-2, disable FSK BK4819_WriteRegister(BK4819_REG_59, 0x0068); BK4819_WriteRegister(BK4819_REG_70, 0x0000); BK4819_WriteRegister(BK4819_REG_58, 0x0000); } void BK4819_Enable_AfDac_DiscMode_TxDsp(void) { BK4819_WriteRegister(BK4819_REG_30, 0x0000); BK4819_WriteRegister(BK4819_REG_30, 0x0302); } void BK4819_GetVoxAmp(uint16_t *pResult) { *pResult = BK4819_ReadRegister(BK4819_REG_64) & 0x7FFF; } void BK4819_SetScrambleFrequencyControlWord(uint32_t Frequency) { BK4819_WriteRegister(BK4819_REG_71, scale_freq(Frequency)); } void BK4819_PlayDTMFEx(bool bLocalLoopback, char Code) { BK4819_EnableDTMF(); BK4819_EnterTxMute(); BK4819_SetAF(bLocalLoopback ? BK4819_AF_BEEP : BK4819_AF_MUTE); // BK4819_WriteRegister(BK4819_REG_70, 0xD3D3); BK4819_WriteRegister(BK4819_REG_70, BK4819_REG_70_MASK_ENABLE_TONE1 | (DTMF_TONE1_GAIN << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN) | BK4819_REG_70_MASK_ENABLE_TONE2 | (DTMF_TONE2_GAIN << BK4819_REG_70_SHIFT_TONE2_TUNING_GAIN)); BK4819_EnableTXLink(); SYSTEM_DelayMs(50); BK4819_PlayDTMF(Code); BK4819_ExitTxMute(); }