Added back frequency display for CTCSS

Attempted to fix replay, just fixed StreamBuffer read() and added
waterfall display...
Updated binary
This commit is contained in:
furrtek 2017-12-06 13:20:51 +00:00
parent d77337dd77
commit 3221992ad1
18 changed files with 133 additions and 54 deletions

View File

@ -333,12 +333,11 @@ void AnalogAudioView::squelched() {
} }
void AnalogAudioView::handle_coded_squelch(const uint32_t value) { void AnalogAudioView::handle_coded_squelch(const uint32_t value) {
//const std::string value_string = to_string_dec_uint(value / 10) + "." + to_string_dec_uint(value % 10);
float diff, min_diff = value; float diff, min_diff = value;
size_t min_idx { 0 }; size_t min_idx { 0 };
size_t c; size_t c;
for (c = 0; c < KEY_TONES_NB; c++) { for (c = 0; c < tone_keys.size(); c++) {
diff = abs(((float)value / 100.0) - tone_keys[c].second); diff = abs(((float)value / 100.0) - tone_keys[c].second);
if (diff < min_diff) { if (diff < min_diff) {
min_idx = c; min_idx = c;

View File

@ -27,6 +27,7 @@
//TEST: Check AFSK transmit end, skips last bits ? //TEST: Check AFSK transmit end, skips last bits ?
//TEST: Imperial in whipcalc //TEST: Imperial in whipcalc
//BUG: Crash on rename file with long filename
//BUG: Auto backlight off doesn't work anymore //BUG: Auto backlight off doesn't work anymore
//BUG: CPLD-related rx ok, tx bad, see portapack.cpp lines 214+ to disable CPLD overlay //BUG: CPLD-related rx ok, tx bad, see portapack.cpp lines 214+ to disable CPLD overlay
//BUG: REPLAY See what's wrong with quality (format, or need for interpolation filter ?) //BUG: REPLAY See what's wrong with quality (format, or need for interpolation filter ?)

View File

@ -51,7 +51,7 @@ ReplayAppView::ReplayAppView(
&field_frequency_step, &field_frequency_step,
&field_rf_amp, &field_rf_amp,
&replay_view, &replay_view,
//&waterfall, &waterfall,
}); });
replay_view.set_file_list(file_list); replay_view.set_file_list(file_list);
@ -89,17 +89,16 @@ ReplayAppView::~ReplayAppView() {
void ReplayAppView::on_hide() { void ReplayAppView::on_hide() {
// TODO: Terrible kludge because widget system doesn't notify Waterfall that // TODO: Terrible kludge because widget system doesn't notify Waterfall that
// it's being shown or hidden. // it's being shown or hidden.
waterfall.on_hide();
//waterfall.on_hide();
View::on_hide(); View::on_hide();
} }
/*void ReplayAppView::set_parent_rect(const Rect new_parent_rect) { void ReplayAppView::set_parent_rect(const Rect new_parent_rect) {
View::set_parent_rect(new_parent_rect); View::set_parent_rect(new_parent_rect);
const ui::Rect waterfall_rect { 0, header_height, new_parent_rect.width(), static_cast<ui::Dim>(new_parent_rect.height() - header_height) }; const ui::Rect waterfall_rect { 0, header_height, new_parent_rect.width(), new_parent_rect.height() - header_height };
waterfall.set_parent_rect(waterfall_rect); waterfall.set_parent_rect(waterfall_rect);
}*/ }
void ReplayAppView::focus() { void ReplayAppView::focus() {
if (!file_error) { if (!file_error) {

View File

@ -41,7 +41,7 @@ public:
void on_hide() override; void on_hide() override;
//void set_parent_rect(const Rect new_parent_rect) override; void set_parent_rect(const Rect new_parent_rect) override;
void focus() override; void focus() override;
@ -54,9 +54,6 @@ private:
static constexpr ui::Dim header_height = 2 * 16; static constexpr ui::Dim header_height = 2 * 16;
static constexpr uint32_t sampling_rate = 500000;
static constexpr uint32_t baseband_bandwidth = 2500000;
void on_target_frequency_changed(rf::Frequency f); void on_target_frequency_changed(rf::Frequency f);
rf::Frequency target_frequency() const; rf::Frequency target_frequency() const;
@ -79,7 +76,7 @@ private:
16384, 3 16384, 3
}; };
//spectrum::WaterfallWidget waterfall { }; spectrum::WaterfallWidget waterfall { };
}; };
} /* namespace ui */ } /* namespace ui */

View File

@ -77,14 +77,46 @@ Optional<File::Error> ReplayThread::run() {
BasebandReplay replay { &config }; BasebandReplay replay { &config };
BufferExchange buffers { &config }; BufferExchange buffers { &config };
while( !chThdShouldTerminate() ) { StreamBuffer* prefill_buffer { nullptr };
auto buffer = buffers.get();
auto read_result = reader->read(buffer->data(), buffer->capacity()); // TESTING: Prefill
buffer->set_size(buffer->capacity()); // While empty buffers fifo is not empty...
while (!buffers.empty()) {
prefill_buffer = buffers.get_prefill();
if (prefill_buffer == nullptr) {
buffers.put_app(prefill_buffer);
} else {
size_t blocks = prefill_buffer->capacity() / 512;
for (size_t c = 0; c < blocks; c++) {
auto read_result = reader->read(&((uint8_t*)prefill_buffer->data())[c * 512], 512);
if( read_result.is_error() ) { if( read_result.is_error() ) {
return read_result.error(); return read_result.error();
} }
}
prefill_buffer->set_size(prefill_buffer->capacity());
buffers.put(prefill_buffer);
//if (!buffers.put(prefill_buffer)) for(;;) {};
}
};
while( !chThdShouldTerminate() ) {
auto buffer = buffers.get();
size_t blocks = buffer->capacity() / 512;
for (size_t c = 0; c < blocks; c++) {
auto read_result = reader->read(&((uint8_t*)buffer->data())[c * 512], 512);
if( read_result.is_error() ) {
return read_result.error();
}
}
buffer->set_size(buffer->capacity());
buffers.put(buffer); buffers.put(buffer);
} }

View File

@ -20,12 +20,12 @@
* Boston, MA 02110-1301, USA. * Boston, MA 02110-1301, USA.
*/ */
#include "tone_key.hpp"
#include "string_format.hpp" #include "string_format.hpp"
#include "tone_key.hpp"
namespace tonekey { namespace tonekey {
const tone_key_t tone_keys[] = { const tone_key_t tone_keys = {
{ "None", 0.0 }, { "None", 0.0 },
{ "0 XZ", 67.000 }, { "0 XZ", 67.000 },
{ "1 WZ", 69.400 }, { "1 WZ", 69.400 },
@ -90,14 +90,22 @@ void tone_keys_populate(OptionsField& field) {
options_t tone_key_options; options_t tone_key_options;
std::string tone_name; std::string tone_name;
for (size_t c = 0; c < KEY_TONES_NB; c++) { for (size_t c = 0; c < tone_keys.size(); c++) {
if (c && (c < 51)) if (c && c < 51) {
tone_name = "CTCSS " + tone_keys[c].first; auto f = tone_keys[c].second;
else tone_name = "CTCSS " + tone_keys[c].first + " " + to_string_dec_uint(f) + "." + to_string_dec_uint((uint32_t)(f * 10) % 10);
} 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);
} }
field.set_options(tone_key_options); field.set_options(tone_key_options);
} }
float tone_key_frequency(const uint32_t index) {
return tone_keys[index].second;
}
} }

View File

@ -28,15 +28,14 @@
using namespace ui; using namespace ui;
#define KEY_TONES_NB 56
namespace tonekey { namespace tonekey {
using tone_key_t = std::pair<std::string, float>; using tone_key_t = std::vector<std::pair<std::string, float>>;
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 uint32_t index);
} }

View File

@ -59,7 +59,7 @@ void MicTXView::configure_baseband() {
sampling_rate / 20, // Update vu-meter at 20Hz sampling_rate / 20, // Update vu-meter at 20Hz
transmitting ? transmitter_model.channel_bandwidth() : 0, transmitting ? transmitter_model.channel_bandwidth() : 0,
mic_gain_x10, mic_gain_x10,
TONES_F2D(tone_keys[tone_key_index].second), TONES_F2D(tone_key_frequency(tone_key_index)),
0.2 // 20% mix 0.2 // 20% mix
); );
} }

View File

@ -91,7 +91,7 @@ void ReplayView::set_file_list(const std::vector<std::filesystem::path>& file_li
for (const auto& file : file_list) { for (const auto& file : file_list) {
bbd_file.open("/" + file.string()); bbd_file.open("/" + file.string());
duration = bbd_file.size() / (2 * 2 * sampling_rate / 4); duration = bbd_file.size() / (2 * 2 * sampling_rate / 8);
file_options.emplace_back(file.string().substr(0, 8), duration); file_options.emplace_back(file.string().substr(0, 8), duration);
} }
options_files.set_options(file_options); options_files.set_options(file_options);

View File

@ -105,7 +105,7 @@ private:
std::unique_ptr<ReplayThread> replay_thread { }; std::unique_ptr<ReplayThread> replay_thread { };
MessageHandlerRegistration message_handler_capture_thread_error { MessageHandlerRegistration message_handler_replay_thread_error {
Message::ID::CaptureThreadDone, Message::ID::CaptureThreadDone,
[this](const Message* const p) { [this](const Message* const p) {
const auto message = *reinterpret_cast<const ReplayThreadDoneMessage*>(p); const auto message = *reinterpret_cast<const ReplayThreadDoneMessage*>(p);

View File

@ -127,7 +127,7 @@ void SoundBoardView::play_sound(uint16_t id) {
divider, divider,
number_bw.value() * 1000, number_bw.value() * 1000,
10, 10,
TONES_F2D(tone_keys[tone_key_index].second), TONES_F2D(tone_key_frequency(tone_key_index)),
0.2 // 20% mix 0.2 // 20% mix
); );
} }

View File

@ -21,19 +21,20 @@
*/ */
#include "proc_replay.hpp" #include "proc_replay.hpp"
#include "sine_table_int8.hpp"
#include "event_m4.hpp" #include "event_m4.hpp"
#include "utility.hpp" #include "utility.hpp"
ReplayProcessor::ReplayProcessor() { ReplayProcessor::ReplayProcessor() {
// TODO: Interpolation filter needed ! channel_filter_pass_f = taps_200k_decim_1.pass_frequency_normalized * 1000000; // 162760.416666667
channel_filter_stop_f = taps_200k_decim_1.stop_frequency_normalized * 1000000; // 337239.583333333
/*spectrum_interval_samples = baseband_fs / spectrum_rate_hz; spectrum_interval_samples = (baseband_fs / 8) / spectrum_rate_hz;
spectrum_samples = 0; spectrum_samples = 0;
channel_spectrum.set_decimation_factor(1);*/ channel_spectrum.set_decimation_factor(1);
} }
void ReplayProcessor::execute(const buffer_c8_t& buffer) { void ReplayProcessor::execute(const buffer_c8_t& buffer) {
@ -43,13 +44,13 @@ void ReplayProcessor::execute(const buffer_c8_t& buffer) {
// File data is in C16 format, we need C8 // File data is in C16 format, we need C8
// File samplerate is 500kHz, we're at 4MHz // File samplerate is 500kHz, we're at 4MHz
// iq_buffer can only be 512 samples (RAM limitation) // iq_buffer can only be 512 C16 samples (RAM limitation)
// For a full 2048-sample C8 buffer, we need: // To fill up the 2048-sample C8 buffer, we need:
// 2048 samples * 2 bytes per sample = 4096 bytes // 2048 samples * 2 bytes per sample = 4096 bytes
// Since we're oversampling by 4M/500k = 8, we only need 2048/8 = 256 samples from the file // Since we're oversampling by 4M/500k = 8, we only need 2048/8 = 256 samples from the file and duplicate them 8 times each
// So 256 * 4 bytes per sample (C16) = 1024 bytes from the file // So 256 * 4 bytes per sample (C16) = 1024 bytes from the file
if( stream ) { if( stream ) {
const size_t bytes_to_read = sizeof(*buffer.p) * 2 * (buffer.count / 8); // *2 (C16), /8 (oversampling) const size_t bytes_to_read = sizeof(*buffer.p) * 2 * (buffer.count / 8); // *2 (C16), /8 (oversampling) should be == 1024
const auto result = stream->read(iq_buffer.p, bytes_to_read); const auto result = stream->read(iq_buffer.p, bytes_to_read);
} }
@ -57,25 +58,39 @@ void ReplayProcessor::execute(const buffer_c8_t& buffer) {
// Zero-stuff // Zero-stuff
for (size_t i = 0; i < buffer.count; i++) { for (size_t i = 0; i < buffer.count; i++) {
if (i & 3)
buffer.p[i] = { 0, 0 }; // DEBUG: This works. Transmits a 1kHz tone
else /*sample = (sine_table_i8[(tone_phase & 0xFF000000) >> 24]);
buffer.p[i] = { iq_buffer.p[i >> 3].real() >> 8, iq_buffer.p[i >> 3].imag() >> 8 }; tone_phase += (1000 * ((1ULL << 32) / baseband_fs));
// Do FM
delta = sample * 30000 * (0xFFFFFFULL / baseband_fs);
phase += delta;
sphase = phase + (64 << 24);
iq_buffer.p[i >> 3] = { (int16_t)(sine_table_i8[(sphase & 0xFF000000) >> 24]) << 8, (int16_t)(sine_table_i8[(phase & 0xFF000000) >> 24]) << 8 };
*/
/*if (i & 3)
buffer.p[i] = buffer.p[i - 1];
else {*/
auto re_out = iq_buffer.p[i >> 3].real() >> 8;
auto im_out = iq_buffer.p[i >> 3].imag() >> 8;
buffer.p[i] = { re_out, im_out };
//}
} }
/*spectrum_samples += channel.count; spectrum_samples += buffer.count;
if( spectrum_samples >= spectrum_interval_samples ) { if( spectrum_samples >= spectrum_interval_samples ) {
spectrum_samples -= spectrum_interval_samples; spectrum_samples -= spectrum_interval_samples;
channel_spectrum.feed(channel, channel_filter_pass_f, channel_filter_stop_f); channel_spectrum.feed(iq_buffer, channel_filter_pass_f, channel_filter_stop_f);
}*/ }
} }
void ReplayProcessor::on_message(const Message* const message) { void ReplayProcessor::on_message(const Message* const message) {
switch(message->id) { switch(message->id) {
/*case Message::ID::UpdateSpectrum: case Message::ID::UpdateSpectrum:
case Message::ID::SpectrumStreamingConfig: case Message::ID::SpectrumStreamingConfig:
channel_spectrum.on_message(message); channel_spectrum.on_message(message);
break;*/ break;
case Message::ID::ReplayConfig: case Message::ID::ReplayConfig:
replay_config(*reinterpret_cast<const ReplayConfigMessage*>(message)); replay_config(*reinterpret_cast<const ReplayConfigMessage*>(message));

View File

@ -43,21 +43,28 @@ public:
private: private:
static constexpr size_t baseband_fs = 4000000; static constexpr size_t baseband_fs = 4000000;
//static constexpr auto spectrum_rate_hz = 50.0f; static constexpr auto spectrum_rate_hz = 50.0f;
BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Transmit }; BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Transmit };
std::array<complex16_t, 256> iq { }; // This fits in just right in allocated RAM std::array<complex16_t, 256> iq { }; // This fits in just right in allocated RAM - Too big ?
const buffer_c16_t iq_buffer { const buffer_c16_t iq_buffer {
iq.data(), iq.data(),
iq.size() iq.size()
}; };
uint32_t channel_filter_pass_f = 0;
uint32_t channel_filter_stop_f = 0;
// DEBUG
//uint32_t tone_phase { 0 }, phase { 0 }, delta { 0 }, sphase { 0 };
//int8_t sample { 0 };
std::unique_ptr<StreamOutput> stream { }; std::unique_ptr<StreamOutput> stream { };
/*SpectrumCollector channel_spectrum; SpectrumCollector channel_spectrum { };
size_t spectrum_interval_samples = 0; size_t spectrum_interval_samples = 0;
size_t spectrum_samples = 0;*/ size_t spectrum_samples = 0;
void replay_config(const ReplayConfigMessage& message); void replay_config(const ReplayConfigMessage& message);
}; };

View File

@ -35,7 +35,9 @@ StreamOutput::StreamOutput(ReplayConfig* const config) :
config->fifo_buffers_full = &fifo_buffers_full; config->fifo_buffers_full = &fifo_buffers_full;
for(size_t i=0; i<config->buffer_count; i++) { for(size_t i=0; i<config->buffer_count; i++) {
// Set buffers to point consecutively in previously allocated unique_ptr "data"
buffers[i] = { &(data.get()[i * config->read_size]), config->read_size }; buffers[i] = { &(data.get()[i * config->read_size]), config->read_size };
// Put all buffer pointers in the "empty buffer" FIFO
fifo_buffers_empty.in(&buffers[i]); fifo_buffers_empty.in(&buffers[i]);
} }
} }
@ -49,6 +51,8 @@ size_t StreamOutput::read(void* const data, const size_t length) {
// We need a full buffer... // We need a full buffer...
if( !fifo_buffers_full.out(active_buffer) ) { if( !fifo_buffers_full.out(active_buffer) ) {
// ...but none are available. Hole in transmission (inform app and stop ?) // ...but none are available. Hole in transmission (inform app and stop ?)
//active_buffer = nullptr;
//creg::m4txevent::assert();
break; break;
} }
} }

View File

@ -69,3 +69,10 @@ StreamBuffer* BufferExchange::get(FIFO<StreamBuffer*>* fifo) {
chSysUnlock(); chSysUnlock();
} }
} }
StreamBuffer* BufferExchange::get_prefill(FIFO<StreamBuffer*>* fifo) {
StreamBuffer* p { nullptr };
fifo->out(p);
return p;
}

View File

@ -47,9 +47,18 @@ public:
return get(fifo_buffers_for_application); return get(fifo_buffers_for_application);
} }
StreamBuffer* get_prefill() {
return get_prefill(fifo_buffers_for_application);
}
bool put(StreamBuffer* const p) { bool put(StreamBuffer* const p) {
return fifo_buffers_for_baseband->in(p); return fifo_buffers_for_baseband->in(p);
} }
// TESTING...
bool put_app(StreamBuffer* const p) {
return fifo_buffers_for_application->in(p);
}
#endif #endif
#if defined(LPC43XX_M4) #if defined(LPC43XX_M4)
@ -99,4 +108,6 @@ private:
} }
StreamBuffer* get(FIFO<StreamBuffer*>* fifo); StreamBuffer* get(FIFO<StreamBuffer*>* fifo);
StreamBuffer* get_prefill(FIFO<StreamBuffer*>* fifo);
}; };

View File

@ -541,7 +541,7 @@ public:
size_t read(void* p, const size_t count) { size_t read(void* p, const size_t count) {
const auto copy_size = std::min(used_, count); const auto copy_size = std::min(used_, count);
memcpy(p, &data_[used_ - copy_size], copy_size); memcpy(p, &data_[capacity_ - used_], copy_size);
used_ -= copy_size; used_ -= copy_size;
return copy_size; return copy_size;
} }

Binary file not shown.