diff --git a/app/app.c b/app/app.c index 4132d62..ee29897 100644 --- a/app/app.c +++ b/app/app.c @@ -586,11 +586,12 @@ uint32_t APP_set_frequency_by_step(vfo_info_t *pInfo, int8_t Step) Frequency = Lower + Base + (Index * 833); } - if (Frequency >= FREQ_BAND_TABLE[pInfo->band].upper) - Frequency = FREQ_BAND_TABLE[pInfo->band].lower; - else - if (Frequency < FREQ_BAND_TABLE[pInfo->band].lower) - Frequency = FREQUENCY_FloorToStep(FREQ_BAND_TABLE[pInfo->band].upper, pInfo->step_freq, FREQ_BAND_TABLE[pInfo->band].lower); +// if (Frequency >= FREQ_BAND_TABLE[pInfo->band].upper) +// Frequency = FREQ_BAND_TABLE[pInfo->band].lower; +// else +// if (Frequency < FREQ_BAND_TABLE[pInfo->band].lower) +// Frequency = FREQUENCY_floor_to_step(FREQ_BAND_TABLE[pInfo->band].upper, pInfo->step_freq, FREQ_BAND_TABLE[pInfo->band].lower); + Frequency = FREQUENCY_wrap_to_step_band(Frequency, pInfo->step_freq, pInfo->band); return Frequency; } diff --git a/app/main.c b/app/main.c index 6e3a0db..6c1300e 100644 --- a/app/main.c +++ b/app/main.c @@ -43,7 +43,7 @@ void toggle_chan_scanlist(void) { // toggle the selected channels scanlist setting -// if (IS_FREQ_CHANNEL(g_tx_vfo->channel_save)) +// if (IS_FREQ_CHANNEL(g_tx_vfo->channel_save)) // TODO: include the VFO freq as a channel when scanning if (IS_NOAA_CHANNEL(g_tx_vfo->channel_save)) { g_beep_to_play = BEEP_500HZ_60MS_DOUBLE_BEEP_OPTIONAL; @@ -212,10 +212,10 @@ void processFKeyFunction(const key_code_t Key) if (g_setting_350_enable || Band != BAND5_350MHz) { if (Band > BAND7_470MHz) - Band = BAND1_50MHz; + Band = BAND1_50MHz; // wrap-a-round } else - Band = BAND6_400MHz; + Band = BAND6_400MHz; // jump to next band g_tx_vfo->band = Band; g_eeprom.screen_channel[Vfo] = FREQ_CHANNEL_FIRST + Band; @@ -545,10 +545,9 @@ void MAIN_Key_DIGITS(key_code_t Key, bool key_pressed, bool key_held) RADIO_configure_channel(Vfo, VFO_CONFIGURE_RELOAD); } -// Frequency += 75; // is this meant to be rounding ? - Frequency += g_tx_vfo->step_freq / 2; // no idea, but this is + Frequency += g_tx_vfo->step_freq / 2; // for rounding to nearest step size - Frequency = FREQUENCY_FloorToStep(Frequency, g_tx_vfo->step_freq, FREQ_BAND_TABLE[g_tx_vfo->band].lower); + Frequency = FREQUENCY_floor_to_step(Frequency, g_tx_vfo->step_freq, FREQ_BAND_TABLE[g_tx_vfo->band].lower, FREQ_BAND_TABLE[g_tx_vfo->band].upper); if (Frequency >= BX4819_BAND1.upper && Frequency < BX4819_BAND2.lower) { // clamp the frequency to the limit diff --git a/app/menu.c b/app/menu.c index 27c4212..569237e 100644 --- a/app/menu.c +++ b/app/menu.c @@ -1424,7 +1424,7 @@ static void MENU_Key_0_to_9(key_code_t Key, bool key_pressed, bool key_held) NUMBER_Get(g_input_box, &Frequency); g_input_box_index = 0; - g_sub_menu_selection = FREQUENCY_FloorToStep(Frequency + (g_tx_vfo->step_freq / 2), g_tx_vfo->step_freq, 0); + g_sub_menu_selection = FREQUENCY_floor_to_step(Frequency + (g_tx_vfo->step_freq / 2), g_tx_vfo->step_freq, 0, Frequency + (g_tx_vfo->step_freq / 2)); return; } @@ -1852,7 +1852,7 @@ static void MENU_Key_UP_DOWN(bool key_pressed, bool key_held, int8_t Direction) else Offset = 0; - g_sub_menu_selection = FREQUENCY_FloorToStep(Offset, g_tx_vfo->step_freq, 0); + g_sub_menu_selection = FREQUENCY_floor_to_step(Offset, g_tx_vfo->step_freq, 0, Offset); g_request_display_screen = DISPLAY_MENU; return; } diff --git a/frequencies.c b/frequencies.c index ac871c1..ed573c4 100644 --- a/frequencies.c +++ b/frequencies.c @@ -157,29 +157,49 @@ uint8_t FREQUENCY_CalculateOutputPower(uint8_t TxpLow, uint8_t TxpMid, uint8_t T return pwr; } -uint32_t FREQUENCY_FloorToStep(uint32_t Upper, uint32_t Step, uint32_t Lower) +uint32_t FREQUENCY_floor_to_step(uint32_t freq, const uint32_t step_size, const uint32_t lower, const uint32_t upper) { - #if 1 - uint32_t Index; + uint32_t delta; - if (Step == 833) - { - const uint32_t Delta = Upper - Lower; - uint32_t Base = (Delta / 2500) * 2500; - const uint32_t Index = ((Delta - Base) % 2500) / 833; + if (freq <= lower) + return lower; - if (Index == 2) - Base++; + if (freq > (upper - 1)) + freq = upper - 1; - return Lower + Base + (Index * 833); - } + delta = freq - lower; - Index = (Upper - Lower) / Step; + if (delta < step_size) + return lower; + + if (step_size == 833) + { + uint32_t base = (delta / 2500) * 2500; // 25kHz step + const unsigned int index = ((delta - base) % 2500) / step_size; - return Lower + (Step * Index); - #else - return Lower + (((Upper - Lower) / Step) * Step); - #endif + if (index == 2) + base++; + + freq = lower + base + (step_size * index); + } + else + freq = lower + ((delta / step_size) * step_size); + + return freq; +} + +uint32_t FREQUENCY_wrap_to_step_band(uint32_t freq, const uint32_t step_size, const unsigned int band) +{ + const uint32_t upper = FREQ_BAND_TABLE[band].upper; + const uint32_t lower = FREQ_BAND_TABLE[band].lower; + + if (freq < lower) + return FREQUENCY_floor_to_step(upper, step_size, lower, upper); + + if (freq >= upper) + freq = lower; + + return freq; } int FREQUENCY_tx_freq_check(const uint32_t Frequency) diff --git a/frequencies.h b/frequencies.h index 1f8d476..a77f3dd 100644 --- a/frequencies.h +++ b/frequencies.h @@ -93,7 +93,9 @@ void FREQUENCY_init(void); frequency_band_t FREQUENCY_GetBand(uint32_t Frequency); uint8_t FREQUENCY_CalculateOutputPower(uint8_t TxpLow, uint8_t TxpMid, uint8_t TxpHigh, int32_t LowerLimit, int32_t Middle, int32_t UpperLimit, int32_t Frequency); -uint32_t FREQUENCY_FloorToStep(uint32_t Upper, uint32_t Step, uint32_t Lower); + +uint32_t FREQUENCY_floor_to_step(uint32_t freq, const uint32_t step_size, const uint32_t lower, const uint32_t upper); +uint32_t FREQUENCY_wrap_to_step_band(uint32_t freq, const uint32_t step_size, const unsigned int band); int FREQUENCY_tx_freq_check(const uint32_t Frequency); int FREQUENCY_rx_freq_check(const uint32_t Frequency); diff --git a/mdc1200.c b/mdc1200.c index a2efabb..79ba022 100644 --- a/mdc1200.c +++ b/mdc1200.c @@ -57,11 +57,12 @@ uint16_t reverse_bits(const uint16_t bits_in, const unsigned int num_bits) return bits_out; } -#if 0 +#if 1 uint16_t compute_crc(const uint8_t *data, const unsigned int data_len) { // using the reverse computation avoids having to reverse the bit order during and after + unsigned int i; uint16_t crc = 0; - for (i = 0; i < len; i++) + for (i = 0; i < data_len; i++) { unsigned int k; crc ^= data[i]; @@ -129,54 +130,80 @@ uint16_t reverse_bits(const uint16_t bits_in, const unsigned int num_bits) } #endif +#define FEC_K 7 + uint8_t * encode_data(uint8_t *data) { unsigned int i; - unsigned int k; - unsigned int m; - uint8_t csr[7]; - uint8_t lbits[(ARRAY_SIZE(csr) * 2) * 8]; - for (i = 0; i < ARRAY_SIZE(csr); i++) - csr[i] = 0; - - for (i = 0; i < ARRAY_SIZE(csr); i++) + // R=1/2 K=7 convolutional coder + // + // create the FEC bits + // + // op 0x01 + // arg 0x80 + // id 0x1234 + // crc 0x2E3E + // status 0x00 + // FEC 0x6580A862DD8808 + // + // 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 listed above (for display) + // { - unsigned int bit; - data[i + ARRAY_SIZE(csr)] = 0; - for (bit = 0; bit < 8; bit++) + uint8_t shift_reg = 0; + for (i = 0; i < FEC_K; i++) { - uint8_t b; - for (k = 6; k > 0; k--) - csr[k] = csr[k - 1]; - csr[0] = (data[i] >> bit) & 1u; - b = csr[0] + csr[2] + csr[5] + csr[6]; - data[i + ARRAY_SIZE(csr)] |= (b & 1u) << bit; + unsigned int bit; + const uint8_t bi = data[i]; + uint8_t bo = 0; + + for (bit = 0; bit < 8; bit++) + { + shift_reg = (shift_reg << 1) | ((bi >> bit) & 1u); + bo |= (((shift_reg >> 6) ^ (shift_reg >> 5) ^ (shift_reg >> 2) ^ (shift_reg >> 0)) & 1u) << bit; + } + + data[i + FEC_K] = bo; } } - for (i = 0, k = 0, m = 0; i < (ARRAY_SIZE(csr) * 2); i++) { - unsigned int bit; - for (bit = 0; bit < 8; bit++) + unsigned int k; + unsigned int m; + uint8_t interleaved[(FEC_K * 2) * 8]; + + // bit interleaver + for (i = 0, k = 0, m = 0; i < (FEC_K * 2); i++) { - lbits[k] = (data[i] >> bit) & 1u; - k += 16; - if (k >= ARRAY_SIZE(lbits)) - k = ++m; + unsigned int bit; + const uint8_t b = data[i]; + for (bit = 0; bit < 8; bit++) + { + interleaved[k] = (b >> bit) & 1u; + k += 16; + if (k >= sizeof(interleaved)) + k = ++m; + } + } + + // copy the interleaved bits to the output buffer + for (i = 0, k = 0; i < (FEC_K * 2); i++) + { + int bit; + uint8_t b = 0; + for (bit = 7; bit >= 0; bit--) + if (interleaved[k++]) + b |= 1u << bit; + data[i] = b; } } - for (i = 0, k = 0; i < (ARRAY_SIZE(csr) * 2); i++) - { - int bit; - data[i] = 0; - for (bit = 7; bit >= 0; bit--) - if (lbits[k++]) - data[i] |= 1u << bit; - } - - return data + 14; + return data + (FEC_K * 2); } void delta_modulation(uint8_t *data, const unsigned int size) @@ -215,12 +242,15 @@ unsigned int MDC1200_encode_single_packet(uint8_t *data, const uint8_t op, const crc = compute_crc(p, 4); p[4] = (crc >> 0) & 0x00ff; p[5] = (crc >> 8) & 0x00ff; - p[6] = 0; + p[6] = 0; // unknown field (00 for PTTIDs, 76 for STS and MSG) p = encode_data(p); -#if 1 - { // op 0x01, arg 0x80, id 0xB183 +#if 0 + { // test packet + // + // op 0x01, arg 0x80, id 0xB183 + // const uint8_t test_packet[] = {0x07, 0x25, 0xDD, 0xD5, 0x9F, 0xC5, 0x3D, 0x89, 0x2D, 0xBD, 0x57, 0x35, 0xE7, 0x44}; memcpy(data + sizeof(header), test_packet, sizeof(test_packet)); } @@ -229,7 +259,7 @@ unsigned int MDC1200_encode_single_packet(uint8_t *data, const uint8_t op, const size = (unsigned int)(p - data); delta_modulation(data, size); - + return size; // return 26; } @@ -250,7 +280,7 @@ unsigned int MDC1200_encode_double_packet(uint8_t *data, const uint8_t op, const crc = compute_crc(p, 4); p[4] = (crc >> 0) & 0x00ff; p[5] = (crc >> 8) & 0x00ff; - p[6] = 0; + p[6] = 0; // status byte p = encode_data(p); @@ -261,7 +291,7 @@ unsigned int MDC1200_encode_double_packet(uint8_t *data, const uint8_t op, const crc = compute_crc(p, 4); p[4] = (crc >> 0) & 0x00ff; p[5] = (crc >> 8) & 0x00ff; - p[6] = 0; + p[6] = 0; // status byte p = encode_data(p); diff --git a/mdc1200.h b/mdc1200.h index e1a6b86..f0d8c5a 100644 --- a/mdc1200.h +++ b/mdc1200.h @@ -4,6 +4,9 @@ #include +// 0x00 (0x81) emergency alarm +// 0x20 (0x00) emergency alarm ack +// // 0x01 (0x80) is PTT ID // 0x01 (0x00) is POST ID // 0x11 (0x8A) is REMOTE MONITOR @@ -13,7 +16,61 @@ // 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, diff --git a/radio.c b/radio.c index c38fb2f..962d438 100644 --- a/radio.c +++ b/radio.c @@ -311,25 +311,19 @@ void RADIO_configure_channel(const unsigned int VFO, const unsigned int configur Frequency = p_vfo->freq_config_rx.frequency; -#if 1 - // fix previously maybe incorrect set band - Band = FREQUENCY_GetBand(Frequency); - p_vfo->band = Band; -#endif - if (Frequency < FREQ_BAND_TABLE[Band].lower) Frequency = FREQ_BAND_TABLE[Band].lower; else - if (Frequency > FREQ_BAND_TABLE[Band].upper) - Frequency = FREQ_BAND_TABLE[Band].upper; + if (Frequency >= FREQ_BAND_TABLE[Band].upper) + Frequency = FREQUENCY_floor_to_step(Frequency, p_vfo->step_freq, FREQ_BAND_TABLE[Band].lower, FREQ_BAND_TABLE[Band].upper); else if (Channel >= FREQ_CHANNEL_FIRST) - Frequency = FREQUENCY_FloorToStep(Frequency, p_vfo->step_freq, FREQ_BAND_TABLE[Band].lower); + Frequency = FREQUENCY_floor_to_step(Frequency, p_vfo->step_freq, FREQ_BAND_TABLE[Band].lower, FREQ_BAND_TABLE[Band].upper); if (!g_setting_350_enable && Frequency >= 35000000 && Frequency < 40000000) { // 350~400Mhz not allowed - // hop onto the euro ham band + // hop onto the next band up Frequency = 43350000; p_vfo->freq_config_rx.frequency = Frequency; p_vfo->freq_config_tx.frequency = Frequency; @@ -338,6 +332,11 @@ void RADIO_configure_channel(const unsigned int VFO, const unsigned int configur p_vfo->frequency_reverse = 0; p_vfo->tx_offset_freq_dir = TX_OFFSET_FREQ_DIR_OFF; p_vfo->tx_offset_freq = 0; + + + // TODO: also update other settings such as step size + + } p_vfo->freq_config_rx.frequency = Frequency; @@ -350,7 +349,7 @@ void RADIO_configure_channel(const unsigned int VFO, const unsigned int configur else if (Channel > USER_CHANNEL_LAST) { - p_vfo->tx_offset_freq = FREQUENCY_FloorToStep(p_vfo->tx_offset_freq, p_vfo->step_freq, 0); + p_vfo->tx_offset_freq = FREQUENCY_floor_to_step(p_vfo->tx_offset_freq, p_vfo->step_freq, 0, p_vfo->tx_offset_freq); } RADIO_ApplyOffset(p_vfo);