diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index d2caabd..4c75cb3 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -20,8 +20,26 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -65,32 +83,38 @@
- {
- "keyToString": {
- "ASKED_ADD_EXTERNAL_FILES": "true",
- "RunOnceActivity.OpenProjectViewOnStart": "true",
- "RunOnceActivity.ShowReadmeOnStart": "true",
- "RunOnceActivity.cidr.known.project.marker": "true",
- "SHARE_PROJECT_CONFIGURATION_FILES": "true",
- "WebServerToolWindowFactoryState": "false",
- "cf.first.check.clang-format": "false",
- "cidr.known.project.marker": "true",
- "last_opened_file_path": "C:/Users/RUPC/Desktop/UV-K6/uv-k5-firmware-chinese",
- "node.js.detected.package.eslint": "true",
- "node.js.detected.package.tslint": "true",
- "node.js.selected.package.eslint": "(autodetect)",
- "node.js.selected.package.tslint": "(autodetect)",
- "nodejs_package_manager_path": "npm",
- "settings.editor.selected.configurable": "File.Encoding",
- "vue.rearranger.settings.migration": "true"
+
+}]]>
+
+
+
+
+
+
@@ -125,7 +149,7 @@
-
+
1701136012311
@@ -267,7 +291,14 @@
1701562094909
-
+
+ 1701563372624
+
+
+
+ 1701563372624
+
+
@@ -291,6 +322,7 @@
-
+
+
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 912475f..717986f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -816,4 +816,4 @@ add_executable(uv_k5_firmware_custom_0_17
sram-overlay.c
sram-overlay.h
version.c
- version.h chinese.h)
+ version.h chinese.h app/mdc1200.c app/mdc1200.c)
diff --git a/Makefile b/Makefile
index 6381f47..1a761df 100644
--- a/Makefile
+++ b/Makefile
@@ -45,6 +45,10 @@ ENABLE_REDUCE_LOW_MID_TX_POWER:= 0
ENABLE_BYP_RAW_DEMODULATORS := 0
ENABLE_BLMIN_TMP_OFF := 0
ENABLE_SCAN_RANGES := 1
+ENABLE_MDC1200 := 1
+ENABLE_MDC1200_SHOW_OP_ARG := 1
+ENABLE_MDC1200_SIDE_BEEP := 1
+
#############################################################
@@ -72,7 +76,9 @@ ifeq ($(ENABLE_OVERLAY),1)
OBJS += sram-overlay.o
endif
OBJS += external/printf/printf.o
-
+ifeq ($(ENABLE_MDC1200),1)
+ OBJS += app/mdc1200.o
+endif
# Drivers
OBJS += driver/adc.o
ifeq ($(ENABLE_UART),1)
@@ -233,7 +239,15 @@ else
# We get most of the space savings if LTO creates problems
CFLAGS += -ffunction-sections -fdata-sections
endif
-
+ifeq ($(ENABLE_MDC1200),1)
+ CFLAGS += -DENABLE_MDC1200
+endif
+ifeq ($(ENABLE_MDC1200_SHOW_OP_ARG),1)
+ CFLAGS += -DENABLE_MDC1200_SHOW_OP_ARG
+endif
+ifeq ($(ENABLE_MDC1200_SIDE_BEEP),1)
+ CFLAGS += -DENABLE_MDC1200_SIDE_BEEP
+endif
# May cause unhelpful build failures
#CFLAGS += -Wpadded
diff --git a/app/app.c b/app/app.c
index 93f9c52..2797584 100644
--- a/app/app.c
+++ b/app/app.c
@@ -446,6 +446,7 @@ static void HandleFunction(void)
void APP_StartListening(FUNCTION_Type_t Function, const bool reset_am_fix)
{
+ (void)reset_am_fix;
const unsigned int chan = gEeprom.RX_VFO;
// const unsigned int chan = gRxVfo->CHANNEL_SAVE;
@@ -498,31 +499,13 @@ void APP_StartListening(FUNCTION_Type_t Function, const bool reset_am_fix)
gUpdateStatus = true;
}
- { // RF RX front end gain
- // original QS front end register settings
- // 0x03BE 00000 011 101 11 110
- const uint8_t orig_lna_short = 3; // 0dB
- const uint8_t orig_lna = 5; // -4dB
- const uint8_t orig_mixer = 3; // 0dB
- const uint8_t orig_pga = 6; // -3dB
-
#ifdef ENABLE_AM_FIX
- BK4819_SetAGC(gRxVfo->Modulation != MODULATION_AM || !gSetting_AM_fix);
-
-
if (gRxVfo->Modulation == MODULATION_AM && gSetting_AM_fix) { // AM RX mode
if (reset_am_fix)
AM_fix_reset(chan); // TODO: only reset it when moving channel/frequency
AM_fix_10ms(chan);
}
- else { // FM RX mode
- BK4819_WriteRegister(BK4819_REG_13, (orig_lna_short << 8) | (orig_lna << 5) | (orig_mixer << 3) | (orig_pga << 0));
- }
-#else
- (void)reset_am_fix;
- BK4819_WriteRegister(BK4819_REG_13, (orig_lna_short << 8) | (orig_lna << 5) | (orig_mixer << 3) | (orig_pga << 0));
#endif
- }
// AF gain - original QS values
// if (gRxVfo->Modulation != MODULATION_FM){
diff --git a/app/mdc1200.c b/app/mdc1200.c
new file mode 100644
index 0000000..e76754a
--- /dev/null
+++ b/app/mdc1200.c
@@ -0,0 +1,562 @@
+
+#include "driver/bk4819.h"
+#include "driver/crc.h"
+
+#include "mdc1200.h"
+#include "misc.h"
+#include
+
+
+const uint8_t mdc1200_pre_amble[] = {0x00, 0x00, 0x00};
+const uint8_t mdc1200_sync[5] = {0x07, 0x09, 0x2a, 0x44, 0x6f};
+
+uint8_t mdc1200_sync_suc_xor[sizeof(mdc1200_sync)];
+
+
+#if 1
+
+uint16_t compute_crc(const void *data, const unsigned int data_len)
+{ // let the CPU's hardware do some work :)
+ uint16_t crc;
+ CRC_InitReverse();
+ crc = CRC_Calculate(data, data_len);
+ CRC_Init();
+ return crc;
+}
+
+#elif 1
+
+uint16_t compute_crc(const void *data, const unsigned int data_len)
+ { // using the reverse computation and polynominal avoids having to reverse the bit order during and after
+ unsigned int i;
+ const uint8_t *data8 = (const uint8_t *)data;
+ uint16_t crc = 0;
+ for (i = 0; i < data_len; i++)
+ {
+ unsigned int k;
+ crc ^= data8[i];
+ for (k = 8; k > 0; k--)
+ crc = (crc & 1u) ? (crc >> 1) ^ 0x8408 : crc >> 1;
+ }
+ return crc ^ 0xffff;
+ }
+
+#else
+
+ uint16_t compute_crc(const void *data, const unsigned int data_len)
+ {
+ unsigned int i;
+ const uint8_t *data8 = (const uint8_t *)data;
+ uint16_t crc = 0;
+
+ for (i = 0; i < data_len; i++)
+ {
+ uint8_t mask;
+
+ // bit reverse each data byte
+ const uint8_t bits = bit_reverse_8(*data8++);
+
+ for (mask = 0x0080; mask != 0; mask >>= 1)
+ {
+ uint16_t msb = crc & 0x8000;
+ if (bits & mask)
+ msb ^= 0x8000;
+ crc <<= 1;
+ if (msb)
+ crc ^= 0x1021;
+ }
+ }
+
+ // bit reverse and invert the final CRC
+ return bit_reverse_16(crc) ^ 0xffff;
+ }
+
+#endif
+
+void error_correction(void *data)
+{ // can correct up to 3 or 4 corrupted bits (I think)
+
+ int i;
+ uint8_t shift_reg;
+ uint8_t syn;
+ uint8_t *data8 = (uint8_t *)data;
+
+ for (i = 0, shift_reg = 0, syn = 0; i < MDC1200_FEC_K; i++)
+ {
+ const uint8_t bi = data8[i];
+ int bit_num;
+ for (bit_num = 0; bit_num < 8; bit_num++)
+ {
+ uint8_t b;
+ unsigned int k = 0;
+
+ shift_reg = (shift_reg << 1) | ((bi >> bit_num) & 1u);
+ b = ((shift_reg >> 6) ^ (shift_reg >> 5) ^ (shift_reg >> 2) ^ (shift_reg >> 0)) & 1u;
+ syn = (syn << 1) | (((b ^ (data8[i + MDC1200_FEC_K] >> bit_num)) & 1u) ? 1u : 0u);
+
+ if (syn & 0x80) k++;
+ if (syn & 0x20) k++;
+ if (syn & 0x04) k++;
+ if (syn & 0x02) k++;
+
+ if (k >= 3)
+ { // correct a bit error
+ int ii = i;
+ int bn = bit_num - 7;
+ if (bn < 0)
+ {
+ bn += 8;
+ ii--;
+ }
+ if (ii >= 0)
+ data8[ii] ^= 1u << bn; // fix a bit
+ syn ^= 0xA6; // 10100110
+ }
+ }
+ }
+}
+
+bool decode_data(void *data)
+{
+ uint16_t crc1;
+ uint16_t crc2;
+ uint8_t *data8 = (uint8_t *)data;
+
+ { // de-interleave
+
+ unsigned int i;
+ unsigned int k;
+ unsigned int m;
+ uint8_t deinterleaved[(MDC1200_FEC_K * 2) * 8]; // temp individual bit storage
+
+ // interleave order
+ // 0, 16, 32, 48, 64, 80, 96,
+ // 1, 17, 33, 49, 65, 81, 97,
+ // 2, 18, 34, 50, 66, 82, 98,
+ // 3, 19, 35, 51, 67, 83, 99,
+ // 4, 20, 36, 52, 68, 84, 100,
+ // 5, 21, 37, 53, 69, 85, 101,
+ // 6, 22, 38, 54, 70, 86, 102,
+ // 7, 23, 39, 55, 71, 87, 103,
+ // 8, 24, 40, 56, 72, 88, 104,
+ // 9, 25, 41, 57, 73, 89, 105,
+ // 10, 26, 42, 58, 74, 90, 106,
+ // 11, 27, 43, 59, 75, 91, 107,
+ // 12, 28, 44, 60, 76, 92, 108,
+ // 13, 29, 45, 61, 77, 93, 109,
+ // 14, 30, 46, 62, 78, 94, 110,
+ // 15, 31, 47, 63, 79, 95, 111
+
+ // de-interleave the received bits
+ for (i = 0, k = 0; i < 16; i++)
+ {
+ for (m = 0; m < MDC1200_FEC_K; m++)
+ {
+ const unsigned int n = (m * 16) + i;
+ deinterleaved[k++] = (data8[n >> 3] >> ((7 - n) & 7u)) & 1u;
+ }
+ }
+
+ // copy the de-interleaved bits back into the data buffer
+ for (i = 0, m = 0; i < (MDC1200_FEC_K * 2); i++)
+ {
+ unsigned int k;
+ uint8_t b = 0;
+ for (k = 0; k < 8; k++)
+ if (deinterleaved[m++])
+ b |= 1u << k;
+ data8[i] = b;
+ }
+ }
+
+ // try to correct the odd corrupted bit
+ error_correction(data);
+
+ // rx'ed de-interleaved data (min 14 bytes) looks like this ..
+ //
+ // OP ARG ID CRC STATUS FEC bits
+ // 01 80 1234 2E3E 00 6580A862DD8808
+
+ crc1 = compute_crc(data, 4);
+ crc2 = ((uint16_t)data8[5] << 8) | (data8[4] << 0);
+
+ return (crc1 == crc2) ? true : false;
+}
+
+// **********************************************************
+// TX
+
+void xor_modulation(void *data, const unsigned int size)
+{ // exclusive-or succesive bits - the entire packet
+ unsigned int i;
+ uint8_t *data8 = (uint8_t *)data;
+ uint8_t prev_bit = 0;
+ for (i = 0; i < size; i++)
+ {
+ int bit_num;
+ uint8_t in = data8[i];
+ uint8_t out = 0;
+ for (bit_num = 7; bit_num >= 0; bit_num--)
+ {
+ const uint8_t new_bit = (in >> bit_num) & 1u;
+ if (new_bit != prev_bit)
+ out |= 1u << bit_num; // previous bit and new bit are different - send a '1'
+ prev_bit = new_bit;
+ }
+ data8[i] = out ^ 0xff;
+ }
+}
+
+uint8_t * encode_data(void *data)
+{
+ // R=1/2 K=7 convolutional coder
+ //
+ // OP ARG ID CRC STATUS FEC bits
+ // 01 80 1234 2E3E 00 6580A862DD8808
+ //
+ // 1. reverse the bit order for each byte of the first 7 bytes (to undo the reversal performed for display, above)
+ // 2. feed those bits into a shift register which is preloaded with all zeros
+ // 3. for each bit, calculate the modulo-2 sum: bit(n-0) + bit(n-2) + bit(n-5) + bit(n-6)
+ // 4. then for each byte of resulting output, again reverse those bits to generate the values shown above
+
+ uint8_t *data8 = (uint8_t *)data;
+
+ { // add the FEC bits to the end of the data
+ unsigned int i;
+ uint8_t shift_reg = 0;
+ for (i = 0; i < MDC1200_FEC_K; i++)
+ {
+ unsigned int bit_num;
+ const uint8_t bi = data8[i];
+ uint8_t bo = 0;
+ for (bit_num = 0; bit_num < 8; bit_num++)
+ {
+ shift_reg = (shift_reg << 1) | ((bi >> bit_num) & 1u);
+ bo |= (((shift_reg >> 6) ^ (shift_reg >> 5) ^ (shift_reg >> 2) ^ (shift_reg >> 0)) & 1u) << bit_num;
+ }
+ data8[MDC1200_FEC_K + i] = bo;
+ }
+ }
+
+
+ { // interleave the bits
+
+ unsigned int i;
+ unsigned int k;
+ uint8_t interleaved[(MDC1200_FEC_K * 2) * 8]; // temp individual bit storage
+
+ // interleave order
+ // 0, 16, 32, 48, 64, 80, 96,
+ // 1, 17, 33, 49, 65, 81, 97,
+ // 2, 18, 34, 50, 66, 82, 98,
+ // 3, 19, 35, 51, 67, 83, 99,
+ // 4, 20, 36, 52, 68, 84, 100,
+ // 5, 21, 37, 53, 69, 85, 101,
+ // 6, 22, 38, 54, 70, 86, 102,
+ // 7, 23, 39, 55, 71, 87, 103,
+ // 8, 24, 40, 56, 72, 88, 104,
+ // 9, 25, 41, 57, 73, 89, 105,
+ // 10, 26, 42, 58, 74, 90, 106,
+ // 11, 27, 43, 59, 75, 91, 107,
+ // 12, 28, 44, 60, 76, 92, 108,
+ // 13, 29, 45, 61, 77, 93, 109,
+ // 14, 30, 46, 62, 78, 94, 110,
+ // 15, 31, 47, 63, 79, 95, 111
+
+ // bit interleaver
+ for (i = 0, k = 0; i < (MDC1200_FEC_K * 2); i++)
+ {
+ unsigned int bit_num;
+ const uint8_t b = data8[i];
+ for (bit_num = 0; bit_num < 8; bit_num++)
+ {
+ interleaved[k] = (b >> bit_num) & 1u;
+ k += 16;
+ if (k >= sizeof(interleaved))
+ k -= sizeof(interleaved) - 1;
+ }
+ }
+
+ // copy the interleaved bits back to the data buffer
+ for (i = 0, k = 0; i < (MDC1200_FEC_K * 2); i++)
+ {
+ int bit_num;
+ uint8_t b = 0;
+ for (bit_num = 7; bit_num >= 0; bit_num--)
+ if (interleaved[k++])
+ b |= 1u << bit_num;
+ data8[i] = b;
+ }
+ }
+
+ return data8 + (MDC1200_FEC_K * 2);
+}
+
+unsigned int MDC1200_encode_single_packet(void *data, const uint8_t op, const uint8_t arg, const uint16_t unit_id)
+{
+ unsigned int size;
+ uint16_t crc;
+ uint8_t *p = (uint8_t *)data;
+
+ memcpy(p, mdc1200_pre_amble, sizeof(mdc1200_pre_amble));
+ p += sizeof(mdc1200_pre_amble);
+ memcpy(p, mdc1200_sync, sizeof(mdc1200_sync));
+ p += sizeof(mdc1200_sync);
+
+ p[0] = op;
+ p[1] = arg;
+ p[2] = (unit_id >> 8) & 0x00ff;
+ p[3] = (unit_id >> 0) & 0x00ff;
+ crc = compute_crc(p, 4);
+ p[4] = (crc >> 0) & 0x00ff;
+ p[5] = (crc >> 8) & 0x00ff;
+ p[6] = 0; // unknown field (00 for PTTIDs, 76 for STS and MSG)
+
+ p = encode_data(p);
+
+ size = (unsigned int)(p - (uint8_t *)data);
+
+ xor_modulation(data, size);
+
+ return size;
+}
+
+
+struct {
+ uint8_t bit;
+ uint8_t prev_bit;
+ uint8_t xor_bit;
+ uint64_t shift_reg;
+ unsigned int bit_count;
+ unsigned int stage;
+ bool inverted_sync;
+ unsigned int data_index;
+ uint8_t data[40];
+} rx;
+
+void MDC1200_reset_rx(void)
+{
+ memset(&rx, 0, sizeof(rx));
+}
+
+bool MDC1200_process_rx_data(
+ const void *buffer,
+ const unsigned int size,
+ //const bool inverted,
+ uint8_t *op,
+ uint8_t *arg,
+ uint16_t *unit_id)
+{
+ const uint8_t *buffer8 = (const uint8_t *)buffer;
+ unsigned int index;
+
+ // 04 8D BF 66 58 sync
+ // FB 72 40 99 A7 inverted sync
+ //
+ // 04 8D BF 66 58 40 C4 B0 32 BA F9 33 18 35 08 83 F6 0C 36 .. 80 87 20 23 2C AE 22 10 26 0F 02 A4 08 24
+ // 04 8D BF 66 58 45 DB 03 07 BC FA 35 2E 33 0E 83 0E 83 69 .. 86 92 02 05 28 AC 26 34 22 0B 02 0B 02 4E
+
+ memset(&rx, 0, sizeof(rx));
+
+ for (index = 0; index < size; index++)
+ {
+ int bit;
+ const uint8_t rx_byte = buffer8[index];
+
+ for (bit = 7; bit >= 0; bit--)
+ {
+ unsigned int i;
+
+ rx.prev_bit = rx.bit;
+
+ rx.bit = (rx_byte >> bit) & 1u;
+
+ rx.xor_bit = (rx.xor_bit ^ rx.bit) & 1u; // toggle our bit if the rx bit is high
+
+ rx.shift_reg = (rx.shift_reg << 1) | rx.xor_bit;
+ rx.bit_count++;
+
+ // *********
+
+ if (rx.stage == 0)
+ { // looking for the 40-bit sync pattern
+
+ const unsigned int sync_bit_ok_threshold = 32;
+
+ if (rx.bit_count >= 40)
+ {
+ // 40-bit sync pattern
+ uint64_t sync_nor = 0x07092a446fu; // normal
+ uint64_t sync_inv = 0xffffffffffu ^ sync_nor; // bit inverted
+
+ sync_nor ^= rx.shift_reg;
+ sync_inv ^= rx.shift_reg;
+
+ unsigned int nor_count = 0;
+ unsigned int inv_count = 0;
+ for (i = 40; i > 0; i--, sync_nor >>= 1, sync_inv >>= 1)
+ {
+ nor_count += sync_nor & 1u;
+ inv_count += sync_inv & 1u;
+ }
+ nor_count = 40 - nor_count;
+ inv_count = 40 - inv_count;
+
+
+
+ if (nor_count >= sync_bit_ok_threshold || inv_count >= sync_bit_ok_threshold)
+ { // good enough
+
+ rx.inverted_sync = (inv_count > nor_count) ? true : false;
+ rx.data_index = 0;
+ rx.bit_count = 0;
+ rx.stage = 1;
+
+
+ }
+ }
+
+ continue;
+ }
+
+ if (rx.bit_count < 8)
+ continue;
+
+ rx.bit_count = 0;
+
+ rx.data[rx.data_index++] = rx.shift_reg & 0xff; // save the last 8 bits
+
+ if (rx.data_index < (MDC1200_FEC_K * 2))
+ continue;
+
+
+
+ if (!decode_data(rx.data))
+ {
+ MDC1200_reset_rx();
+
+
+
+ continue;
+ }
+
+ // extract the info from the packet
+ *op = rx.data[0];
+ *arg = rx.data[1];
+ *unit_id = ((uint16_t)rx.data[2] << 8) | (rx.data[3] << 0);
+
+
+ // reset the detector
+ MDC1200_reset_rx();
+
+ return true;
+ }
+ }
+
+ MDC1200_reset_rx();
+
+ return false;
+}
+
+uint8_t mdc1200_rx_buffer[sizeof(mdc1200_sync_suc_xor) + (MDC1200_FEC_K * 2)];
+unsigned int mdc1200_rx_buffer_index = 0;
+
+uint8_t mdc1200_op;
+uint8_t mdc1200_arg;
+uint16_t mdc1200_unit_id;
+uint8_t mdc1200_rx_ready_tick_500ms;
+
+void MDC1200_process_rx(const uint16_t interrupt_bits)
+{
+ const uint16_t rx_sync_flags = BK4819_ReadRegister(0x0B);
+ const uint16_t fsk_reg59 = BK4819_ReadRegister(0x59) & ~((1u << 15) | (1u << 14) | (1u << 12) | (1u << 11));
+
+ const bool rx_sync = (interrupt_bits & BK4819_REG_02_FSK_RX_SYNC) ? true : false;
+ const bool rx_sync_neg = (rx_sync_flags & (1u << 7)) ? true : false;
+ const bool rx_fifo_almost_full = (interrupt_bits & BK4819_REG_02_FSK_FIFO_ALMOST_FULL) ? true : false;
+ const bool rx_finished = (interrupt_bits & BK4819_REG_02_FSK_RX_FINISHED) ? true : false;
+
+
+ if (rx_sync)
+ {
+
+ mdc1200_rx_buffer_index = 0;
+
+ {
+ unsigned int i;
+ memset(mdc1200_rx_buffer, 0, sizeof(mdc1200_rx_buffer));
+ for (i = 0; i < sizeof(mdc1200_sync_suc_xor); i++)
+ mdc1200_rx_buffer[mdc1200_rx_buffer_index++] = mdc1200_sync_suc_xor[i] ^ (rx_sync_neg ? 0xFF : 0x00);
+ }
+
+
+
+
+
+
+ }
+
+ if (rx_fifo_almost_full)
+ {
+ unsigned int i;
+ const unsigned int count = BK4819_ReadRegister(0x5E) & (7u << 0); // almost full threshold
+
+
+ // fetch received packet data
+ for (i = 0; i < count; i++)
+ {
+ const uint16_t word = BK4819_ReadRegister(0x5F) ^ (rx_sync_neg ? 0xFFFF : 0x0000);
+
+
+
+ if (mdc1200_rx_buffer_index < sizeof(mdc1200_rx_buffer))
+ mdc1200_rx_buffer[mdc1200_rx_buffer_index++] = (word >> 0) & 0xff;
+
+ if (mdc1200_rx_buffer_index < sizeof(mdc1200_rx_buffer))
+ mdc1200_rx_buffer[mdc1200_rx_buffer_index++] = (word >> 8) & 0xff;
+ }
+
+
+ if (mdc1200_rx_buffer_index >= sizeof(mdc1200_rx_buffer))
+ {
+ BK4819_WriteRegister(0x59, (1u << 15) | (1u << 14) | fsk_reg59);
+ BK4819_WriteRegister(0x59, (1u << 12) | fsk_reg59);
+
+
+ if (MDC1200_process_rx_data(
+ mdc1200_rx_buffer,
+ mdc1200_rx_buffer_index,
+ &mdc1200_op,
+ &mdc1200_arg,
+ &mdc1200_unit_id)) {
+ mdc1200_rx_ready_tick_500ms = 2 * 6; // 6 second MDC display time
+
+ gUpdateDisplay = true;
+
+ }
+
+ mdc1200_rx_buffer_index = 0;
+ }
+ }
+
+ if (rx_finished)
+ {
+ mdc1200_rx_buffer_index = 0;
+
+
+ BK4819_WriteRegister(0x59, (1u << 15) | (1u << 14) | fsk_reg59);
+ BK4819_WriteRegister(0x59, (1u << 12) | fsk_reg59);
+
+
+ }
+}
+
+
+
+void MDC1200_init(void)
+{
+ memcpy(mdc1200_sync_suc_xor, mdc1200_sync, sizeof(mdc1200_sync));
+ xor_modulation(mdc1200_sync_suc_xor, sizeof(mdc1200_sync_suc_xor));
+
+ MDC1200_reset_rx();
+}
diff --git a/app/mdc1200.h b/app/mdc1200.h
new file mode 100644
index 0000000..3f9d5e8
--- /dev/null
+++ b/app/mdc1200.h
@@ -0,0 +1,106 @@
+
+#ifndef MDC1200H
+#define MDC1200H
+
+#include
+#include
+
+#define MDC1200_FEC_K 7 // R=1/2 K=7 convolutional coder
+
+// 0x00 (0x81) emergency alarm
+// 0x20 (0x00) emergency alarm ack
+//
+// 0x01 (0x80) is PTT ID
+// 0x01 (0x00) is POST ID
+// 0x11 (0x8A) is REMOTE MONITOR
+// 0x22 (0x06) is STATUS REQ
+// 0x2B (0x0C) is RADIO ENABLE
+// 0x2B (0x00) is RADIO DISABLE
+// 0x35 (0x89) is CALL ALERT
+// 0x46 (0xXX) is STS XX
+// 0x47 (0xXX) is MSG XX
+//
+// 0x63 (0x85) is RADIO CHECK
+// 0x30 (0x00) is RADIO CHECK ack
+//
+// * CALL ALERT [Double packet - 2 codewords, 1234 places call to 5678]
+// 3589 5678 830D 1234 [Spectra, Astro Saber "PAGE", Maxtrac "CA" w/Ack Expected=Y]
+// 3589 5678 810D 1234 [Maxtrac "CA" w/Ack Expected=N]
+//
+// * VOICE SELECTIVE CALL [Double packet - 2 codewords, 1234 places call to 5678]
+// 3589 5678 8205 1234 [Spectra "CALL"]
+// 3589 5678 8015 1234 [Maxtrac "SC", Astro Saber "CALL"]
+//
+// * CALL ALERT ACKNOWLEDGE [Double packet - 2 codewords, 5678 acks the call from 1234]
+// 3589 1234 A000 5678
+//
+// * SIMPLE STATUS [unit 1234 transmits status number X]
+// 460X 1234
+//
+// * STATUS ACKNOWLEDGE
+// 2300 1234
+//
+// * STATUS REQUEST [i.e. unit 5678 report your last status]
+// 2206 5678
+//
+// * STATUS RESPONSE [from target 5678 when interrogated]
+// 060X 5678
+//
+// * INBOUND MESSAGE
+// 470X 1234 [ack expected]
+// 070X 1234 [ack not expected CDM1550]
+//
+// * INBOUND MESSAGE ACKNOWLEDGE
+// 2300 1234
+//
+// * REMOTE MONITOR [No MDC response from target unless it has PTT ID]
+// 118A 5678 [118A per KA6SQG]
+//
+// * SELECTIVE RADIO INHIBIT [Fixed end inhibits target 5678]
+// 2B00 5678
+//
+// * SELECTIVE RADIO INHIBIT ACKNOWLEDGE [5678 acks the inhibit]
+// 0B00 5678
+//
+// * SELECTIVE RADIO INHIBIT CANCEL [Fixed end enables target 5678]
+// 2B0C 5678
+//
+// * SELECTIVE RADIO INHIBIT CANCEL [5678 acks the enable]
+// 0B0C 5678
+//
+// * REQUEST TO TALK [Unit 1234 asks fixed end for permission to PTT]
+// 4001 1234 [CDM1550 dedicated button]
+// 4101 1234 [CDM1550 slaved to mic PTT]
+//
+// * REQUEST TO TALK ACKNOWLEDGE
+// 2300 1234 [general ack - not same as permission to PTT]
+
+enum mdc1200_op_code_e {
+ MDC1200_OP_CODE_PTT_ID = 0x01,
+ MDC1200_OP_CODE_POST_ID = 0x01,
+ MDC1200_OP_CODE_REMOTE_MONITOR = 0x11,
+ MDC1200_OP_CODE_STATUS_REQ = 0x22,
+ MDC1200_OP_CODE_RADIO_ENABLE = 0x2B,
+ MDC1200_OP_CODE_RADIO_DISABLE = 0x2B,
+ MDC1200_OP_CODE_CALL_ALERT = 0x35,
+ MDC1200_OP_CODE_STS_XX = 0x46,
+ MDC1200_OP_CODE_MSG_XX = 0x47,
+ MDC1200_OP_CODE_RADIO_CHECK = 0x63
+};
+typedef enum mdc1200_op_code_e mdc1200_op_code_t;
+
+extern const uint8_t mdc1200_sync[5];
+extern uint8_t mdc1200_sync_suc_xor[sizeof(mdc1200_sync)];
+
+extern uint8_t mdc1200_op;
+extern uint8_t mdc1200_arg;
+extern uint16_t mdc1200_unit_id;
+extern uint8_t mdc1200_rx_ready_tick_500ms;
+
+unsigned int MDC1200_encode_single_packet(void *data, const uint8_t op, const uint8_t arg, const uint16_t unit_id);
+//unsigned int MDC1200_encode_double_packet(void *data, const uint8_t op, const uint8_t arg, const uint16_t unit_id, const uint8_t b0, const uint8_t b1, const uint8_t b2, const uint8_t b3);
+void MDC1200_reset_rx(void);
+void MDC1200_process_rx(const uint16_t interrupt_bits);
+void MDC1200_init(void);
+
+#endif
diff --git a/app/spectrum.c b/app/spectrum.c
index eaeb848..d8ac734 100644
--- a/app/spectrum.c
+++ b/app/spectrum.c
@@ -18,6 +18,8 @@
#include "driver/backlight.h"
#include "audio.h"
#include "ui/helper.h"
+#include "am_fix.h"
+#include "ui/main.h"
struct FrequencyBandInfo {
uint32_t lower;
@@ -30,6 +32,7 @@ struct FrequencyBandInfo {
const uint16_t RSSI_MAX_VALUE = 65535;
+
static uint16_t R30, R37, R3D, R43, R47, R48, R7E;
static uint32_t initialFreq;
static char String[32];
@@ -68,7 +71,7 @@ SpectrumSettings settings = {stepsCount: STEPS_64,
uint32_t fMeasure = 0;
uint32_t currentFreq, tempFreq;
uint16_t rssiHistory[128];
-
+int vfo;
uint8_t freqInputIndex = 0;
uint8_t freqInputDotIndex = 0;
KEY_Code_t freqInputArr[10];
@@ -99,7 +102,10 @@ static uint8_t DBm2S(int dbm) {
return i;
}
-static int Rssi2DBm(uint16_t rssi) { return (rssi >> 1) - 160; }
+static int Rssi2DBm(uint16_t rssi)
+{
+ return (rssi / 2) - 160 + dBmCorrTable[gRxVfo->Band];
+}
static uint16_t GetRegMenuValue(uint8_t st) {
RegisterSpec s = registerSpecs[st];
@@ -276,7 +282,15 @@ uint16_t GetRssi() {
while ((BK4819_ReadRegister(0x63) & 0b11111111) >= 255) {
SYSTICK_DelayUs(100);
}
- return BK4819_GetRSSI();
+ if(settings.modulationType == MODULATION_AM)
+ {
+ return BK4819_GetRSSI() - rssi_gain_diff[vfo]; //return the corrected RSSI to allow for AM_Fixs AGC action.
+ }
+ else
+ {
+ return BK4819_GetRSSI();
+ }
+
}
static void ToggleAudio(bool on) {
@@ -383,7 +397,7 @@ static void Measure() { rssiHistory[scanInfo.i] = scanInfo.rssi = GetRssi(); }
static uint16_t dbm2rssi(int dBm)
{
- return (dBm + 160)*2;
+ return (dBm + 160 - dBmCorrTable[gRxVfo->Band])*2;
}
static void ClampRssiTriggerLevel()
@@ -475,6 +489,7 @@ static void ToggleModulation() {
settings.modulationType = MODULATION_FM;
}
RADIO_SetModulation(settings.modulationType);
+ RelaunchScan();
redrawScreen = true;
}
@@ -588,7 +603,7 @@ uint8_t Rssi2PX(uint16_t rssi, uint8_t pxMin, uint8_t pxMax) {
const uint8_t PX_RANGE = pxMax - pxMin;
- int dbm = clamp(rssi - (160 << 1), DB_MIN, DB_MAX);
+ int dbm = clamp(Rssi2DBm(rssi) << 1, DB_MIN, DB_MAX);
return ((dbm - DB_MIN) * PX_RANGE + DB_RANGE / 2) / DB_RANGE + pxMin;
}
@@ -1104,6 +1119,11 @@ static void UpdateListening() {
}
static void Tick() {
+
+ if(settings.modulationType == MODULATION_AM)
+ {
+ AM_fix_10ms(vfo); //allow AM_Fix to apply its AGC action
+ }
if (!preventKeypress) {
HandleUserInput();
}
@@ -1133,8 +1153,9 @@ static void Tick() {
void APP_RunSpectrum() {
// TX here coz it always? set to active VFO
- currentFreq = initialFreq =
- gEeprom.VfoInfo[gEeprom.TX_VFO].pRX->Frequency;
+ vfo = gEeprom.TX_VFO;
+ //set the current frequency in the middle of the display
+ currentFreq = initialFreq = gEeprom.VfoInfo[vfo].pRX->Frequency - ((GetStepsCount()/2) * GetScanStep());
BackupRegisters();
@@ -1144,7 +1165,7 @@ void APP_RunSpectrum() {
newScanStart = true;
ToggleRX(true), ToggleRX(false); // hack to prevent noise when squelch off
- RADIO_SetModulation(settings.modulationType = MODULATION_FM);
+ RADIO_SetModulation(settings.modulationType = gRxVfo->Modulation);
BK4819_SetFilterBandwidth(settings.listenBw = BK4819_FILTER_BW_WIDE, false);
RelaunchScan();
diff --git a/audio.c b/audio.c
index e865fdc..66a48f8 100644
--- a/audio.c
+++ b/audio.c
@@ -192,7 +192,9 @@ void AUDIO_PlayBeep(BEEP_Type_t Beep)
#endif
SYSTEM_DelayMs(5);
- BK4819_TurnsOffTones_TurnsOnRX();
+ //stop tone
+ //BK4819_TurnsOffTones_TurnsOnRX();
+ BK4819_stop_tones(false);
SYSTEM_DelayMs(5);
BK4819_WriteRegister(BK4819_REG_71, ToneConfig);
diff --git a/cmake-build-debug/CMakeFiles/clion-Debug-log.txt b/cmake-build-debug/CMakeFiles/clion-Debug-log.txt
index c48853a..2594228 100644
--- a/cmake-build-debug/CMakeFiles/clion-Debug-log.txt
+++ b/cmake-build-debug/CMakeFiles/clion-Debug-log.txt
@@ -1,4 +1,13 @@
"C:\Program Files\JetBrains\CLion 2023.1.1\bin\cmake\win\x64\bin\cmake.exe" -DCMAKE_BUILD_TYPE=Debug -DCMAKE_MAKE_PROGRAM=C:/Qt/Qt5.13.1/Tools/mingw730_64/bin/mingw32-make.exe -DCMAKE_C_COMPILER=C:/Qt/Qt5.13.1/Tools/mingw730_64/bin/gcc.exe -DCMAKE_CXX_COMPILER=C:/Qt/Qt5.13.1/Tools/mingw730_64/bin/g++.exe -G "CodeBlocks - MinGW Makefiles" -S C:\Users\RUPC\Desktop\UV-K6\uv-k5-firmware-chinese -B C:\Users\RUPC\Desktop\UV-K6\uv-k5-firmware-chinese\cmake-build-debug
-- Configuring done
--- Generating done
--- Build files have been written to: C:/Users/RUPC/Desktop/UV-K6/uv-k5-firmware-chinese/cmake-build-debug
+CMake Error at CMakeLists.txt:122 (add_executable):
+ Cannot find source file:
+
+ external/CMSIS_5/CMSIS/DAP/Firmware/Config/DAP_config.h
+
+
+CMake Error at CMakeLists.txt:122 (add_executable):
+ No SOURCES given to target: uv_k5_firmware_custom_0_17
+
+
+CMake Generate step failed. Build files cannot be regenerated correctly.
diff --git a/driver/bk4819.c b/driver/bk4819.c
index 3559d72..d52ec01 100644
--- a/driver/bk4819.c
+++ b/driver/bk4819.c
@@ -23,10 +23,13 @@
#include "driver/gpio.h"
#include "driver/system.h"
#include "driver/systick.h"
-
+#ifdef ENABLE_MDC1200
+#include "app/mdc1200.h"
+#endif
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
#endif
+BK4819_FilterBandwidth_t m_bandwidth = BK4819_FILTER_BW_NARROW;
static const uint16_t FSK_RogerTable[7] = {0xF1A2, 0x7446, 0x61A4, 0x6544, 0x4E8A, 0xE044, 0xEA84};
@@ -164,6 +167,7 @@ uint16_t BK4819_ReadRegister(BK4819_REGISTER_t Register)
GPIO_SetBit(&GPIOC->DATA, GPIOC_PIN_BK4819_SDA);
return Value;
+
}
void BK4819_WriteRegister(BK4819_REGISTER_t Register, uint16_t Data)
@@ -562,6 +566,7 @@ void BK4819_SetFilterBandwidth(const BK4819_FilterBandwidth_t Bandwidth, const b
// <1:0> 0 ???
uint16_t val;
+ m_bandwidth = Bandwidth;
switch (Bandwidth)
{
@@ -1772,4 +1777,642 @@ void BK4819_PlayDTMFEx(bool bLocalLoopback, char Code)
BK4819_PlayDTMF(Code);
BK4819_ExitTxMute();
-}
\ No newline at end of file
+}
+//ENABLE_MDC1200
+#define h
+#ifdef h
+void BK4819_start_tone(const uint16_t frequency, const unsigned int level, const bool tx, const bool tx_mute)
+{
+ SYSTEM_DelayMs(1);
+
+ GPIO_ClearBit(&GPIOC->DATA, 4);
+
+ SYSTEM_DelayMs(1);
+
+ // mute TX
+ BK4819_WriteRegister(0x50, (1u << 15) | 0x3B20);
+
+ BK4819_WriteRegister(0x70, BK4819_REG_70_ENABLE_TONE1 | ((level & 0x7f) << BK4819_REG_70_SHIFT_TONE1_TUNING_GAIN));
+
+ BK4819_WriteRegister(0x30, 0);
+
+ if (!tx)
+ {
+ BK4819_WriteRegister(0x30,
+// BK4819_REG_30_ENABLE_VCO_CALIB |
+// BK4819_REG_30_ENABLE_UNKNOWN |
+// 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_PA_GAIN |
+// BK4819_REG_30_ENABLE_MIC_ADC |
+ BK4819_REG_30_ENABLE_TX_DSP |
+// BK4819_REG_30_ENABLE_RX_DSP |
+ 0);
+ }
+ else
+ {
+ BK4819_WriteRegister(0x30,
+ BK4819_REG_30_ENABLE_VCO_CALIB |
+ BK4819_REG_30_ENABLE_UNKNOWN |
+// 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_PA_GAIN |
+// BK4819_REG_30_ENABLE_MIC_ADC |
+ BK4819_REG_30_ENABLE_TX_DSP |
+// BK4819_REG_30_ENABLE_RX_DSP |
+ 0);
+ }
+
+ BK4819_WriteRegister(0x71, scale_freq(frequency));
+
+ SYSTEM_DelayMs(1);
+
+// BK4819_SetAF(tx ? BK4819_AF_BEEP : 2);
+ BK4819_SetAF(2); // RX
+// BK4819_SetAF(BK4819_AF_BEEP); // TX
+
+ if (!tx_mute)
+ BK4819_WriteRegister(0x50, 0x3B20); // 0011 1011 0010 0000
+
+ GPIO_SetBit(&GPIOC->DATA, 4);
+
+ SYSTEM_DelayMs(1);
+}
+
+void BK4819_stop_tones(const bool tx)
+{
+ SYSTEM_DelayMs(1);
+
+ GPIO_ClearBit(&GPIOC->DATA, 4);
+
+ SYSTEM_DelayMs(1);
+
+ BK4819_SetAF(BK4819_AF_MUTE);
+
+// BK4819_EnterTxMute();
+
+ SYSTEM_DelayMs(1);
+
+ BK4819_WriteRegister(0x70, 0);
+
+ BK4819_WriteRegister(0x30, 0);
+ if (!tx)
+ {
+ BK4819_WriteRegister(0x30,
+ BK4819_REG_30_ENABLE_VCO_CALIB |
+// BK4819_REG_30_ENABLE_UNKNOWN |
+ 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_PA_GAIN |
+// BK4819_REG_30_ENABLE_MIC_ADC |
+// BK4819_REG_30_ENABLE_TX_DSP |
+ BK4819_REG_30_ENABLE_RX_DSP |
+ 0);
+ }
+ else
+ {
+ BK4819_WriteRegister(0x30,
+ BK4819_REG_30_ENABLE_VCO_CALIB |
+ BK4819_REG_30_ENABLE_UNKNOWN |
+// 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_PA_GAIN |
+ BK4819_REG_30_ENABLE_MIC_ADC |
+ BK4819_REG_30_ENABLE_TX_DSP |
+// BK4819_REG_30_ENABLE_RX_DSP |
+ 0);
+ }
+
+ SYSTEM_DelayMs(1);
+
+ BK4819_ExitTxMute();
+
+ SYSTEM_DelayMs(1);
+}
+
+void BK4819_enable_mdc1200_rx(const bool enable)
+ {
+ // REG_70
+ //
+ // <15> 0 TONE-1
+ // 1 = enable
+ // 0 = disable
+ //
+ // <14:8> 0 TONE-1 gain
+ //
+ // <7> 0 TONE-2
+ // 1 = enable
+ // 0 = disable
+ //
+ // <6:0> 0 TONE-2 / FSK gain
+ // 0 ~ 127
+ //
+ // enable tone-2, set gain
+
+ // REG_72
+ //
+ // <15:0> 0x2854 TONE-2 / FSK frequency control word
+ // = freq(Hz) * 10.32444 for XTAL 13M / 26M or
+ // = freq(Hz) * 10.48576 for XTAL 12.8M / 19.2M / 25.6M / 38.4M
+ //
+ // tone-2 = 1200Hz
+
+ // REG_58
+ //
+ // <15:13> 1 FSK TX mode selection
+ // 0 = FSK 1.2K and FSK 2.4K TX .. no tones, direct FM
+ // 1 = FFSK 1200 / 1800 TX
+ // 2 = ???
+ // 3 = FFSK 1200 / 2400 TX
+ // 4 = ???
+ // 5 = NOAA SAME TX
+ // 6 = ???
+ // 7 = ???
+ //
+ // <12:10> 0 FSK RX mode selection
+ // 0 = FSK 1.2K, FSK 2.4K RX and NOAA SAME RX .. no tones, direct FM
+ // 1 = ???
+ // 2 = ???
+ // 3 = ???
+ // 4 = FFSK 1200 / 2400 RX
+ // 5 = ???
+ // 6 = ???
+ // 7 = FFSK 1200 / 1800 RX
+ //
+ // <9:8> 0 FSK RX gain
+ // 0 ~ 3
+ //
+ // <7:6> 0 ???
+ // 0 ~ 3
+ //
+ // <5:4> 0 FSK preamble type selection
+ // 0 = 0xAA or 0x55 due to the MSB of FSK sync byte 0
+ // 1 = ???
+ // 2 = 0x55
+ // 3 = 0xAA
+ //
+ // <3:1> 1 FSK RX bandwidth setting
+ // 0 = FSK 1.2K .. no tones, direct FM
+ // 1 = FFSK 1200 / 1800
+ // 2 = NOAA SAME RX
+ // 3 = ???
+ // 4 = FSK 2.4K and FFSK 1200 / 2400
+ // 5 = ???
+ // 6 = ???
+ // 7 = ???
+ //
+ // <0> 1 FSK enable
+ // 0 = disable
+ // 1 = enable
+
+ // REG_5C
+ //
+ // <15:7> ???
+ //
+ // <6> 1 CRC option enable
+ // 0 = disable
+ // 1 = enable
+ //
+ // <5:0> ???
+ //
+ // disable CRC
+
+ // REG_5D
+ //
+ // set the packet size
+
+ if (enable)
+ {
+ const uint16_t fsk_reg59 =
+ (0u << 15) | // 1 = clear TX FIFO
+ (0u << 14) | // 1 = clear RX FIFO
+ (0u << 13) | // 1 = scramble
+ (0u << 12) | // 1 = enable RX
+ (0u << 11) | // 1 = enable TX
+ (0u << 10) | // 1 = invert data when RX
+ (0u << 9) | // 1 = invert data when TX
+ (0u << 8) | // ???
+ (0u << 4) | // 0 ~ 15 preamble length selection .. mdc1200 does not send bit reversals :(
+ (1u << 3) | // 0/1 sync length selection
+ (0u << 0); // 0 ~ 7 ???
+
+ BK4819_WriteRegister(0x70,
+ ( 0u << 15) | // 0
+ ( 0u << 8) | // 0
+ ( 1u << 7) | // 1
+ (96u << 0)); // 96
+
+ BK4819_WriteRegister(0x72, scale_freq(1200));
+
+ BK4819_WriteRegister(0x58,
+ (1u << 13) | // 1 FSK TX mode selection
+ // 0 = FSK 1.2K and FSK 2.4K TX .. no tones, direct FM
+ // 1 = FFSK 1200 / 1800 TX
+ // 2 = ???
+ // 3 = FFSK 1200 / 2400 TX
+ // 4 = ???
+ // 5 = NOAA SAME TX
+ // 6 = ???
+ // 7 = ???
+ //
+ (7u << 10) | // 0 FSK RX mode selection
+ // 0 = FSK 1.2K, FSK 2.4K RX and NOAA SAME RX .. no tones, direct FM
+ // 1 = ???
+ // 2 = ???
+ // 3 = ???
+ // 4 = FFSK 1200 / 2400 RX
+ // 5 = ???
+ // 6 = ???
+ // 7 = FFSK 1200 / 1800 RX
+ //
+ (3u << 8) | // 0 FSK RX gain
+ // 0 ~ 3
+ //
+ (0u << 6) | // 0 ???
+ // 0 ~ 3
+ //
+ (0u << 4) | // 0 FSK preamble type selection
+ // 0 = 0xAA or 0x55 due to the MSB of FSK sync byte 0
+ // 1 = ???
+ // 2 = 0x55
+ // 3 = 0xAA
+ //
+ (1u << 1) | // 1 FSK RX bandwidth setting
+ // 0 = FSK 1.2K .. no tones, direct FM
+ // 1 = FFSK 1200 / 1800
+ // 2 = NOAA SAME RX
+ // 3 = ???
+ // 4 = FSK 2.4K and FFSK 1200 / 2400
+ // 5 = ???
+ // 6 = ???
+ // 7 = ???
+ //
+ (1u << 0)); // 1 FSK enable
+ // 0 = disable
+ // 1 = enable
+
+ // REG_5A .. bytes 0 & 1 sync pattern
+ //
+ // <15:8> sync byte 0
+ // < 7:0> sync byte 1
+// BK4819_WriteRegister(0x5A, ((uint16_t)mdc1200_sync_suc_xor[0] << 8) | (mdc1200_sync_suc_xor[1] << 0));
+ BK4819_WriteRegister(0x5A, ((uint16_t)mdc1200_sync_suc_xor[1] << 8) | (mdc1200_sync_suc_xor[2] << 0));
+
+ // REG_5B .. bytes 2 & 3 sync pattern
+ //
+ // <15:8> sync byte 2
+ // < 7:0> sync byte 3
+// BK4819_WriteRegister(0x5B, ((uint16_t)mdc1200_sync_suc_xor[2] << 8) | (mdc1200_sync_suc_xor[3] << 0));
+ BK4819_WriteRegister(0x5B, ((uint16_t)mdc1200_sync_suc_xor[3] << 8) | (mdc1200_sync_suc_xor[4] << 0));
+
+ // disable CRC
+ BK4819_WriteRegister(0x5C, 0x5625); // 01010110 0 0 100101
+// BK4819_WriteRegister(0x5C, 0xAA30); // 10101010 0 0 110000
+
+ // set the almost full threshold
+ BK4819_WriteRegister(0x5E, (64u << 3) | (1u << 0)); // 0 ~ 127, 0 ~ 7
+
+ { // packet size .. sync + 14 bytes - size of a single mdc1200 packet
+// uint16_t size = 1 + (MDC1200_FEC_K * 2);
+ uint16_t size = 0 + (MDC1200_FEC_K * 2);
+// size -= (fsk_reg59 & (1u << 3)) ? 4 : 2;
+ size = ((size + 1) / 2) * 2; // round up to even, else FSK RX doesn't work
+ BK4819_WriteRegister(0x5D, ((size - 1) << 8));
+ }
+
+ // clear FIFO's then enable RX
+ BK4819_WriteRegister(0x59, (1u << 15) | (1u << 14) | fsk_reg59);
+ BK4819_WriteRegister(0x59, (1u << 12) | fsk_reg59);
+
+ // clear interrupt flags
+ BK4819_WriteRegister(0x02, 0);
+
+// BK4819_RX_TurnOn();
+
+ // enable interrupts
+// BK4819_WriteRegister(0x3F, BK4819_ReadRegister(0x3F) | BK4819_REG_3F_FSK_RX_SYNC | BK4819_REG_3F_FSK_RX_FINISHED | BK4819_REG_3F_FSK_FIFO_ALMOST_FULL);
+ }
+ else
+ {
+ BK4819_WriteRegister(0x70, 0);
+ BK4819_WriteRegister(0x58, 0);
+ }
+ }
+
+ void BK4819_send_MDC1200(const uint8_t op, const uint8_t arg, const uint16_t id, const bool long_preamble)
+ {
+ uint16_t fsk_reg59;
+ uint8_t packet[42];
+
+ // create the MDC1200 packet
+ const unsigned int size = MDC1200_encode_single_packet(packet, op, arg, id);
+
+ //BK4819_ExitTxMute();
+ BK4819_WriteRegister(0x50, 0x3B20); // 0011 1011 0010 0000
+
+ BK4819_WriteRegister(0x30,
+ BK4819_REG_30_ENABLE_VCO_CALIB |
+ BK4819_REG_30_ENABLE_UNKNOWN |
+// 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_PA_GAIN |
+// BK4819_REG_30_ENABLE_MIC_ADC |
+ BK4819_REG_30_ENABLE_TX_DSP |
+// BK4819_REG_30_ENABLE_RX_DSP |
+ 0);
+
+ #if 1
+ GPIO_ClearBit(&GPIOC->DATA, 4);
+ BK4819_SetAF(BK4819_AF_MUTE);
+ #else
+ // let the user hear the FSK being sent
+ BK4819_SetAF(BK4819_AF_BEEP);
+ GPIO_SetBit(&GPIOC->DATA, 4);
+ #endif
+// SYSTEM_DelayMs(2);
+
+ // REG_51
+ //
+ // <15> TxCTCSS/CDCSS 0 = disable 1 = Enable
+ //
+ // turn off CTCSS/CDCSS during FFSK
+ const uint16_t css_val = BK4819_ReadRegister(0x51);
+ BK4819_WriteRegister(0x51, 0);
+
+ // set the FM deviation level
+ const uint16_t dev_val = BK4819_ReadRegister(0x40);
+ #if defined(ENABLE_UART) && defined(ENABLE_UART_DEBUG)
+// UART_printf("tx dev %04X\r\n", dev_val);
+ #endif
+ {
+ uint16_t deviation = 850;
+ switch (m_bandwidth)
+ {
+ case BK4819_FILTER_BW_WIDE: deviation = 1050; break;
+ case BK4819_FILTER_BW_NARROW: deviation = 850; break;
+ case BK4819_FILTER_BW_NARROWER: deviation = 750; break;
+ }
+ //BK4819_WriteRegister(0x40, (3u << 12) | (deviation & 0xfff));
+ BK4819_WriteRegister(0x40, (dev_val & 0xf000) | (deviation & 0xfff));
+ }
+
+ // REG_2B 0
+ //
+ // <15> 1 Enable CTCSS/CDCSS DC cancellation after FM Demodulation 1 = enable 0 = disable
+ // <14> 1 Enable AF DC cancellation after FM Demodulation 1 = enable 0 = disable
+ // <10> 0 AF RX HPF 300Hz filter 0 = enable 1 = disable
+ // <9> 0 AF RX LPF 3kHz filter 0 = enable 1 = disable
+ // <8> 0 AF RX de-emphasis filter 0 = enable 1 = disable
+ // <2> 0 AF TX HPF 300Hz filter 0 = enable 1 = disable
+ // <1> 0 AF TX LPF filter 0 = enable 1 = disable
+ // <0> 0 AF TX pre-emphasis filter 0 = enable 1 = disable
+ //
+ // disable the 300Hz HPF and FM pre-emphasis filter
+ //
+ const uint16_t filt_val = BK4819_ReadRegister(0x2B);
+ BK4819_WriteRegister(0x2B, (1u << 2) | (1u << 0));
+
+ // *******************************************
+ // setup the FFSK modem as best we can for MDC1200
+
+ // MDC1200 uses 1200/1800 Hz FSK tone frequencies 1200 bits/s
+ //
+ BK4819_WriteRegister(0x58, // 0x37C3); // 001 101 11 11 00 001 1
+ (1u << 13) | // 1 FSK TX mode selection
+ // 0 = FSK 1.2K and FSK 2.4K TX .. no tones, direct FM
+ // 1 = FFSK 1200/1800 TX
+ // 2 = ???
+ // 3 = FFSK 1200/2400 TX
+ // 4 = ???
+ // 5 = NOAA SAME TX
+ // 6 = ???
+ // 7 = ???
+ //
+ (7u << 10) | // 0 FSK RX mode selection
+ // 0 = FSK 1.2K, FSK 2.4K RX and NOAA SAME RX .. no tones, direct FM
+ // 1 = ???
+ // 2 = ???
+ // 3 = ???
+ // 4 = FFSK 1200/2400 RX
+ // 5 = ???
+ // 6 = ???
+ // 7 = FFSK 1200/1800 RX
+ //
+ (0u << 8) | // 0 FSK RX gain
+ // 0 ~ 3
+ //
+ (0u << 6) | // 0 ???
+ // 0 ~ 3
+ //
+ (0u << 4) | // 0 FSK preamble type selection
+ // 0 = 0xAA or 0x55 due to the MSB of FSK sync byte 0
+ // 1 = ???
+ // 2 = 0x55
+ // 3 = 0xAA
+ //
+ (1u << 1) | // 1 FSK RX bandwidth setting
+ // 0 = FSK 1.2K .. no tones, direct FM
+ // 1 = FFSK 1200/1800
+ // 2 = NOAA SAME RX
+ // 3 = ???
+ // 4 = FSK 2.4K and FFSK 1200/2400
+ // 5 = ???
+ // 6 = ???
+ // 7 = ???
+ //
+ (1u << 0)); // 1 FSK enable
+ // 0 = disable
+ // 1 = enable
+
+ // REG_72
+ //
+ // <15:0> 0x2854 TONE-2 / FSK frequency control word
+ // = freq(Hz) * 10.32444 for XTAL 13M / 26M or
+ // = freq(Hz) * 10.48576 for XTAL 12.8M / 19.2M / 25.6M / 38.4M
+ //
+ // tone-2 = 1200Hz
+ //
+ BK4819_WriteRegister(0x72, scale_freq(1200));
+
+ // REG_70
+ //
+ // <15> 0 TONE-1
+ // 1 = enable
+ // 0 = disable
+ //
+ // <14:8> 0 TONE-1 tuning
+ //
+ // <7> 0 TONE-2
+ // 1 = enable
+ // 0 = disable
+ //
+ // <6:0> 0 TONE-2 / FSK tuning
+ // 0 ~ 127
+ //
+ // enable tone-2, set gain
+ //
+ BK4819_WriteRegister(0x70, // 0 0000000 1 1100000
+ ( 0u << 15) | // 0
+ ( 0u << 8) | // 0
+ ( 1u << 7) | // 1
+ (96u << 0)); // 96
+// (127u << 0));
+
+ // REG_59
+ //
+ // <15> 0 TX FIFO 1 = clear
+ // <14> 0 RX FIFO 1 = clear
+ // <13> 0 FSK Scramble 1 = Enable
+ // <12> 0 FSK RX 1 = Enable
+ // <11> 0 FSK TX 1 = Enable
+ // <10> 0 FSK data when RX 1 = Invert
+ // <9> 0 FSK data when TX 1 = Invert
+ // <8> 0 ???
+ //
+ // <7:4> 0 FSK preamble length selection
+ // 0 = 1 byte
+ // 1 = 2 bytes
+ // 2 = 3 bytes
+ // 15 = 16 bytes
+ //
+ // <3> 0 FSK sync length selection
+ // 0 = 2 bytes (FSK Sync Byte 0, 1)
+ // 1 = 4 bytes (FSK Sync Byte 0, 1, 2, 3)
+ //
+ // <2:0> 0 ???
+ //
+ fsk_reg59 = (0u << 15) | // 0/1 1 = clear TX FIFO
+ (0u << 14) | // 0/1 1 = clear RX FIFO
+ (0u << 13) | // 0/1 1 = scramble
+ (0u << 12) | // 0/1 1 = enable RX
+ (0u << 11) | // 0/1 1 = enable TX
+ (0u << 10) | // 0/1 1 = invert data when RX
+ (0u << 9) | // 0/1 1 = invert data when TX
+ (0u << 8) | // 0/1 ???
+ (0u << 4) | // 0 ~ 15 preamble length .. bit toggling
+ (1u << 3) | // 0/1 sync length
+ (0u << 0); // 0 ~ 7 ???
+ fsk_reg59 |= long_preamble ? 15u << 4 : 3u << 4;
+
+ // Set packet length (not including pre-amble and sync bytes that we can't seem to disable)
+ BK4819_WriteRegister(0x5D, ((size - 1) << 8));
+
+ // REG_5A
+ //
+ // <15:8> 0x55 FSK Sync Byte 0 (Sync Byte 0 first, then 1,2,3)
+ // <7:0> 0x55 FSK Sync Byte 1
+ //
+ BK4819_WriteRegister(0x5A, 0x0000); // bytes 1 & 2
+
+ // REG_5B
+ //
+ // <15:8> 0x55 FSK Sync Byte 2 (Sync Byte 0 first, then 1,2,3)
+ // <7:0> 0xAA FSK Sync Byte 3
+ //
+ BK4819_WriteRegister(0x5B, 0x0000); // bytes 2 & 3
+
+ // CRC setting (plus other stuff we don't know what)
+ //
+ // REG_5C
+ //
+ // <15:7> ???
+ //
+ // <6> 1 CRC option enable 0 = disable 1 = enable
+ //
+ // <5:0> ???
+ //
+ // disable CRC
+ //
+ // NB, this also affects TX pre-amble in some way
+ //
+ BK4819_WriteRegister(0x5C, 0x5625); // 010101100 0 100101
+// BK4819_WriteRegister(0x5C, 0xAA30); // 101010100 0 110000
+// BK4819_WriteRegister(0x5C, 0x0030); // 000000000 0 110000
+
+ BK4819_WriteRegister(0x59, (1u << 15) | (1u << 14) | fsk_reg59); // clear FIFO's
+ BK4819_WriteRegister(0x59, fsk_reg59); // release the FIFO reset
+
+ { // load the entire packet data into the TX FIFO buffer
+ unsigned int i;
+ const uint16_t *p = (const uint16_t *)packet;
+ for (i = 0; i < (size / sizeof(p[0])); i++)
+ BK4819_WriteRegister(0x5F, p[i]); // load 16-bits at a time
+ }
+
+ // enable tx interrupt
+ BK4819_WriteRegister(0x3F, BK4819_REG_3F_FSK_TX_FINISHED);
+
+ // enable FSK TX
+ BK4819_WriteRegister(0x59, (1u << 11) | fsk_reg59);
+
+ { // packet time is ..
+ // 173ms for PTT ID, acks, emergency
+ // 266ms for call alert and sel-calls
+
+ // allow up to 310ms for the TX to complete
+ // if it takes any longer then somethings gone wrong, we shut the TX down
+ unsigned int timeout = 300 / 4;
+
+ while (timeout-- > 0)
+ {
+ SYSTEM_DelayMs(4);
+ if (BK4819_ReadRegister(0x0C) & (1u << 0))
+ { // we have interrupt flags
+ BK4819_WriteRegister(0x02, 0);
+ if (BK4819_ReadRegister(0x02) & BK4819_REG_02_FSK_TX_FINISHED)
+ timeout = 0; // TX is complete
+ }
+ }
+ }
+
+ GPIO_ClearBit(&GPIOC->DATA, 4);
+
+ // disable FSK
+ BK4819_WriteRegister(0x59, fsk_reg59);
+
+ BK4819_WriteRegister(0x3F, 0); // disable interrupts
+ BK4819_WriteRegister(0x70, 0);
+ BK4819_WriteRegister(0x58, 0);
+
+ // restore FM deviation level
+ BK4819_WriteRegister(0x40, dev_val);
+
+ // restore TX/RX filtering
+ BK4819_WriteRegister(0x2B, filt_val);
+
+ // restore the CTCSS/CDCSS setting
+ BK4819_WriteRegister(0x51, css_val);
+
+ //BK4819_EnterTxMute();
+ BK4819_WriteRegister(0x50, 0xBB20); // 1011 1011 0010 0000
+
+ //BK4819_SetAF(BK4819_AF_MUTE);
+ BK4819_WriteRegister(0x47, (1u << 14) | (1u << 13) | (BK4819_AF_MUTE << 8) | (1u << 6));
+
+ BK4819_WriteRegister(0x30,
+ BK4819_REG_30_ENABLE_VCO_CALIB |
+ BK4819_REG_30_ENABLE_UNKNOWN |
+// 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_PA_GAIN |
+ BK4819_REG_30_ENABLE_MIC_ADC |
+ BK4819_REG_30_ENABLE_TX_DSP |
+// BK4819_REG_30_ENABLE_RX_DSP |
+ 0);
+
+ //BK4819_ExitTxMute();
+ BK4819_WriteRegister(0x50, 0x3B20); // 0011 1011 0010 0000
+ }
+#endif
\ No newline at end of file
diff --git a/driver/bk4819.h b/driver/bk4819.h
index 3248c17..8787246 100644
--- a/driver/bk4819.h
+++ b/driver/bk4819.h
@@ -66,6 +66,7 @@ typedef enum BK4819_CssScanResult_t BK4819_CssScanResult_t;
extern bool gRxIdleMode;
void BK4819_Init(void);
+
uint16_t BK4819_ReadRegister(BK4819_REGISTER_t Register);
void BK4819_WriteRegister(BK4819_REGISTER_t Register, uint16_t Data);
void BK4819_SetRegValue(RegisterSpec s, uint16_t v);
@@ -168,6 +169,10 @@ void BK4819_Enable_AfDac_DiscMode_TxDsp(void);
void BK4819_GetVoxAmp(uint16_t *pResult);
void BK4819_SetScrambleFrequencyControlWord(uint32_t Frequency);
void BK4819_PlayDTMFEx(bool bLocalLoopback, char Code);
+void BK4819_send_MDC1200(const uint8_t op, const uint8_t arg, const uint16_t id, const bool long_preamble);
+
+void BK4819_stop_tones(const bool tx);
+void BK4819_start_tone(const uint16_t frequency, const unsigned int level, const bool tx, const bool tx_mute);
#endif
diff --git a/driver/crc.c b/driver/crc.c
index 7a1840d..e839d55 100644
--- a/driver/crc.c
+++ b/driver/crc.c
@@ -19,18 +19,34 @@
void CRC_Init(void)
{
- CRC_CR = 0
- | CRC_CR_CRC_EN_BITS_DISABLE
- | CRC_CR_INPUT_REV_BITS_NORMAL
- | CRC_CR_INPUT_INV_BITS_NORMAL
- | CRC_CR_OUTPUT_REV_BITS_NORMAL
- | CRC_CR_OUTPUT_INV_BITS_NORMAL
- | CRC_CR_DATA_WIDTH_BITS_8
- | CRC_CR_CRC_SEL_BITS_CRC_16_CCITT
- ;
- CRC_IV = 0;
+ CRC_CR =
+ CRC_CR_CRC_EN_BITS_DISABLE |
+ CRC_CR_INPUT_REV_BITS_NORMAL |
+ CRC_CR_INPUT_INV_BITS_BIT_INVERTED |
+ CRC_CR_OUTPUT_REV_BITS_REVERSED |
+ CRC_CR_OUTPUT_INV_BITS_BIT_INVERTED |
+ CRC_CR_DATA_WIDTH_BITS_8 |
+ CRC_CR_CRC_SEL_BITS_CRC_16_CCITT;
+
+ CRC_IV = 0;
+
}
+#ifdef ENABLE_MDC1200
+void CRC_InitReverse(void)
+ {
+ CRC_CR =
+ CRC_CR_CRC_EN_BITS_DISABLE |
+ CRC_CR_INPUT_REV_BITS_NORMAL |
+ CRC_CR_INPUT_INV_BITS_BIT_INVERTED |
+ CRC_CR_OUTPUT_REV_BITS_REVERSED |
+ CRC_CR_OUTPUT_INV_BITS_BIT_INVERTED |
+ CRC_CR_DATA_WIDTH_BITS_8 |
+ CRC_CR_CRC_SEL_BITS_CRC_16_CCITT;
+
+ CRC_IV = 0;
+ }
+#endif
uint16_t CRC_Calculate(const void *pBuffer, uint16_t Size)
{
const uint8_t *pData = (const uint8_t *)pBuffer;
diff --git a/driver/crc.h b/driver/crc.h
index acc9b49..cf192ee 100644
--- a/driver/crc.h
+++ b/driver/crc.h
@@ -21,6 +21,7 @@
void CRC_Init(void);
uint16_t CRC_Calculate(const void *pBuffer, uint16_t Size);
+void CRC_InitReverse(void);
#endif
diff --git a/driver/systick.c b/driver/systick.c
index 5971d74..dd4e469 100644
--- a/driver/systick.c
+++ b/driver/systick.c
@@ -43,3 +43,23 @@ void SYSTICK_DelayUs(uint32_t Delay)
} while (i < ticks);
}
+void SYSTICK_Delay250ns(const uint32_t Delay)
+{
+ const uint32_t ticks = (Delay * gTickMultiplier) >> 2;
+ uint32_t i = 0;
+ uint32_t Start = SysTick->LOAD;
+ uint32_t Previous = SysTick->VAL;
+
+ do {
+ uint32_t Delta;
+ uint32_t Current;
+
+ do Current = SysTick->VAL;
+ while (Current == Previous);
+
+ Delta = (Current < Previous) ? -Current : Start - Current;
+ i += Delta + Previous;
+ Previous = Current;
+
+ } while (i < ticks);
+}
diff --git a/driver/systick.h b/driver/systick.h
index 95ba478..9d0d1f2 100644
--- a/driver/systick.h
+++ b/driver/systick.h
@@ -21,6 +21,7 @@
void SYSTICK_Init(void);
void SYSTICK_DelayUs(uint32_t Delay);
+void SYSTICK_Delay250ns(const uint32_t Delay);
#endif
diff --git a/radio.c b/radio.c
index 826b030..7591dfb 100644
--- a/radio.c
+++ b/radio.c
@@ -13,7 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include "driver/bk4819.h"
+#include "app/mdc1200.h"
#include
#include "app/dtmf.h"
@@ -904,6 +906,7 @@ void RADIO_SetTxParameters(void)
void RADIO_SetModulation(ModulationMode_t modulation)
{
+ static ModulationMode_t m = MODULATION_UKNOWN;
BK4819_AF_Type_t mod;
switch(modulation) {
default:
@@ -928,9 +931,16 @@ void RADIO_SetModulation(ModulationMode_t modulation)
}
BK4819_SetAF(mod);
- BK4819_SetRegValue(afDacGainRegSpec, 0xF);
- BK4819_WriteRegister(BK4819_REG_3D, modulation == MODULATION_USB ? 0 : 0x2AAB);
- BK4819_SetRegValue(afcDisableRegSpec, modulation != MODULATION_FM);
+ if(m != modulation) {
+ m = modulation;
+ BK4819_SetRegValue(afDacGainRegSpec, 0xF);
+ BK4819_WriteRegister(BK4819_REG_3D, modulation == MODULATION_USB ? 0 : 0x2AAB);
+ BK4819_SetRegValue(afcDisableRegSpec, modulation != MODULATION_FM);
+#ifdef ENABLE_AM_FIX
+ BK4819_SetAGC(gRxVfo->Modulation != MODULATION_AM || !gSetting_AM_fix);
+ BK4819_InitAGC();
+#endif
+ }
}
void RADIO_SetVfoState(VfoState_t State)
@@ -1113,12 +1123,19 @@ void RADIO_SendEndOfTransmission(void)
if (gEeprom.ROGER == ROGER_MODE_ROGER)
BK4819_PlayRoger();
else
- if (gEeprom.ROGER == ROGER_MODE_MDC)
- BK4819_PlayRogerMDC();
+ if (gEeprom.ROGER == ROGER_MODE_MDC) {
+ BK4819_send_MDC1200(MDC1200_OP_CODE_POST_ID, 0x00, 12, false);
+#ifdef ENABLE_MDC1200_SIDE_BEEP
+ BK4819_start_tone(880, 10, true, true);
+ SYSTEM_DelayMs(120);
+ BK4819_stop_tones(true);
+#endif
+ }
if (gCurrentVfo->DTMF_PTT_ID_TX_MODE == PTT_ID_APOLLO)
- BK4819_PlaySingleTone(2475, 250, 28, gEeprom.DTMF_SIDE_TONE);
+ { BK4819_PlaySingleTone(2475, 250, 28, gEeprom.DTMF_SIDE_TONE);
+ }
if (
#ifdef ENABLE_DTMF_CALLING
gDTMF_CallState == DTMF_CALL_STATE_NONE &&
diff --git a/ui/main.c b/ui/main.c
index 24bdb49..89d4c04 100644
--- a/ui/main.c
+++ b/ui/main.c
@@ -38,7 +38,15 @@
#include "ui/ui.h"
center_line_t center_line = CENTER_LINE_NONE;
-
+const int8_t dBmCorrTable[7] = {
+ -15, // band 1
+ -25, // band 2
+ -20, // band 3
+ -4, // band 4
+ -7, // band 5
+ -6, // band 6
+ -1 // band 7
+};
// ***************************************************************************
static void DrawSmallAntennaAndBars(uint8_t *p, unsigned int level)
@@ -175,15 +183,7 @@ static void DisplayRSSIBar(const int16_t rssi, const bool now)
if (now)
memset(p_line, 0, LCD_WIDTH);
- const int8_t dBmCorrTable[7] = {
- -15, // band 1
- -25, // band 2
- -20, // band 3
- -4, // band 4
- -7, // band 5
- -6, // band 6
- -1 // band 7
- };
+
const int16_t s0_dBm = -130; // S0 .. base level
// const int16_t rssi_dBm = (rssi / 2) - 160;
const int16_t rssi_dBm = (rssi / 2) - 160 + dBmCorrTable[gRxVfo->Band];
diff --git a/ui/main.h b/ui/main.h
index 80024f9..ba01acc 100644
--- a/ui/main.h
+++ b/ui/main.h
@@ -33,6 +33,6 @@ extern center_line_t center_line;
void UI_DisplayAudioBar(void);
void UI_UpdateRSSI(const int16_t rssi, const int vfo);
void UI_DisplayMain(void);
-
+extern const int8_t dBmCorrTable[7];
#endif
diff --git a/版本说明.txt b/版本说明.txt
index ea0b268..5770a64 100644
--- a/版本说明.txt
+++ b/版本说明.txt
@@ -1,3 +1,20 @@
+#0.10.4
+ 修复开机显示问题
+ 修复宽窄带开机后失效问题
+ 频谱图增加AM-FIX
+ 增加MDC1200信令
+#0.10.3
+ 修复“长按菜单切换调制模式(AM/FM/USB)再切回FM亚音消失问题”
+ 锁定按键改成原来的逻辑,以后这种操作逻辑相关的都不来改了,众口难调
+#0.10.2
+ 修复命名信道时频率会变化的bug
+ 锁定按键时只允许发射/接收按键,与官方中文版逻辑一致
+#0.10.1
+ 重构代码,菜单名使用中文(是的,中文宏定义,感谢现代编译器,中文见/ui/menu.c)
+ 优化代码,节省了1.4KB
+ 修复扫描时“频差”翻译错误,纠正为“频率”
+ 修复开机显示菜单选项错误问题
+ (哥们比较空,所以更新的快,其实不用天天升级,跟着大版本升级就好了)
# 0.10
* 版本为egcn变种,旨在精简固件植入更多功能,如MDC1200信令
* egcn更新至191,结束:https://github.com/losehu/uv-k5-firmware-egcn/tree/main