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

View File

@ -45,10 +45,6 @@ public:
std::string title() const override { return "Replay"; };
void start();
void stop();
bool is_active() const;
private:
NavigationView& nav_;
@ -67,61 +63,67 @@ private:
rf::Frequency target_frequency() const;
void toggle();
void start();
void stop(const bool do_loop);
bool is_active() const;
void set_ready();
void handle_replay_thread_done(const File::Error error);
void handle_error(const File::Error error);
void handle_replay_thread_done(const uint32_t return_code);
void file_error();
std::filesystem::path file_path { };
std::unique_ptr<ReplayThread> replay_thread { };
bool ready_signal { false };
Labels labels {
{ { 10 * 8, 0 * 8 }, "LNA: AMP:", 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 }
{ { 10 * 8, 2 * 16 }, "LNA: A:", Color::light_grey() }
};
Button button_open {
{ 20 * 8, 1 * 16, 10 * 8, 2 * 16 },
{ 0 * 8, 0 * 16, 10 * 8, 2 * 16 },
"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 { };
MessageHandlerRegistration message_handler_replay_thread_error {
Message::ID::ReplayThreadDone,
[this](const Message* const 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 buffer_count,
bool* ready_signal,
std::function<void()> success_callback,
std::function<void(File::Error)> error_callback
std::function<void(uint32_t return_code)> terminate_callback
) : config { read_size, buffer_count },
reader { std::move(reader) },
ready_sig { ready_signal },
success_callback { std::move(success_callback) },
error_callback { std::move(error_callback) }
terminate_callback { std::move(terminate_callback) }
{
// Need significant stack for FATFS
thread = chThdCreateFromHeap(NULL, 1024, NORMALPRIO + 10, ReplayThread::static_fn, this);
@ -64,18 +62,14 @@ ReplayThread::~ReplayThread() {
msg_t ReplayThread::static_fn(void* arg) {
auto obj = static_cast<ReplayThread*>(arg);
const auto error = obj->run();
if( error.is_valid() && obj->error_callback ) {
obj->error_callback(error.value());
} else {
if( obj->success_callback ) {
obj->success_callback();
}
const auto return_code = obj->run();
if( obj->terminate_callback ) {
obj->terminate_callback(return_code);
}
return 0;
}
Optional<File::Error> ReplayThread::run() {
uint32_t ReplayThread::run() {
BasebandReplay replay { &config };
BufferExchange buffers { &config };
@ -99,7 +93,7 @@ Optional<File::Error> ReplayThread::run() {
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();
return READ_ERROR;
}
}
@ -116,10 +110,10 @@ Optional<File::Error> ReplayThread::run() {
auto read_result = reader->read(buffer->data(), buffer->capacity());
if( read_result.is_error() ) {
return read_result.error();
return READ_ERROR;
} else {
if (read_result.value() == 0) {
return { };
return END_OF_FILE;
}
}
@ -128,5 +122,5 @@ Optional<File::Error> ReplayThread::run() {
buffers.put(buffer);
}
return { };
return TERMINATED;
}

View File

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

View File

@ -117,6 +117,23 @@ std::string to_string_short_freq(const uint64_t f) {
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) {
const uint32_t d = n & 0xf;
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_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_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) {
uint32_t duration = sounds[id].ms_duration;
text_duration.set(to_string_dec_uint(duration / 1000) + "." + to_string_dec_uint((duration / 100) % 10) + "s");
text_duration.set(to_string_time_ms(sounds[id].ms_duration));
text_title.set(sounds[id].title);
}

View File

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

Binary file not shown.