diff --git a/include/3dscapture.hpp b/include/3dscapture.hpp index 8970647..a91275e 100755 --- a/include/3dscapture.hpp +++ b/include/3dscapture.hpp @@ -39,6 +39,9 @@ struct PACKED CaptureReceived { struct CaptureData { FT_HANDLE handle; + char chosen_serial_number[17]; + std::string error_text; + bool new_error_text; CaptureReceived capture_buf[NUM_CONCURRENT_DATA_BUFFERS]; ULONG read[NUM_CONCURRENT_DATA_BUFFERS]; double time_in_buf[NUM_CONCURRENT_DATA_BUFFERS]; diff --git a/include/frontend.hpp b/include/frontend.hpp index f6c1513..dbf2fc4 100755 --- a/include/frontend.hpp +++ b/include/frontend.hpp @@ -56,13 +56,14 @@ void reset_screen_info(ScreenInfo &info); void load_screen_info(std::string key, std::string value, std::string base, ScreenInfo &info); std::string save_screen_info(std::string base, const ScreenInfo &info); +enum TextKind {TEXT_KIND_NORMAL, TEXT_KIND_SELECTED, TEXT_KIND_SUCCESS, TEXT_KIND_WARNING, TEXT_KIND_ERROR}; + class TextRectangle { public: TextRectangle(bool font_load_success, sf::Font &text_font); ~TextRectangle(); - enum TextRectangleKind {TEXT_NORMAL, TEXT_SELECTED, TEXT_SUCCESS, TEXT_WARNING, TEXT_ERROR}; void setSize(int width, int height); - void setRectangleKind(TextRectangleKind kind); + void setRectangleKind(TextKind kind); void setDuration(float on_seconds); void startTimer(bool do_start); void setProportionalBox(bool proportional_box); @@ -90,7 +91,7 @@ private: struct TextData { bool is_timed; bool start_timer; - TextRectangleKind kind; + TextKind kind; bool show_text; bool render_text; bool proportional_box; @@ -124,6 +125,7 @@ public: void end(); void draw(double frame_time, VideoOutputData* out_buf); + void print_notification(std::string text, TextKind kind = TEXT_KIND_NORMAL); int load_data(); int save_data(); bool open_capture(); @@ -185,7 +187,6 @@ private: void resize_in_rect(sf::RectangleShape &in_rect, int start_x, int start_y, int width, int height); int get_screen_corner_modifier_x(int rotation, int width); int get_screen_corner_modifier_y(int rotation, int height); - void print_notification(std::string text); void print_notification_on_off(std::string base_text, bool value); void poll_window(); void prepare_screen_rendering(); diff --git a/source/3dscapture.cpp b/source/3dscapture.cpp index f792d7e..6e36dff 100755 --- a/source/3dscapture.cpp +++ b/source/3dscapture.cpp @@ -67,12 +67,17 @@ static int choose_device(DevicesList &devices_list) { } bool connect(bool print_failed, CaptureData* capture_data) { + capture_data->new_error_text = false; if (capture_data->connected) { capture_data->close_success = false; return false; } if(!capture_data->close_success) { + if(print_failed) { + capture_data->error_text = "Previous device still closing..."; + capture_data->new_error_text = true; + } return false; } @@ -80,8 +85,10 @@ bool connect(bool print_failed, CaptureData* capture_data) { list_devices(devices_list); if(devices_list.numValidDevices <= 0) { - if(print_failed) - printf("[%s] No device was found.\n", NAME); + if(print_failed) { + capture_data->error_text = "No device was found"; + capture_data->new_error_text = true; + } if(devices_list.numAllocedDevices > 0) delete []devices_list.serialNumbers; return false; @@ -89,52 +96,67 @@ bool connect(bool print_failed, CaptureData* capture_data) { int chosen_device = choose_device(devices_list); if(chosen_device == -1) { - if(print_failed) - printf("[%s] No device was selected.\n", NAME); - delete []devices_list.serialNumbers; - return false; - } - - if (FT_Create(&devices_list.serialNumbers[17 * chosen_device], FT_OPEN_BY_SERIAL_NUMBER, &capture_data->handle)) { - if(print_failed) - printf("[%s] Create failed.\n", NAME); + if(print_failed) { + capture_data->error_text = "No device was selected"; + capture_data->new_error_text = true; + } delete []devices_list.serialNumbers; return false; } + for(int i = 0; i < 17; i++) + capture_data->chosen_serial_number[i] = devices_list.serialNumbers[(17 * chosen_device) + i]; delete []devices_list.serialNumbers; + if (FT_Create(capture_data->chosen_serial_number, FT_OPEN_BY_SERIAL_NUMBER, &capture_data->handle)) { + if(print_failed) { + capture_data->error_text = "Create failed"; + capture_data->new_error_text = true; + } + return false; + } + UCHAR buf[4] = {0x40, 0x80, 0x00, 0x00}; ULONG written = 0; if (FT_WritePipe(capture_data->handle, BULK_OUT, buf, 4, &written, 0)) { - if(print_failed) - printf("[%s] Write failed.\n", NAME); + if(print_failed) { + capture_data->error_text = "Write failed"; + capture_data->new_error_text = true; + } return false; } buf[1] = 0x00; if (FT_WritePipe(capture_data->handle, BULK_OUT, buf, 4, &written, 0)) { - if(print_failed) - printf("[%s] Write failed.\n", NAME); + if(print_failed) { + capture_data->error_text = "Write failed"; + capture_data->new_error_text = true; + } return false; } if (FT_SetStreamPipe(capture_data->handle, false, false, BULK_IN, sizeof(CaptureReceived))) { - if(print_failed) - printf("[%s] Stream failed.\n", NAME); + if(print_failed) { + capture_data->error_text = "Stream failed"; + capture_data->new_error_text = true; + } return false; } if(FT_AbortPipe(capture_data->handle, BULK_IN)) { - if(print_failed) - printf("[%s] Abort failed.\n", NAME); + if(print_failed) { + capture_data->error_text = "Abort failed"; + capture_data->new_error_text = true; + } } if (FT_SetStreamPipe(capture_data->handle, false, false, BULK_IN, sizeof(CaptureReceived))) { - if(print_failed) - printf("[%s] Stream failed.\n", NAME); + if(print_failed) { + capture_data->error_text = "Stream failed"; + capture_data->new_error_text = true; + } return false; } @@ -151,7 +173,8 @@ static void fast_capture_call(CaptureData* capture_data, OVERLAPPED overlap[NUM_ for (inner_curr_in = 0; inner_curr_in < NUM_CONCURRENT_DATA_BUFFERS; ++inner_curr_in) { ftStatus = FT_InitializeOverlapped(capture_data->handle, &overlap[inner_curr_in]); if (ftStatus) { - printf("[%s] Initialize failed.\n", NAME); + capture_data->error_text = "Initialize failed"; + capture_data->new_error_text = true; return; } } @@ -159,7 +182,8 @@ static void fast_capture_call(CaptureData* capture_data, OVERLAPPED overlap[NUM_ for (inner_curr_in = 0; inner_curr_in < NUM_CONCURRENT_DATA_BUFFERS - 1; ++inner_curr_in) { ftStatus = FT_ASYNC_CALL(capture_data->handle, FIFO_CHANNEL, (UCHAR*)&capture_data->capture_buf[inner_curr_in], sizeof(CaptureReceived), &capture_data->read[inner_curr_in], &overlap[inner_curr_in]); if (ftStatus != FT_IO_PENDING) { - printf("[%s] Read failed.\n", NAME); + capture_data->error_text = "Read failed"; + capture_data->new_error_text = true; return; } } @@ -172,7 +196,8 @@ static void fast_capture_call(CaptureData* capture_data, OVERLAPPED overlap[NUM_ ftStatus = FT_ASYNC_CALL(capture_data->handle, FIFO_CHANNEL, (UCHAR*)&capture_data->capture_buf[inner_curr_in], sizeof(CaptureReceived), &capture_data->read[inner_curr_in], &overlap[inner_curr_in]); if (ftStatus != FT_IO_PENDING) { - printf("[%s] Read failed.\n", NAME); + capture_data->error_text = "Read failed"; + capture_data->new_error_text = true; return; } @@ -180,7 +205,8 @@ static void fast_capture_call(CaptureData* capture_data, OVERLAPPED overlap[NUM_ ftStatus = FT_GetOverlappedResult(capture_data->handle, &overlap[inner_curr_in], &capture_data->read[inner_curr_in], true); if(FT_FAILED(ftStatus)) { - printf("[%s] USB error.\n", NAME); + capture_data->error_text = "USB error"; + capture_data->new_error_text = true; return; } const auto curr_time = std::chrono::high_resolution_clock::now(); @@ -207,7 +233,8 @@ static bool safe_capture_call(CaptureData* capture_data) { FT_STATUS ftStatus = FT_ReadPipeEx(capture_data->handle, FIFO_CHANNEL, (UCHAR*)&capture_data->capture_buf[inner_curr_in], sizeof(CaptureReceived), &capture_data->read[inner_curr_in], 1000); if(FT_FAILED(ftStatus)) { - printf("[%s] Read failed.\n", NAME); + capture_data->error_text = "Read failed"; + capture_data->new_error_text = true; return true; } @@ -272,17 +299,20 @@ void captureCall(CaptureData* capture_data) { for (inner_curr_in = 0; inner_curr_in < NUM_CONCURRENT_DATA_BUFFERS; ++inner_curr_in) { ftStatus = FT_GetOverlappedResult(capture_data->handle, &overlap[inner_curr_in], &capture_data->read[inner_curr_in], true); if (FT_ReleaseOverlapped(capture_data->handle, &overlap[inner_curr_in])) { - printf("[%s] Release failed.\n", NAME); + capture_data->error_text = "Release failed"; + capture_data->new_error_text = true; } } } if(FT_AbortPipe(capture_data->handle, BULK_IN)) { - printf("[%s] Abort failed.\n", NAME); + capture_data->error_text = "Abort failed"; + capture_data->new_error_text = true; } if (FT_Close(capture_data->handle)) { - printf("[%s] Close failed.\n", NAME); + capture_data->error_text = "Close failed"; + capture_data->new_error_text = true; } capture_data->close_success = false; diff --git a/source/TextRectangle.cpp b/source/TextRectangle.cpp index 2458537..1729343 100755 --- a/source/TextRectangle.cpp +++ b/source/TextRectangle.cpp @@ -35,7 +35,7 @@ void TextRectangle::setSize(int width, int height) { this->text_rect.out_rect.setTextureRect(sf::IntRect(0, 0, this->width, this->height)); } -void TextRectangle::setRectangleKind(TextRectangleKind kind) { +void TextRectangle::setRectangleKind(TextKind kind) { if(this->future_data.kind != kind) { this->future_data.render_text = true; } @@ -118,7 +118,7 @@ void TextRectangle::draw(sf::RenderTarget &window) { void TextRectangle::reset_data(TextData &data) { data.is_timed = false; data.start_timer = false; - data.kind = TEXT_NORMAL; + data.kind = TEXT_KIND_NORMAL; data.show_text = false; data.render_text = false; data.proportional_box = true; @@ -158,16 +158,16 @@ void TextRectangle::updateText() { } sf::Color *used_color = this->base_bg_color; switch(this->loaded_data.kind) { - case TEXT_SELECTED: + case TEXT_KIND_SELECTED: used_color = this->selected_bg_color; break; - case TEXT_SUCCESS: + case TEXT_KIND_SUCCESS: used_color = this->success_bg_color; break; - case TEXT_WARNING: + case TEXT_KIND_WARNING: used_color = this->warning_bg_color; break; - case TEXT_ERROR: + case TEXT_KIND_ERROR: used_color = this->error_bg_color; break; default: diff --git a/source/WindowScreen.cpp b/source/WindowScreen.cpp index a46ae45..b4ab03a 100755 --- a/source/WindowScreen.cpp +++ b/source/WindowScreen.cpp @@ -359,6 +359,13 @@ void WindowScreen::draw(double frame_time, VideoOutputData* out_buf) { } } +void WindowScreen::print_notification(std::string text, TextKind kind) { + this->notification->setText(text); + this->notification->setRectangleKind(kind); + this->notification->startTimer(true); + this->notification->setShowText(true); +} + int WindowScreen::load_data() { int ret_val = this->m_prepare_load; this->m_prepare_load = 0; @@ -429,12 +436,6 @@ int WindowScreen::get_screen_corner_modifier_y(int rotation, int height) { return 0; } -void WindowScreen::print_notification(std::string text) { - this->notification->setText(text); - this->notification->startTimer(true); - this->notification->setShowText(true); -} - void WindowScreen::print_notification_on_off(std::string base_text, bool value) { std::string status_text = "On"; if(!value) diff --git a/source/cc3dsfs.cpp b/source/cc3dsfs.cpp index 5f9bd49..1f75463 100755 --- a/source/cc3dsfs.cpp +++ b/source/cc3dsfs.cpp @@ -9,6 +9,7 @@ #else #include #endif +#include #include #include #include @@ -30,7 +31,35 @@ #define AUDIO_LATENCY_LIMIT 4 #define NUM_CONCURRENT_AUDIO_BUFFERS ((AUDIO_LATENCY_LIMIT * 2) + 1) -bool load(const std::string path, const std::string name, ScreenInfo &top_info, ScreenInfo &bottom_info, ScreenInfo &joint_info, DisplayData &display_data, AudioData *audio_data) { +struct OutTextData { + std::string full_text; + std::string small_text; + bool consumed; + TextKind kind; +}; + +void ConsoleOutText(std::string full_text) { + std::cout << "[" << NAME << "] " << full_text << std::endl; +} + +void UpdateOutText(OutTextData &out_text_data, std::string full_text, std::string small_text, TextKind kind) { + if(!out_text_data.consumed) + ConsoleOutText(out_text_data.full_text); + out_text_data.full_text = full_text; + out_text_data.small_text = small_text; + out_text_data.kind = kind; + out_text_data.consumed = false; +} + +void ConnectedOutTextGenerator(OutTextData &out_text_data, CaptureData* capture_data) { + UpdateOutText(out_text_data, "Connected to " + std::string(capture_data->chosen_serial_number), "Connected", TEXT_KIND_SUCCESS); +} + +std::string LayoutNameGenerator(int index) { + return "layout" + std::to_string(index) + ".cfg"; +} + +bool load(const std::string path, const std::string name, ScreenInfo &top_info, ScreenInfo &bottom_info, ScreenInfo &joint_info, DisplayData &display_data, AudioData *audio_data, OutTextData &out_text_data) { std::ifstream file(path + name); std::string line; @@ -39,7 +68,7 @@ bool load(const std::string path, const std::string name, ScreenInfo &top_info, reset_screen_info(joint_info); if (!file.good()) { - printf("[%s] File \"%s\" load failed.\nDefaults re-loaded.\n", NAME, (path + name).c_str()); + UpdateOutText(out_text_data, "File " + path + name + " load failed.\nDefaults re-loaded.", "Load failed\nDefaults re-loaded", TEXT_KIND_ERROR); return false; } @@ -85,7 +114,7 @@ bool load(const std::string path, const std::string name, ScreenInfo &top_info, return true; } -void save(const std::string path, const std::string name, const ScreenInfo &top_info, const ScreenInfo &bottom_info, const ScreenInfo &joint_info, DisplayData &display_data, AudioData *audio_data) { +bool save(const std::string path, const std::string name, const ScreenInfo &top_info, const ScreenInfo &bottom_info, const ScreenInfo &joint_info, DisplayData &display_data, AudioData *audio_data, OutTextData &out_text_data) { #if (!defined(_MSC_VER)) || (_MSC_VER > 1916) std::filesystem::create_directories(path); #else @@ -93,8 +122,8 @@ void save(const std::string path, const std::string name, const ScreenInfo &top_ #endif std::ofstream file(path + name); if (!file.good()) { - printf("[%s] File \"%s\" save failed.\n", NAME, (path + name).c_str()); - return; + UpdateOutText(out_text_data, "File " + path + name + " save failed.", "Save failed", TEXT_KIND_ERROR); + return false; } file << save_screen_info("bot_", bottom_info); @@ -105,6 +134,7 @@ void save(const std::string path, const std::string name, const ScreenInfo &top_ file << "volume=" << audio_data->volume << std::endl; file.close(); + return true; } void soundCall(AudioData *audio_data, CaptureData* capture_data) { @@ -180,12 +210,17 @@ void mainVideoOutputCall(AudioData* audio_data, CaptureData* capture_data) { int num_allowed_blanks = MAX_ALLOWED_BLANKS; double last_frame_time = 0; std::mutex events_access; + OutTextData out_text_data; + out_text_data.consumed = true; #if not(defined(_WIN32) || defined(_WIN64)) std::string cfg_dir = std::string(std::getenv("HOME")) + "/.config/" + std::string(NAME); #else std::string cfg_dir = ".config/" + std::string(NAME); #endif + std::string base_path = cfg_dir + "/"; + std::string base_name = std::string(NAME) + ".cfg"; + std::string layout_path = cfg_dir + "/presets/"; out_buf = new VideoOutputData; null_buf = new VideoOutputData; @@ -197,8 +232,11 @@ void mainVideoOutputCall(AudioData* audio_data, CaptureData* capture_data) { WindowScreen bot_screen(WindowScreen::ScreenType::BOTTOM, &display_data, audio_data, &events_access); WindowScreen joint_screen(WindowScreen::ScreenType::JOINT, &display_data, audio_data, &events_access); + if(capture_data->connected) + ConnectedOutTextGenerator(out_text_data, capture_data); + if(!skip_io) { - load(cfg_dir + "/", std::string(NAME) + ".cfg", top_screen.m_info, bot_screen.m_info, joint_screen.m_info, display_data, audio_data); + load(base_path, base_name, top_screen.m_info, bot_screen.m_info, joint_screen.m_info, display_data, audio_data, out_text_data); } top_screen.build(); @@ -275,6 +313,8 @@ void mainVideoOutputCall(AudioData* audio_data, CaptureData* capture_data) { if(top_screen.open_capture() || bot_screen.open_capture() || joint_screen.open_capture()) { capture_data->connected = connect(true, capture_data); + if(capture_data->connected) + ConnectedOutTextGenerator(out_text_data, capture_data); } if(top_screen.close_capture() || bot_screen.close_capture() || joint_screen.close_capture()) { @@ -283,16 +323,35 @@ void mainVideoOutputCall(AudioData* audio_data, CaptureData* capture_data) { if((load_index = top_screen.load_data()) || (load_index = bot_screen.load_data()) || (load_index = joint_screen.load_data())) { if (!skip_io) { - load(cfg_dir + "/presets/", "layout" + std::to_string(load_index) + ".cfg", top_screen.m_info, bot_screen.m_info, joint_screen.m_info, display_data, audio_data); + std::string layout_name = LayoutNameGenerator(load_index); + bool op_success = load(layout_path, layout_name, top_screen.m_info, bot_screen.m_info, joint_screen.m_info, display_data, audio_data, out_text_data); + if(op_success) + UpdateOutText(out_text_data, "Layout loaded from: " + layout_path + layout_name, "Layout loaded", TEXT_KIND_SUCCESS); reload = true; } } if((save_index = top_screen.save_data()) || (save_index = bot_screen.save_data()) || (save_index = joint_screen.save_data())) { if (!skip_io) { - save(cfg_dir + "/presets/", "layout" + std::to_string(save_index) + ".cfg", top_screen.m_info, bot_screen.m_info, joint_screen.m_info, display_data, audio_data); + std::string layout_name = LayoutNameGenerator(save_index); + bool op_success = save(layout_path, layout_name, top_screen.m_info, bot_screen.m_info, joint_screen.m_info, display_data, audio_data, out_text_data); + if(op_success) + UpdateOutText(out_text_data, "Layout saved to: " + layout_path + layout_name, "Layout saved", TEXT_KIND_SUCCESS); } } + + if(capture_data->new_error_text) { + UpdateOutText(out_text_data, capture_data->error_text, capture_data->error_text, TEXT_KIND_ERROR); + capture_data->new_error_text = false; + } + + if(!out_text_data.consumed) { + ConsoleOutText(out_text_data.full_text); + top_screen.print_notification(out_text_data.small_text, out_text_data.kind); + bot_screen.print_notification(out_text_data.small_text, out_text_data.kind); + joint_screen.print_notification(out_text_data.small_text, out_text_data.kind); + out_text_data.consumed = true; + } } top_screen.end(); @@ -304,7 +363,12 @@ void mainVideoOutputCall(AudioData* audio_data, CaptureData* capture_data) { joint_thread.join(); if (!skip_io) { - save(cfg_dir + "/", std::string(NAME) + ".cfg", top_screen.m_info, bot_screen.m_info, joint_screen.m_info, display_data, audio_data); + save(base_path, base_name, top_screen.m_info, bot_screen.m_info, joint_screen.m_info, display_data, audio_data, out_text_data); + } + + if(!out_text_data.consumed) { + ConsoleOutText(out_text_data.full_text); + out_text_data.consumed = true; } delete out_buf;