mirror of
https://github.com/eried/portapack-mayhem.git
synced 2025-01-11 07:19:34 -05:00
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:
parent
d77337dd77
commit
3221992ad1
@ -333,12 +333,11 @@ void AnalogAudioView::squelched() {
|
||||
}
|
||||
|
||||
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;
|
||||
size_t min_idx { 0 };
|
||||
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);
|
||||
if (diff < min_diff) {
|
||||
min_idx = c;
|
||||
|
@ -27,6 +27,7 @@
|
||||
//TEST: Check AFSK transmit end, skips last bits ?
|
||||
//TEST: Imperial in whipcalc
|
||||
|
||||
//BUG: Crash on rename file with long filename
|
||||
//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: REPLAY See what's wrong with quality (format, or need for interpolation filter ?)
|
||||
|
@ -51,7 +51,7 @@ ReplayAppView::ReplayAppView(
|
||||
&field_frequency_step,
|
||||
&field_rf_amp,
|
||||
&replay_view,
|
||||
//&waterfall,
|
||||
&waterfall,
|
||||
});
|
||||
|
||||
replay_view.set_file_list(file_list);
|
||||
@ -89,17 +89,16 @@ ReplayAppView::~ReplayAppView() {
|
||||
void ReplayAppView::on_hide() {
|
||||
// TODO: Terrible kludge because widget system doesn't notify Waterfall that
|
||||
// it's being shown or hidden.
|
||||
|
||||
//waterfall.on_hide();
|
||||
waterfall.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);
|
||||
|
||||
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);
|
||||
}*/
|
||||
}
|
||||
|
||||
void ReplayAppView::focus() {
|
||||
if (!file_error) {
|
||||
|
@ -41,7 +41,7 @@ public:
|
||||
|
||||
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;
|
||||
|
||||
@ -54,9 +54,6 @@ private:
|
||||
|
||||
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);
|
||||
|
||||
rf::Frequency target_frequency() const;
|
||||
@ -79,7 +76,7 @@ private:
|
||||
16384, 3
|
||||
};
|
||||
|
||||
//spectrum::WaterfallWidget waterfall { };
|
||||
spectrum::WaterfallWidget waterfall { };
|
||||
};
|
||||
|
||||
} /* namespace ui */
|
||||
|
@ -77,14 +77,46 @@ Optional<File::Error> ReplayThread::run() {
|
||||
BasebandReplay replay { &config };
|
||||
BufferExchange buffers { &config };
|
||||
|
||||
while( !chThdShouldTerminate() ) {
|
||||
auto buffer = buffers.get();
|
||||
StreamBuffer* prefill_buffer { nullptr };
|
||||
|
||||
auto read_result = reader->read(buffer->data(), buffer->capacity());
|
||||
buffer->set_size(buffer->capacity());
|
||||
// TESTING: Prefill
|
||||
// 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() ) {
|
||||
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);
|
||||
}
|
||||
|
@ -20,12 +20,12 @@
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "tone_key.hpp"
|
||||
#include "string_format.hpp"
|
||||
#include "tone_key.hpp"
|
||||
|
||||
namespace tonekey {
|
||||
|
||||
const tone_key_t tone_keys[] = {
|
||||
const tone_key_t tone_keys = {
|
||||
{ "None", 0.0 },
|
||||
{ "0 XZ", 67.000 },
|
||||
{ "1 WZ", 69.400 },
|
||||
@ -90,14 +90,22 @@ void tone_keys_populate(OptionsField& field) {
|
||||
options_t tone_key_options;
|
||||
std::string tone_name;
|
||||
|
||||
for (size_t c = 0; c < KEY_TONES_NB; c++) {
|
||||
if (c && (c < 51))
|
||||
tone_name = "CTCSS " + tone_keys[c].first;
|
||||
else
|
||||
for (size_t c = 0; c < tone_keys.size(); c++) {
|
||||
if (c && c < 51) {
|
||||
auto f = tone_keys[c].second;
|
||||
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_key_options.emplace_back(tone_name, c);
|
||||
}
|
||||
|
||||
field.set_options(tone_key_options);
|
||||
}
|
||||
|
||||
float tone_key_frequency(const uint32_t index) {
|
||||
return tone_keys[index].second;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -28,15 +28,14 @@
|
||||
|
||||
using namespace ui;
|
||||
|
||||
#define KEY_TONES_NB 56
|
||||
|
||||
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);
|
||||
float tone_key_frequency(const uint32_t index);
|
||||
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,7 @@ void MicTXView::configure_baseband() {
|
||||
sampling_rate / 20, // Update vu-meter at 20Hz
|
||||
transmitting ? transmitter_model.channel_bandwidth() : 0,
|
||||
mic_gain_x10,
|
||||
TONES_F2D(tone_keys[tone_key_index].second),
|
||||
TONES_F2D(tone_key_frequency(tone_key_index)),
|
||||
0.2 // 20% mix
|
||||
);
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ void ReplayView::set_file_list(const std::vector<std::filesystem::path>& file_li
|
||||
|
||||
for (const auto& file : file_list) {
|
||||
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);
|
||||
}
|
||||
options_files.set_options(file_options);
|
||||
|
@ -105,7 +105,7 @@ private:
|
||||
|
||||
std::unique_ptr<ReplayThread> replay_thread { };
|
||||
|
||||
MessageHandlerRegistration message_handler_capture_thread_error {
|
||||
MessageHandlerRegistration message_handler_replay_thread_error {
|
||||
Message::ID::CaptureThreadDone,
|
||||
[this](const Message* const p) {
|
||||
const auto message = *reinterpret_cast<const ReplayThreadDoneMessage*>(p);
|
||||
|
@ -127,7 +127,7 @@ void SoundBoardView::play_sound(uint16_t id) {
|
||||
divider,
|
||||
number_bw.value() * 1000,
|
||||
10,
|
||||
TONES_F2D(tone_keys[tone_key_index].second),
|
||||
TONES_F2D(tone_key_frequency(tone_key_index)),
|
||||
0.2 // 20% mix
|
||||
);
|
||||
}
|
||||
|
@ -21,19 +21,20 @@
|
||||
*/
|
||||
|
||||
#include "proc_replay.hpp"
|
||||
#include "sine_table_int8.hpp"
|
||||
|
||||
#include "event_m4.hpp"
|
||||
|
||||
#include "utility.hpp"
|
||||
|
||||
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;
|
||||
|
||||
channel_spectrum.set_decimation_factor(1);*/
|
||||
|
||||
channel_spectrum.set_decimation_factor(1);
|
||||
}
|
||||
|
||||
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 samplerate is 500kHz, we're at 4MHz
|
||||
// iq_buffer can only be 512 samples (RAM limitation)
|
||||
// For a full 2048-sample C8 buffer, we need:
|
||||
// iq_buffer can only be 512 C16 samples (RAM limitation)
|
||||
// To fill up the 2048-sample C8 buffer, we need:
|
||||
// 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
|
||||
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);
|
||||
}
|
||||
|
||||
@ -57,25 +58,39 @@ void ReplayProcessor::execute(const buffer_c8_t& buffer) {
|
||||
|
||||
// Zero-stuff
|
||||
for (size_t i = 0; i < buffer.count; i++) {
|
||||
if (i & 3)
|
||||
buffer.p[i] = { 0, 0 };
|
||||
else
|
||||
buffer.p[i] = { iq_buffer.p[i >> 3].real() >> 8, iq_buffer.p[i >> 3].imag() >> 8 };
|
||||
|
||||
// DEBUG: This works. Transmits a 1kHz tone
|
||||
/*sample = (sine_table_i8[(tone_phase & 0xFF000000) >> 24]);
|
||||
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 ) {
|
||||
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) {
|
||||
switch(message->id) {
|
||||
/*case Message::ID::UpdateSpectrum:
|
||||
case Message::ID::UpdateSpectrum:
|
||||
case Message::ID::SpectrumStreamingConfig:
|
||||
channel_spectrum.on_message(message);
|
||||
break;*/
|
||||
break;
|
||||
|
||||
case Message::ID::ReplayConfig:
|
||||
replay_config(*reinterpret_cast<const ReplayConfigMessage*>(message));
|
||||
|
@ -43,21 +43,28 @@ public:
|
||||
|
||||
private:
|
||||
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 };
|
||||
|
||||
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 {
|
||||
iq.data(),
|
||||
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 { };
|
||||
|
||||
/*SpectrumCollector channel_spectrum;
|
||||
SpectrumCollector channel_spectrum { };
|
||||
size_t spectrum_interval_samples = 0;
|
||||
size_t spectrum_samples = 0;*/
|
||||
size_t spectrum_samples = 0;
|
||||
|
||||
void replay_config(const ReplayConfigMessage& message);
|
||||
};
|
||||
|
@ -35,7 +35,9 @@ StreamOutput::StreamOutput(ReplayConfig* const config) :
|
||||
config->fifo_buffers_full = &fifo_buffers_full;
|
||||
|
||||
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 };
|
||||
// Put all buffer pointers in the "empty buffer" FIFO
|
||||
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...
|
||||
if( !fifo_buffers_full.out(active_buffer) ) {
|
||||
// ...but none are available. Hole in transmission (inform app and stop ?)
|
||||
//active_buffer = nullptr;
|
||||
//creg::m4txevent::assert();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -69,3 +69,10 @@ StreamBuffer* BufferExchange::get(FIFO<StreamBuffer*>* fifo) {
|
||||
chSysUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
StreamBuffer* BufferExchange::get_prefill(FIFO<StreamBuffer*>* fifo) {
|
||||
StreamBuffer* p { nullptr };
|
||||
fifo->out(p);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
@ -47,9 +47,18 @@ public:
|
||||
return get(fifo_buffers_for_application);
|
||||
}
|
||||
|
||||
StreamBuffer* get_prefill() {
|
||||
return get_prefill(fifo_buffers_for_application);
|
||||
}
|
||||
|
||||
bool put(StreamBuffer* const p) {
|
||||
return fifo_buffers_for_baseband->in(p);
|
||||
}
|
||||
|
||||
// TESTING...
|
||||
bool put_app(StreamBuffer* const p) {
|
||||
return fifo_buffers_for_application->in(p);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(LPC43XX_M4)
|
||||
@ -99,4 +108,6 @@ private:
|
||||
}
|
||||
|
||||
StreamBuffer* get(FIFO<StreamBuffer*>* fifo);
|
||||
|
||||
StreamBuffer* get_prefill(FIFO<StreamBuffer*>* fifo);
|
||||
};
|
||||
|
@ -541,7 +541,7 @@ public:
|
||||
|
||||
size_t read(void* p, const size_t 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;
|
||||
return copy_size;
|
||||
}
|
||||
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user