Added loop option in Replay app

Updated binary
This commit is contained in:
furrtek 2017-12-11 04:14:54 +00:00
parent 70c7646743
commit c9381f1418
9 changed files with 117 additions and 101 deletions

View File

@ -44,18 +44,15 @@ void ReplayAppView::on_file_changed(std::filesystem::path new_file_path) {
file_path = new_file_path; file_path = new_file_path;
text_filename.set(new_file_path.string().substr(0, 18)); text_filename.set(new_file_path.string().substr(0, 19));
bbd_file.open("/" + new_file_path.string()); bbd_file.open("/" + new_file_path.string());
auto file_size = bbd_file.size(); auto file_size = bbd_file.size();
auto duration = file_size / (2 * 2 * sampling_rate / 8); auto duration = (file_size * 1000) / (2 * 2 * sampling_rate / 8);
progressbar.set_max(file_size); progressbar.set_max(file_size);
if (duration >= 60) text_duration.set(to_string_time_ms(duration));
str_duration = to_string_dec_uint(duration / 60) + "m";
text_duration.set(str_duration + to_string_dec_uint(duration % 60) + "s");
button_play.focus(); button_play.focus();
} }
@ -68,27 +65,31 @@ void ReplayAppView::focus() {
button_open.focus(); button_open.focus();
} }
void ReplayAppView::file_error() {
nav_.display_modal("Error", "File read error.");
}
bool ReplayAppView::is_active() const { bool ReplayAppView::is_active() const {
return (bool)replay_thread; return (bool)replay_thread;
} }
void ReplayAppView::toggle() { void ReplayAppView::toggle() {
if( is_active() ) { if( is_active() ) {
stop(); stop(false);
} else { } else {
start(); start();
} }
} }
void ReplayAppView::start() { void ReplayAppView::start() {
stop(); stop(false);
std::unique_ptr<stream::Reader> reader; std::unique_ptr<stream::Reader> reader;
auto p = std::make_unique<FileReader>(); auto p = std::make_unique<FileReader>();
auto open_error = p->open(file_path); auto open_error = p->open(file_path);
if( open_error.is_valid() ) { if( open_error.is_valid() ) {
handle_error(open_error.value()); file_error();
} else { } else {
reader = std::move(p); reader = std::move(p);
} }
@ -99,12 +100,8 @@ void ReplayAppView::start() {
std::move(reader), std::move(reader),
read_size, buffer_count, read_size, buffer_count,
&ready_signal, &ready_signal,
[]() { [](uint32_t return_code) {
ReplayThreadDoneMessage message { }; ReplayThreadDoneMessage message { return_code };
EventDispatcher::send_message(message);
},
[](File::Error error) {
ReplayThreadDoneMessage message { error.code() };
EventDispatcher::send_message(message); EventDispatcher::send_message(message);
} }
); );
@ -121,25 +118,27 @@ void ReplayAppView::start() {
}); });
} }
void ReplayAppView::stop() { void ReplayAppView::stop(const bool do_loop) {
if( is_active() ) if( is_active() )
replay_thread.reset(); replay_thread.reset();
progressbar.set_value(0); if (do_loop && check_loop.value()) {
start();
radio::disable(); } else {
button_play.set_bitmap(&bitmap_play); radio::disable();
} button_play.set_bitmap(&bitmap_play);
void ReplayAppView::handle_replay_thread_done(const File::Error error) {
stop();
if( error.code() ) {
handle_error(error);
} }
} }
void ReplayAppView::handle_error(const File::Error error) { void ReplayAppView::handle_replay_thread_done(const uint32_t return_code) {
nav_.display_modal("Error", error.what()); if (return_code == ReplayThread::END_OF_FILE) {
stop(true);
} else if (return_code == ReplayThread::READ_ERROR) {
stop(false);
file_error();
}
progressbar.set_value(0);
} }
ReplayAppView::ReplayAppView( ReplayAppView::ReplayAppView(
@ -150,14 +149,15 @@ ReplayAppView::ReplayAppView(
add_children({ add_children({
&labels, &labels,
&field_frequency, &button_open,
&field_lna,
&field_rf_amp,
&button_play,
&text_filename, &text_filename,
&text_duration, &text_duration,
&progressbar, &progressbar,
&button_open, &field_frequency,
&field_lna,
&field_rf_amp,
&check_loop,
&button_play,
&waterfall, &waterfall,
}); });

View File

@ -45,10 +45,6 @@ public:
std::string title() const override { return "Replay"; }; std::string title() const override { return "Replay"; };
void start();
void stop();
bool is_active() const;
private: private:
NavigationView& nav_; NavigationView& nav_;
@ -67,61 +63,67 @@ private:
rf::Frequency target_frequency() const; rf::Frequency target_frequency() const;
void toggle(); void toggle();
void start();
void stop(const bool do_loop);
bool is_active() const;
void set_ready(); void set_ready();
void handle_replay_thread_done(const File::Error error); void handle_replay_thread_done(const uint32_t return_code);
void handle_error(const File::Error error); void file_error();
std::filesystem::path file_path { }; std::filesystem::path file_path { };
std::unique_ptr<ReplayThread> replay_thread { }; std::unique_ptr<ReplayThread> replay_thread { };
bool ready_signal { false }; bool ready_signal { false };
Labels labels { Labels labels {
{ { 10 * 8, 0 * 8 }, "LNA: AMP:", Color::light_grey() } { { 10 * 8, 2 * 16 }, "LNA: A:", Color::light_grey() }
};
FrequencyField field_frequency {
{ 0 * 8, 0 * 16 },
};
LNAGainField field_lna {
{ 14 * 8, 0 * 16 }
};
RFAmpField field_rf_amp {
{ 21 * 8, 0 * 16 }
};
ImageButton button_play {
{ 0 * 8, 1 * 16 + 8, 2 * 8, 1 * 16 },
&bitmap_play,
Color::green(),
Color::black()
};
Text text_filename {
{ 2 * 8, 1 * 16, 18 * 8, 16 },
"-"
};
Text text_duration {
{ 2 * 8, 2 * 16, 6 * 8, 16 },
"-"
};
ProgressBar progressbar {
{ 9 * 8, 2 * 16, 10 * 8, 16 }
}; };
Button button_open { Button button_open {
{ 20 * 8, 1 * 16, 10 * 8, 2 * 16 }, { 0 * 8, 0 * 16, 10 * 8, 2 * 16 },
"Open file" "Open file"
}; };
Text text_filename {
{ 11 * 8, 0 * 16, 19 * 8, 16 },
"-"
};
Text text_duration {
{ 11 * 8, 1 * 16, 6 * 8, 16 },
"-"
};
ProgressBar progressbar {
{ 18 * 8, 1 * 16, 12 * 8, 16 }
};
FrequencyField field_frequency {
{ 0 * 8, 2 * 16 },
};
LNAGainField field_lna {
{ 14 * 8, 2 * 16 }
};
RFAmpField field_rf_amp {
{ 19 * 8, 2 * 16 }
};
Checkbox check_loop {
{ 21 * 8, 2 * 16 },
4,
"Loop",
true
};
ImageButton button_play {
{ 28 * 8, 2 * 16, 2 * 8, 1 * 16 },
&bitmap_play,
Color::green(),
Color::black()
};
spectrum::WaterfallWidget waterfall { }; spectrum::WaterfallWidget waterfall { };
MessageHandlerRegistration message_handler_replay_thread_error { MessageHandlerRegistration message_handler_replay_thread_error {
Message::ID::ReplayThreadDone, Message::ID::ReplayThreadDone,
[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);
this->handle_replay_thread_done(message.error); this->handle_replay_thread_done(message.return_code);
} }
}; };

View File

@ -42,13 +42,11 @@ ReplayThread::ReplayThread(
size_t read_size, size_t read_size,
size_t buffer_count, size_t buffer_count,
bool* ready_signal, bool* ready_signal,
std::function<void()> success_callback, std::function<void(uint32_t return_code)> terminate_callback
std::function<void(File::Error)> error_callback
) : config { read_size, buffer_count }, ) : config { read_size, buffer_count },
reader { std::move(reader) }, reader { std::move(reader) },
ready_sig { ready_signal }, ready_sig { ready_signal },
success_callback { std::move(success_callback) }, terminate_callback { std::move(terminate_callback) }
error_callback { std::move(error_callback) }
{ {
// Need significant stack for FATFS // Need significant stack for FATFS
thread = chThdCreateFromHeap(NULL, 1024, NORMALPRIO + 10, ReplayThread::static_fn, this); thread = chThdCreateFromHeap(NULL, 1024, NORMALPRIO + 10, ReplayThread::static_fn, this);
@ -64,18 +62,14 @@ ReplayThread::~ReplayThread() {
msg_t ReplayThread::static_fn(void* arg) { msg_t ReplayThread::static_fn(void* arg) {
auto obj = static_cast<ReplayThread*>(arg); auto obj = static_cast<ReplayThread*>(arg);
const auto error = obj->run(); const auto return_code = obj->run();
if( error.is_valid() && obj->error_callback ) { if( obj->terminate_callback ) {
obj->error_callback(error.value()); obj->terminate_callback(return_code);
} else {
if( obj->success_callback ) {
obj->success_callback();
}
} }
return 0; return 0;
} }
Optional<File::Error> ReplayThread::run() { uint32_t ReplayThread::run() {
BasebandReplay replay { &config }; BasebandReplay replay { &config };
BufferExchange buffers { &config }; BufferExchange buffers { &config };
@ -99,7 +93,7 @@ Optional<File::Error> ReplayThread::run() {
for (size_t c = 0; c < blocks; c++) { for (size_t c = 0; c < blocks; c++) {
auto read_result = reader->read(&((uint8_t*)prefill_buffer->data())[c * 512], 512); 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_ERROR;
} }
} }
@ -116,10 +110,10 @@ Optional<File::Error> ReplayThread::run() {
auto read_result = reader->read(buffer->data(), buffer->capacity()); auto read_result = reader->read(buffer->data(), buffer->capacity());
if( read_result.is_error() ) { if( read_result.is_error() ) {
return read_result.error(); return READ_ERROR;
} else { } else {
if (read_result.value() == 0) { if (read_result.value() == 0) {
return { }; return END_OF_FILE;
} }
} }
@ -128,5 +122,5 @@ Optional<File::Error> ReplayThread::run() {
buffers.put(buffer); buffers.put(buffer);
} }
return { }; return TERMINATED;
} }

View File

@ -41,8 +41,7 @@ public:
size_t read_size, size_t read_size,
size_t buffer_count, size_t buffer_count,
bool* ready_signal, bool* ready_signal,
std::function<void()> success_callback, std::function<void(uint32_t return_code)> terminate_callback
std::function<void(File::Error)> error_callback
); );
~ReplayThread(); ~ReplayThread();
@ -53,19 +52,24 @@ public:
const ReplayConfig& state() const { const ReplayConfig& state() const {
return config; return config;
} };
enum replaythread_return {
READ_ERROR = 0,
END_OF_FILE,
TERMINATED
};
private: private:
ReplayConfig config; ReplayConfig config;
std::unique_ptr<stream::Reader> reader; std::unique_ptr<stream::Reader> reader;
bool* ready_sig; bool* ready_sig;
std::function<void()> success_callback; std::function<void(uint32_t return_code)> terminate_callback;
std::function<void(File::Error)> error_callback;
Thread* thread { nullptr }; Thread* thread { nullptr };
static msg_t static_fn(void* arg); static msg_t static_fn(void* arg);
Optional<File::Error> run(); uint32_t run();
}; };
#endif/*__REPLAY_THREAD_H__*/ #endif/*__REPLAY_THREAD_H__*/

View File

@ -117,6 +117,23 @@ std::string to_string_short_freq(const uint64_t f) {
return final_str; return final_str;
} }
std::string to_string_time_ms(const uint32_t ms) {
std::string final_str { "" };
if (ms < 1000) {
final_str = to_string_dec_uint(ms) + "ms";
} else {
auto seconds = ms / 1000;
if (seconds >= 60)
final_str = to_string_dec_uint(seconds / 60) + "m";
return final_str + to_string_dec_uint(seconds % 60) + "s";
}
return final_str;
}
static void to_string_hex_internal(char* p, const uint64_t n, const int32_t l) { static void to_string_hex_internal(char* p, const uint64_t n, const int32_t l) {
const uint32_t d = n & 0xf; const uint32_t d = n & 0xf;
p[l] = (d > 9) ? (d + 55) : (d + 48); p[l] = (d > 9) ? (d + 55) : (d + 48);

View File

@ -45,6 +45,7 @@ std::string to_string_hex(const uint64_t n, const int32_t l = 0);
std::string to_string_hex_array(uint8_t * const array, const int32_t l = 0); std::string to_string_hex_array(uint8_t * const array, const int32_t l = 0);
std::string to_string_short_freq(const uint64_t f); std::string to_string_short_freq(const uint64_t f);
std::string to_string_time_ms(const uint32_t ms);
std::string to_string_datetime(const rtc::RTC& value, const TimeFormat format = YMDHMS); std::string to_string_datetime(const rtc::RTC& value, const TimeFormat format = YMDHMS);
std::string to_string_timestamp(const rtc::RTC& value); std::string to_string_timestamp(const rtc::RTC& value);

View File

@ -133,9 +133,7 @@ void SoundBoardView::play_sound(uint16_t id) {
} }
void SoundBoardView::show_infos(uint16_t id) { void SoundBoardView::show_infos(uint16_t id) {
uint32_t duration = sounds[id].ms_duration; text_duration.set(to_string_time_ms(sounds[id].ms_duration));
text_duration.set(to_string_dec_uint(duration / 1000) + "." + to_string_dec_uint((duration / 100) % 10) + "s");
text_title.set(sounds[id].title); text_title.set(sounds[id].title);
} }

View File

@ -997,13 +997,13 @@ public:
class ReplayThreadDoneMessage : public Message { class ReplayThreadDoneMessage : public Message {
public: public:
constexpr ReplayThreadDoneMessage( constexpr ReplayThreadDoneMessage(
uint32_t error = 0 uint32_t return_code = 0
) : Message { ID::ReplayThreadDone }, ) : Message { ID::ReplayThreadDone },
error { error } return_code { return_code }
{ {
} }
uint32_t error; uint32_t return_code;
}; };
#endif/*__MESSAGE_H__*/ #endif/*__MESSAGE_H__*/

Binary file not shown.