mirror of
https://github.com/eried/portapack-mayhem.git
synced 2024-12-25 23:39:37 -05:00
Display CTCSS tone freq in Audio, Recon, and Level apps (#1231)
* Generate CTCSS messages at fixed rate regardless of tone freq * Generate CTCSS messages at fixed rate regardless of tone freq * Function for generating CTCSS description strings * Function for generating CTCSS description strings * Increase width of CTCSS text to include tone freq * Increase width of CTCSS text field to include frequency * Use CTCSS tone freq when saving HAM freqs to freq file * Use function in tone_key.cpp for displaying CTCSS string * Use function in tone_key.cpp for CTCSS descr strings * Use function in tone_key.cpp for CTCSS descr strings * Clang test * Clang * Clang * Support for reading CTCSS tones from FreqMan file * Clang * Clean up and eliminate floating point * Clean up and eliminate floating point * Corrected CTCSS field length * Corrected CTCSS field length * Clang
This commit is contained in:
parent
44dd8fd083
commit
80c769b97d
@ -404,11 +404,7 @@ void AnalogAudioView::update_modulation(ReceiverModel::Mode modulation) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AnalogAudioView::handle_coded_squelch(uint32_t value) {
|
void AnalogAudioView::handle_coded_squelch(uint32_t value) {
|
||||||
tone_index idx = tone_key_index_by_value(value);
|
text_ctcss.set(tone_key_string_by_value(value, text_ctcss.parent_rect().width() / 8));
|
||||||
if (idx >= 0)
|
|
||||||
text_ctcss.set("CTCSS " + tone_key_string(idx));
|
|
||||||
else
|
|
||||||
text_ctcss.set("???");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} /* namespace ui */
|
} /* namespace ui */
|
||||||
|
@ -71,10 +71,10 @@ class NBFMOptionsView : public View {
|
|||||||
}};
|
}};
|
||||||
|
|
||||||
Text text_squelch{
|
Text text_squelch{
|
||||||
{9 * 8, 0 * 16, 8 * 8, 1 * 16},
|
{7 * 8, 0 * 16, 8 * 8, 1 * 16},
|
||||||
"SQ /99"};
|
"SQ /99"};
|
||||||
NumberField field_squelch{
|
NumberField field_squelch{
|
||||||
{12 * 8, 0 * 16},
|
{10 * 8, 0 * 16},
|
||||||
2,
|
2,
|
||||||
{0, 99},
|
{0, 99},
|
||||||
1,
|
1,
|
||||||
@ -200,7 +200,7 @@ class AnalogAudioView : public View {
|
|||||||
{28 * 8, 0 * 16}};
|
{28 * 8, 0 * 16}};
|
||||||
|
|
||||||
Text text_ctcss{
|
Text text_ctcss{
|
||||||
{19 * 8, 1 * 16, 11 * 8, 1 * 16},
|
{16 * 8, 1 * 16, 14 * 8, 1 * 16},
|
||||||
""};
|
""};
|
||||||
|
|
||||||
std::unique_ptr<Widget> options_widget{};
|
std::unique_ptr<Widget> options_widget{};
|
||||||
|
@ -216,23 +216,10 @@ size_t LevelView::change_mode(freqman_index_t new_mod) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void LevelView::handle_coded_squelch(const uint32_t value) {
|
void LevelView::handle_coded_squelch(const uint32_t value) {
|
||||||
static tone_index last_squelch_index = -1;
|
if (field_mode.selected_index() == NFM_MODULATION)
|
||||||
|
text_ctcss.set(tone_key_string_by_value(value, text_ctcss.parent_rect().width() / 8));
|
||||||
if (field_mode.selected_index() == NFM_MODULATION) {
|
else
|
||||||
tone_index idx = tone_key_index_by_value(value);
|
text_ctcss.set(" ");
|
||||||
|
|
||||||
if ((last_squelch_index < 0) || (last_squelch_index != idx)) {
|
|
||||||
last_squelch_index = idx;
|
|
||||||
if (idx >= 0) {
|
|
||||||
text_ctcss.set("T: " + tone_key_string(idx));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
text_ctcss.set(" ");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} /* namespace ui */
|
} /* namespace ui */
|
||||||
|
@ -114,7 +114,7 @@ class LevelView : public View {
|
|||||||
}};
|
}};
|
||||||
|
|
||||||
Text text_ctcss{
|
Text text_ctcss{
|
||||||
{22 * 8, 3 * 16 + 4, 14 * 8, 1 * 8},
|
{22 * 8, 3 * 16 + 4, 8 * 8, 1 * 8},
|
||||||
""};
|
""};
|
||||||
|
|
||||||
// RSSI: XX/XX/XXX,dt: XX
|
// RSSI: XX/XX/XXX,dt: XX
|
||||||
|
@ -269,7 +269,7 @@ class MicTXView : public View {
|
|||||||
|
|
||||||
OptionsField options_tone_key{
|
OptionsField options_tone_key{
|
||||||
{12 * 8, (13 * 8) - 5},
|
{12 * 8, (13 * 8) - 5},
|
||||||
23,
|
18,
|
||||||
{}};
|
{}};
|
||||||
|
|
||||||
Checkbox check_rogerbeep{
|
Checkbox check_rogerbeep{
|
||||||
|
@ -1426,20 +1426,10 @@ size_t ReconView::change_mode(freqman_index_t new_mod) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ReconView::handle_coded_squelch(const uint32_t value) {
|
void ReconView::handle_coded_squelch(const uint32_t value) {
|
||||||
if (field_mode.selected_index() == NFM_MODULATION) {
|
if (field_mode.selected_index() == NFM_MODULATION)
|
||||||
tone_index idx = tone_key_index_by_value(value);
|
text_ctcss.set(tone_key_string_by_value(value, text_ctcss.parent_rect().width() / 8));
|
||||||
|
else
|
||||||
if ((last_squelch_index < 0) || (last_squelch_index != idx)) {
|
text_ctcss.set(" ");
|
||||||
last_squelch_index = idx;
|
|
||||||
if (idx >= 0) {
|
|
||||||
text_ctcss.set("T: " + tone_key_string(idx));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
text_ctcss.set(" ");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} /* namespace ui */
|
} /* namespace ui */
|
||||||
|
@ -139,7 +139,6 @@ class ReconView : public View {
|
|||||||
int8_t last_rssi_med{-127};
|
int8_t last_rssi_med{-127};
|
||||||
int8_t last_rssi_max{-127};
|
int8_t last_rssi_max{-127};
|
||||||
int32_t last_index{-1};
|
int32_t last_index{-1};
|
||||||
tone_index last_squelch_index{-1};
|
|
||||||
int64_t last_freq{0};
|
int64_t last_freq{0};
|
||||||
std::string freq_file_path{};
|
std::string freq_file_path{};
|
||||||
systime_t chrono_start{};
|
systime_t chrono_start{};
|
||||||
|
@ -122,6 +122,8 @@ bool load_freqman_file(std::string& file_stem, freqman_db& db, bool load_freqs,
|
|||||||
freqman_index_t bandwidth = -1;
|
freqman_index_t bandwidth = -1;
|
||||||
freqman_index_t step = -1;
|
freqman_index_t step = -1;
|
||||||
freqman_index_t tone = -1;
|
freqman_index_t tone = -1;
|
||||||
|
uint32_t tone_freq;
|
||||||
|
char c;
|
||||||
|
|
||||||
auto result = freqman_file.open("FREQMAN/" + file_stem + ".TXT");
|
auto result = freqman_file.open("FREQMAN/" + file_stem + ".TXT");
|
||||||
if (result.is_valid())
|
if (result.is_valid())
|
||||||
@ -210,12 +212,26 @@ bool load_freqman_file(std::string& file_stem, freqman_db& db, bool load_freqs,
|
|||||||
step = freqman_entry_get_step_from_str_short(pos);
|
step = freqman_entry_get_step_from_str_short(pos);
|
||||||
}
|
}
|
||||||
// ctcss tone if any
|
// ctcss tone if any
|
||||||
/* disabled until better form
|
pos = strstr(line_start, "c=");
|
||||||
pos = strstr(line_start, "c=");
|
if (pos) {
|
||||||
if (pos) {
|
pos += 2;
|
||||||
pos += 2;
|
// find decimal point and replace with 0 if there is one, for strtoll
|
||||||
tone = tone_key_index_by_value( strtoll( pos , nullptr , 10 ) );
|
length = strcspn(pos, ".,\x0A");
|
||||||
} */
|
if (pos + length <= line_end) {
|
||||||
|
c = *(pos + length);
|
||||||
|
*(pos + length) = 0;
|
||||||
|
// ASCII Hz to integer Hz x 100
|
||||||
|
tone_freq = strtoll(pos, nullptr, 10) * 100;
|
||||||
|
// stuff saved character back into string in case it was not a decimal point
|
||||||
|
*(pos + length) = c;
|
||||||
|
// now get first digit after decimal point (10ths of Hz)
|
||||||
|
pos += length + 1;
|
||||||
|
if (c == '.' && *pos >= '0' && *pos <= '9')
|
||||||
|
tone_freq += (*pos - '0') * 10;
|
||||||
|
// convert tone_freq (100x the freq in Hz) to a tone_key index
|
||||||
|
tone = tone_key_index_by_value(tone_freq);
|
||||||
|
}
|
||||||
|
}
|
||||||
// Read description until , or LF
|
// Read description until , or LF
|
||||||
pos = strstr(line_start, "d=");
|
pos = strstr(line_start, "d=");
|
||||||
if (pos) {
|
if (pos) {
|
||||||
@ -284,7 +300,7 @@ bool get_freq_string(freqman_entry& entry, std::string& item_string) {
|
|||||||
item_string = "r=" + to_string_dec_uint(frequency_a / 1000) + to_string_dec_uint(frequency_a % 1000UL, 3, '0');
|
item_string = "r=" + to_string_dec_uint(frequency_a / 1000) + to_string_dec_uint(frequency_a % 1000UL, 3, '0');
|
||||||
item_string += ",t=" + to_string_dec_uint(frequency_b / 1000) + to_string_dec_uint(frequency_b % 1000UL, 3, '0');
|
item_string += ",t=" + to_string_dec_uint(frequency_b / 1000) + to_string_dec_uint(frequency_b % 1000UL, 3, '0');
|
||||||
if (entry.tone >= 0) {
|
if (entry.tone >= 0) {
|
||||||
item_string += ",c=" + tone_key_string(entry.tone);
|
item_string += ",c=" + tone_key_value_string(entry.tone);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (entry.modulation >= 0 && (unsigned)entry.modulation < freqman_entry_modulations.size()) {
|
if (entry.modulation >= 0 && (unsigned)entry.modulation < freqman_entry_modulations.size()) {
|
||||||
|
@ -27,62 +27,66 @@ namespace tonekey {
|
|||||||
|
|
||||||
// Keep list in ascending order by tone frequency
|
// Keep list in ascending order by tone frequency
|
||||||
const tone_key_t tone_keys = {
|
const tone_key_t tone_keys = {
|
||||||
{"None", 0.0},
|
{"None", F2Ix100(0.0)},
|
||||||
{"1 XZ", 67.000},
|
{"1 XZ", F2Ix100(67.0)},
|
||||||
{"39 WZ", 69.300},
|
{"39 WZ", F2Ix100(69.3)},
|
||||||
{"2 XA", 71.900},
|
{"2 XA", F2Ix100(71.9)},
|
||||||
{"3 WA", 74.400},
|
{"3 WA", F2Ix100(74.4)},
|
||||||
{"4 XB", 77.000},
|
{"4 XB", F2Ix100(77.0)},
|
||||||
{"5 WB", 79.700},
|
{"5 WB", F2Ix100(79.7)},
|
||||||
{"6 YZ", 82.500},
|
{"6 YZ", F2Ix100(82.5)},
|
||||||
{"7 YA", 85.400},
|
{"7 YA", F2Ix100(85.4)},
|
||||||
{"8 YB", 88.500},
|
{"8 YB", F2Ix100(88.5)},
|
||||||
{"9 ZZ", 91.500},
|
{"9 ZZ", F2Ix100(91.5)},
|
||||||
{"10 ZA", 94.800},
|
{"10 ZA", F2Ix100(94.8)},
|
||||||
{"11 ZB", 97.400},
|
{"11 ZB", F2Ix100(97.4)},
|
||||||
{"12 1Z", 100.000},
|
{"12 1Z", F2Ix100(100.0)},
|
||||||
{"13 1A", 103.500},
|
{"13 1A", F2Ix100(103.5)},
|
||||||
{"14 1B", 107.200},
|
{"14 1B", F2Ix100(107.2)},
|
||||||
{"15 2Z", 110.900},
|
{"15 2Z", F2Ix100(110.9)},
|
||||||
{"16 2A", 114.800},
|
{"16 2A", F2Ix100(114.8)},
|
||||||
{"17 2B", 118.800},
|
{"17 2B", F2Ix100(118.8)},
|
||||||
{"18 3Z", 123.000},
|
{"18 3Z", F2Ix100(123.0)},
|
||||||
{"19 3A", 127.300},
|
{"19 3A", F2Ix100(127.3)},
|
||||||
{"20 3B", 131.800},
|
{"20 3B", F2Ix100(131.8)},
|
||||||
{"21 4Z", 136.500},
|
{"21 4Z", F2Ix100(136.5)},
|
||||||
{"22 4A", 141.300},
|
{"22 4A", F2Ix100(141.3)},
|
||||||
{"23 4B", 146.200},
|
{"23 4B", F2Ix100(146.2)},
|
||||||
{"24 5Z", 151.400},
|
{"24 5Z", F2Ix100(151.4)},
|
||||||
{"25 5A", 156.700},
|
{"25 5A", F2Ix100(156.7)},
|
||||||
{"40 --", 159.800},
|
{"40 --", F2Ix100(159.8)},
|
||||||
{"26 5B", 162.200},
|
{"26 5B", F2Ix100(162.2)},
|
||||||
{"41 --", 165.500},
|
{"41 --", F2Ix100(165.5)},
|
||||||
{"27 6Z", 167.900},
|
{"27 6Z", F2Ix100(167.9)},
|
||||||
{"42 --", 171.300},
|
{"42 --", F2Ix100(171.3)},
|
||||||
{"28 6A", 173.800},
|
{"28 6A", F2Ix100(173.8)},
|
||||||
{"43 --", 177.300},
|
{"43 --", F2Ix100(177.3)},
|
||||||
{"29 6B", 179.900},
|
{"29 6B", F2Ix100(179.9)},
|
||||||
{"44 --", 183.500},
|
{"44 --", F2Ix100(183.5)},
|
||||||
{"30 7Z", 186.200},
|
{"30 7Z", F2Ix100(186.2)},
|
||||||
{"45 --", 189.900},
|
{"45 --", F2Ix100(189.9)},
|
||||||
{"31 7A", 192.800},
|
{"31 7A", F2Ix100(192.8)},
|
||||||
{"46 --", 196.600},
|
{"46 --", F2Ix100(196.6)},
|
||||||
{"47 --", 199.500},
|
{"47 --", F2Ix100(199.5)},
|
||||||
{"32 M1", 203.500},
|
{"32 M1", F2Ix100(203.5)},
|
||||||
{"48 8Z", 206.500},
|
{"48 8Z", F2Ix100(206.5)},
|
||||||
{"33 M2", 210.700},
|
{"33 M2", F2Ix100(210.7)},
|
||||||
{"34 M3", 218.100},
|
{"34 M3", F2Ix100(218.1)},
|
||||||
{"35 M4", 225.700},
|
{"35 M4", F2Ix100(225.7)},
|
||||||
{"49 9Z", 229.100},
|
{"49 9Z", F2Ix100(229.1)},
|
||||||
{"36 M5", 233.600},
|
{"36 M5", F2Ix100(233.6)},
|
||||||
{"37 M6", 241.800},
|
{"37 M6", F2Ix100(241.8)},
|
||||||
{"38 M7", 250.300},
|
{"38 M7", F2Ix100(250.3)},
|
||||||
{"50 0Z", 254.100},
|
{"50 0Z", F2Ix100(254.1)},
|
||||||
{"Shure 19kHz", 19000.0},
|
{"Shure 19kHz", F2Ix100(19000.0)},
|
||||||
{"Axient 28kHz", 28000.0},
|
{"Axient 28kHz", F2Ix100(28000.0)},
|
||||||
{"Senn. 32.000k", 32000.0},
|
{"Senn. 32.000k", F2Ix100(32000.0)},
|
||||||
{"Sony 32.382k", 32382.0},
|
{"Sony 32.382k", F2Ix100(32382.0)},
|
||||||
{"Senn. 32.768k", 32768.0}};
|
{"Senn. 32.768k", F2Ix100(32768.0)}};
|
||||||
|
|
||||||
|
std::string fx100_string(uint32_t f) {
|
||||||
|
return to_string_dec_uint(f / 100) + "." + to_string_dec_uint((f / 10) % 10);
|
||||||
|
}
|
||||||
|
|
||||||
void tone_keys_populate(OptionsField& field) {
|
void tone_keys_populate(OptionsField& field) {
|
||||||
using option_t = std::pair<std::string, int32_t>;
|
using option_t = std::pair<std::string, int32_t>;
|
||||||
@ -91,12 +95,11 @@ void tone_keys_populate(OptionsField& field) {
|
|||||||
std::string tone_name;
|
std::string tone_name;
|
||||||
|
|
||||||
for (size_t c = 0; c < tone_keys.size(); c++) {
|
for (size_t c = 0; c < tone_keys.size(); c++) {
|
||||||
if (c && c < 51) {
|
auto f = tone_keys[c].second;
|
||||||
auto f = tone_keys[c].second;
|
if ((c != 0) && (f < 1000 * 100))
|
||||||
tone_name = "CTCSS " + tone_keys[c].first + " " + to_string_dec_uint(f) + "." + to_string_dec_uint((uint32_t)(f * 10) % 10);
|
tone_name = "CTCSS " + fx100_string(f) + " #" + tone_keys[c].first;
|
||||||
} else {
|
else
|
||||||
tone_name = tone_keys[c].first;
|
tone_name = tone_keys[c].first;
|
||||||
}
|
|
||||||
|
|
||||||
tone_key_options.emplace_back(tone_name, c);
|
tone_key_options.emplace_back(tone_name, c);
|
||||||
}
|
}
|
||||||
@ -104,8 +107,8 @@ void tone_keys_populate(OptionsField& field) {
|
|||||||
field.set_options(tone_key_options);
|
field.set_options(tone_key_options);
|
||||||
}
|
}
|
||||||
|
|
||||||
float tone_key_frequency(const tone_index index) {
|
float tone_key_frequency(tone_index index) {
|
||||||
return tone_keys[index].second;
|
return float(tone_keys[index].second) / 100.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string tone_key_string(tone_index index) {
|
std::string tone_key_string(tone_index index) {
|
||||||
@ -114,20 +117,65 @@ std::string tone_key_string(tone_index index) {
|
|||||||
return tone_keys[index].first;
|
return tone_keys[index].first;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string tone_key_string_by_value(uint32_t value) {
|
// Return string showing frequency only from specific table index
|
||||||
return tone_key_string(tone_key_index_by_value(value));
|
std::string tone_key_value_string(tone_index index) {
|
||||||
|
if (index < 0 || (unsigned)index >= tone_keys.size())
|
||||||
|
return std::string("");
|
||||||
|
return fx100_string(tone_keys[index].second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return variable-length string showing CTCSS tone from tone frequency
|
||||||
|
// Value is in 0.01 Hz units
|
||||||
|
std::string tone_key_string_by_value(uint32_t value, size_t max_length) {
|
||||||
|
static uint8_t tone_display_toggle{0};
|
||||||
|
static uint32_t last_value;
|
||||||
|
tone_index idx;
|
||||||
|
std::string freq_str;
|
||||||
|
|
||||||
|
// If >10Hz difference between consecutive samples, it's probably noise, so ignore
|
||||||
|
if (abs(value - last_value) > 10 * 100) {
|
||||||
|
last_value = value;
|
||||||
|
tone_display_toggle = 0;
|
||||||
|
return " ";
|
||||||
|
}
|
||||||
|
last_value = value;
|
||||||
|
|
||||||
|
// Only display 1/10 Hz accuracy if <1000 Hz; max 5 characters
|
||||||
|
if (value < 1000 * 100)
|
||||||
|
freq_str = "T:" + fx100_string(value);
|
||||||
|
else
|
||||||
|
freq_str = "T:" + to_string_dec_uint(value / 100);
|
||||||
|
|
||||||
|
// Check field length is enough for character counts in the string below
|
||||||
|
if (max_length >= 7 + 2 + 5) {
|
||||||
|
idx = tone_key_index_by_value(value);
|
||||||
|
if (idx != -1)
|
||||||
|
return freq_str + " #" + tone_key_string(idx);
|
||||||
|
} else {
|
||||||
|
// Not enough space; toggle between display of tone received and tone code #
|
||||||
|
if (tone_display_toggle++ >= TONE_DISPLAY_TOGGLE_COUNTER) {
|
||||||
|
if (tone_display_toggle >= TONE_DISPLAY_TOGGLE_COUNTER * 2) tone_display_toggle = 0;
|
||||||
|
|
||||||
|
// Look for a match in the table (otherwise just display frequency)
|
||||||
|
idx = tone_key_index_by_value(value);
|
||||||
|
if (idx != -1)
|
||||||
|
return "T:" + tone_key_string(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return freq_str;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search tone_key table for tone frequency value
|
||||||
|
// Value is in 0.01 Hz units
|
||||||
tone_index tone_key_index_by_value(uint32_t value) {
|
tone_index tone_key_index_by_value(uint32_t value) {
|
||||||
float diff;
|
uint32_t diff;
|
||||||
float min_diff{(float)value};
|
uint32_t min_diff{value * 2};
|
||||||
float fvalue{(float)(min_diff / 100.0)};
|
|
||||||
tone_index min_idx{-1};
|
tone_index min_idx{-1};
|
||||||
tone_index idx;
|
tone_index idx;
|
||||||
|
|
||||||
// Find nearest match
|
// Find nearest match
|
||||||
for (idx = 0; idx < (tone_index)tone_keys.size(); idx++) {
|
for (idx = 0; idx < (tone_index)tone_keys.size(); idx++) {
|
||||||
diff = abs(fvalue - tone_keys[idx].second);
|
diff = abs(value - tone_keys[idx].second);
|
||||||
if (diff < min_diff) {
|
if (diff < min_diff) {
|
||||||
min_idx = idx;
|
min_idx = idx;
|
||||||
min_diff = diff;
|
min_diff = diff;
|
||||||
@ -138,7 +186,7 @@ tone_index tone_key_index_by_value(uint32_t value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Arbitrary confidence threshold
|
// Arbitrary confidence threshold
|
||||||
if (min_diff < 40.0)
|
if (min_diff < TONE_FREQ_TOLERANCE_CENTIHZ)
|
||||||
return min_idx;
|
return min_idx;
|
||||||
else
|
else
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -30,17 +30,22 @@ using namespace ui;
|
|||||||
|
|
||||||
namespace tonekey {
|
namespace tonekey {
|
||||||
|
|
||||||
|
#define TONE_FREQ_TOLERANCE_CENTIHZ (4 * 100)
|
||||||
|
#define TONE_DISPLAY_TOGGLE_COUNTER 3
|
||||||
|
#define F2Ix100(x) (int32_t)(x * 100.0)
|
||||||
|
|
||||||
typedef int32_t tone_index;
|
typedef int32_t tone_index;
|
||||||
|
|
||||||
using tone_key_t = std::vector<std::pair<std::string, float>>;
|
using tone_key_t = std::vector<std::pair<std::string, uint32_t>>;
|
||||||
|
|
||||||
extern const tone_key_t tone_keys;
|
extern const tone_key_t tone_keys;
|
||||||
|
|
||||||
void tone_keys_populate(OptionsField& field);
|
void tone_keys_populate(OptionsField& field);
|
||||||
float tone_key_frequency(const tone_index index);
|
float tone_key_frequency(tone_index index);
|
||||||
|
|
||||||
std::string tone_key_string(const tone_index index);
|
std::string tone_key_string(tone_index index);
|
||||||
std::string tone_key_string_by_value(uint32_t value);
|
std::string tone_key_value_string(tone_index index);
|
||||||
|
std::string tone_key_string_by_value(uint32_t value, size_t max_length);
|
||||||
tone_index tone_key_index_by_value(uint32_t value);
|
tone_index tone_key_index_by_value(uint32_t value);
|
||||||
|
|
||||||
} // namespace tonekey
|
} // namespace tonekey
|
||||||
|
@ -53,7 +53,9 @@ void NarrowbandFMAudio::execute(const buffer_c8_t& buffer) {
|
|||||||
if (ctcss_detect_enabled) {
|
if (ctcss_detect_enabled) {
|
||||||
/* 24kHz int16_t[16]
|
/* 24kHz int16_t[16]
|
||||||
* -> FIR filter, <300Hz pass, >300Hz stop, gain of 1
|
* -> FIR filter, <300Hz pass, >300Hz stop, gain of 1
|
||||||
* -> 12kHz int16_t[8] */
|
* -> 12kHz int16_t[8]
|
||||||
|
*
|
||||||
|
* Note we're only processing a small section of the wave each time this fn is called */
|
||||||
auto audio_ctcss = ctcss_filter.execute(audio, work_audio_buffer);
|
auto audio_ctcss = ctcss_filter.execute(audio, work_audio_buffer);
|
||||||
|
|
||||||
// s16 to f32 for hpf
|
// s16 to f32 for hpf
|
||||||
@ -79,9 +81,11 @@ void NarrowbandFMAudio::execute(const buffer_c8_t& buffer) {
|
|||||||
prev_sample = cur_sample;
|
prev_sample = cur_sample;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (z_count >= 30) {
|
z_filter_count++;
|
||||||
|
if ((z_filter_count >= Z_MIN_FILTER_COUNT) && (z_count >= Z_MIN_ZERO_CROSSINGS)) {
|
||||||
ctcss_message.value = (100 * 12000 / 2 * z_count) / z_acc;
|
ctcss_message.value = (100 * 12000 / 2 * z_count) / z_acc;
|
||||||
shared_memory.application_queue.push(ctcss_message);
|
shared_memory.application_queue.push(ctcss_message);
|
||||||
|
z_filter_count = 0;
|
||||||
z_count = 0;
|
z_count = 0;
|
||||||
z_acc = 0;
|
z_acc = 0;
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,9 @@
|
|||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
#define Z_MIN_FILTER_COUNT 224
|
||||||
|
#define Z_MIN_ZERO_CROSSINGS 20
|
||||||
|
|
||||||
class NarrowbandFMAudio : public BasebandProcessor {
|
class NarrowbandFMAudio : public BasebandProcessor {
|
||||||
public:
|
public:
|
||||||
void execute(const buffer_c8_t& buffer) override;
|
void execute(const buffer_c8_t& buffer) override;
|
||||||
@ -88,7 +91,7 @@ class NarrowbandFMAudio : public BasebandProcessor {
|
|||||||
bool pitch_rssi_enabled{false};
|
bool pitch_rssi_enabled{false};
|
||||||
|
|
||||||
float cur_sample{}, prev_sample{};
|
float cur_sample{}, prev_sample{};
|
||||||
uint32_t z_acc{0}, z_timer{0}, z_count{0};
|
uint32_t z_acc{0}, z_timer{0}, z_count{0}, z_filter_count{0};
|
||||||
bool ctcss_detect_enabled{true};
|
bool ctcss_detect_enabled{true};
|
||||||
static constexpr float k = 32768.0f;
|
static constexpr float k = 32768.0f;
|
||||||
static constexpr float ki = 1.0f / k;
|
static constexpr float ki = 1.0f / k;
|
||||||
|
Loading…
Reference in New Issue
Block a user