Implement partner CTR menu

This commit is contained in:
Lorenzooone 2026-01-13 13:28:21 +01:00
parent 67adb67299
commit 9843ecf116
15 changed files with 442 additions and 35 deletions

View File

@ -526,7 +526,7 @@ else()
set_source_files_properties(source/conversions.cpp PROPERTIES COMPILE_OPTIONS "$<$<CONFIG:Release>:-O3;-funroll-loops>")
endif()
set(EXECUTABLE_SOURCE_FILES source/cc3dsfs.cpp source/utils.cpp source/audio_data.cpp source/audio.cpp source/frontend.cpp source/TextRectangle.cpp source/TextRectanglePool.cpp source/WindowScreen.cpp source/WindowScreen_Menu.cpp source/devicecapture.cpp source/conversions.cpp source/ExtraButtons.cpp source/Menus/ConnectionMenu.cpp source/Menus/OptionSelectionMenu.cpp source/Menus/MainMenu.cpp source/Menus/VideoMenu.cpp source/Menus/CropMenu.cpp source/Menus/PARMenu.cpp source/Menus/RotationMenu.cpp source/Menus/OffsetMenu.cpp source/Menus/AudioMenu.cpp source/Menus/BFIMenu.cpp source/Menus/RelativePositionMenu.cpp source/Menus/ResolutionMenu.cpp source/Menus/FileConfigMenu.cpp source/Menus/ExtraSettingsMenu.cpp source/Menus/StatusMenu.cpp source/Menus/LicenseMenu.cpp source/WindowCommands.cpp source/Menus/ShortcutMenu.cpp source/Menus/ActionSelectionMenu.cpp source/Menus/ScalingRatioMenu.cpp source/Menus/ISNitroMenu.cpp source/Menus/VideoEffectsMenu.cpp source/CaptureDataBuffers.cpp source/Menus/InputMenu.cpp source/Menus/AudioDeviceMenu.cpp source/Menus/SeparatorMenu.cpp source/Menus/ColorCorrectionMenu.cpp source/Menus/Main3DMenu.cpp source/Menus/SecondScreen3DRelativePositionMenu.cpp source/Menus/USBConflictResolutionMenu.cpp source/Menus/Optimize3DSMenu.cpp source/Menus/OptimizeSerialKeyAddMenu.cpp source/libgpiod_compat.cpp ${TOOLS_DATA_DIR}/optimize_serial_key_add_table.cpp ${TOOLS_DATA_DIR}/optimize_serial_key_next_char_table.cpp ${TOOLS_DATA_DIR}/optimize_serial_key_prev_char_table.cpp ${TOOLS_DATA_DIR}/font_ttf.cpp ${TOOLS_DATA_DIR}/font_mono_ttf.cpp ${TOOLS_DATA_DIR}/shaders_list.cpp ${SOURCE_CPP_EXTRA_FILES})
set(EXECUTABLE_SOURCE_FILES source/cc3dsfs.cpp source/utils.cpp source/audio_data.cpp source/audio.cpp source/frontend.cpp source/TextRectangle.cpp source/TextRectanglePool.cpp source/WindowScreen.cpp source/WindowScreen_Menu.cpp source/devicecapture.cpp source/conversions.cpp source/ExtraButtons.cpp source/Menus/ConnectionMenu.cpp source/Menus/OptionSelectionMenu.cpp source/Menus/MainMenu.cpp source/Menus/VideoMenu.cpp source/Menus/CropMenu.cpp source/Menus/PARMenu.cpp source/Menus/RotationMenu.cpp source/Menus/OffsetMenu.cpp source/Menus/AudioMenu.cpp source/Menus/BFIMenu.cpp source/Menus/RelativePositionMenu.cpp source/Menus/ResolutionMenu.cpp source/Menus/FileConfigMenu.cpp source/Menus/ExtraSettingsMenu.cpp source/Menus/StatusMenu.cpp source/Menus/LicenseMenu.cpp source/WindowCommands.cpp source/Menus/ShortcutMenu.cpp source/Menus/ActionSelectionMenu.cpp source/Menus/ScalingRatioMenu.cpp source/Menus/ISNitroMenu.cpp source/Menus/PartnerCTRMenu.cpp source/Menus/VideoEffectsMenu.cpp source/CaptureDataBuffers.cpp source/Menus/InputMenu.cpp source/Menus/AudioDeviceMenu.cpp source/Menus/SeparatorMenu.cpp source/Menus/ColorCorrectionMenu.cpp source/Menus/Main3DMenu.cpp source/Menus/SecondScreen3DRelativePositionMenu.cpp source/Menus/USBConflictResolutionMenu.cpp source/Menus/Optimize3DSMenu.cpp source/Menus/OptimizeSerialKeyAddMenu.cpp source/libgpiod_compat.cpp ${TOOLS_DATA_DIR}/optimize_serial_key_add_table.cpp ${TOOLS_DATA_DIR}/optimize_serial_key_next_char_table.cpp ${TOOLS_DATA_DIR}/optimize_serial_key_prev_char_table.cpp ${TOOLS_DATA_DIR}/font_ttf.cpp ${TOOLS_DATA_DIR}/font_mono_ttf.cpp ${TOOLS_DATA_DIR}/shaders_list.cpp ${SOURCE_CPP_EXTRA_FILES})
if(${CMAKE_SYSTEM_NAME} STREQUAL "Android")
add_compile_flag("SFML_SYSTEM_ANDROID")

View File

@ -25,6 +25,7 @@ uint64_t cypart_device_get_video_in_size(CaptureStatus* status, bool is_3d);
uint64_t cypart_device_get_video_in_size(CaptureData* capture_data, bool is_3d);
void cypart_device_acquisition_main_loop(CaptureData* capture_data);
void usb_cypart_device_acquisition_cleanup(CaptureData* capture_data);
bool is_device_partner_ctr(CaptureDevice* device);
void usb_cypart_device_init();
void usb_cypart_device_close();

View File

@ -28,6 +28,7 @@ enum MainMenuOutAction{
MAIN_MENU_ISN_SETTINGS,
MAIN_MENU_IST_SETTINGS,
MAIN_MENU_OPTIMIZE_3DS_SETTINGS,
MAIN_MENU_PARTNER_CTR_SETTINGS,
MAIN_MENU_INPUT_SETTINGS,
};

View File

@ -0,0 +1,41 @@
#ifndef __PARTCTRMENU_HPP
#define __PARTCTRMENU_HPP
#include "OptionSelectionMenu.hpp"
#include <chrono>
#include "TextRectangle.hpp"
#include "sfml_gfx_structs.hpp"
#include "display_structs.hpp"
#include "capture_structs.hpp"
enum PartnerCTRMenuOutAction{
PCTR_MENU_NO_ACTION,
PCTR_MENU_BACK,
PCTR_MENU_RESET,
PCTR_MENU_BATTERY_INC,
PCTR_MENU_BATTERY_DEC,
PCTR_MENU_AC_ADAPTER_CONNECTED_TOGGLE,
PCTR_MENU_AC_ADAPTER_CHARGING_TOGGLE,
};
class PartnerCTRMenu : public OptionSelectionMenu {
public:
PartnerCTRMenu(TextRectanglePool* text_pool);
~PartnerCTRMenu();
void prepare(float scaling_factor, int view_size_x, int view_size_y, CaptureStatus* capture_status);
void insert_data(CaptureDevice* device);
PartnerCTRMenuOutAction selected_index = PartnerCTRMenuOutAction::PCTR_MENU_NO_ACTION;
void reset_output_option();
protected:
bool is_option_selectable(int index, int action);
bool is_option_inc_dec(int index);
void set_output_option(int index, int action);
size_t get_num_options();
std::string get_string_option(int index, int action);
void class_setup();
private:
int *options_indexes;
size_t num_enabled_options;
};
#endif

View File

@ -371,8 +371,11 @@ struct CaptureStatus {
bool key_updated = false;
CaptureScreensType capture_type;
CaptureSpeedsType capture_speed;
int battery_percentage;
bool ac_adapter_connected;
int is_battery_percentage;
bool is_ac_adapter_connected;
int partner_ctr_battery_percentage;
bool partner_ctr_ac_adapter_connected;
bool partner_ctr_ac_adapter_charging;
// Needed for possible compatibility issues
bool devices_allowed_scan[CC_POSSIBLE_DEVICES_END];
ConsumerMutex video_wait;

View File

@ -26,7 +26,7 @@ enum ScreenType { TOP, BOTTOM, JOINT };
enum BottomRelativePosition { UNDER_TOP, LEFT_TOP, ABOVE_TOP, RIGHT_TOP, BOT_REL_POS_END };
enum SecondScreen3DRelativePosition { UNDER_FIRST, LEFT_FIRST, ABOVE_FIRST, RIGHT_FIRST, SECOND_SCREEN_3D_REL_POS_END };
enum NonIntegerScalingModes { SMALLER_PRIORITY, INVERSE_PROPORTIONAL_PRIORITY, EQUAL_PRIORITY, PROPORTIONAL_PRIORITY, BIGGER_PRIORITY, END_NONINT_SCALE_MODES };
enum CurrMenuType { DEFAULT_MENU_TYPE, CONNECT_MENU_TYPE, MAIN_MENU_TYPE, VIDEO_MENU_TYPE, AUDIO_MENU_TYPE, CROP_MENU_TYPE, TOP_PAR_MENU_TYPE, BOTTOM_PAR_MENU_TYPE, ROTATION_MENU_TYPE, OFFSET_MENU_TYPE, BFI_MENU_TYPE, LOAD_MENU_TYPE, SAVE_MENU_TYPE, RESOLUTION_MENU_TYPE, EXTRA_MENU_TYPE, STATUS_MENU_TYPE, LICENSES_MENU_TYPE, RELATIVE_POS_MENU_TYPE, SHORTCUTS_MENU_TYPE, ACTION_SELECTION_MENU_TYPE, SCALING_RATIO_MENU_TYPE, ISN_MENU_TYPE, VIDEO_EFFECTS_MENU_TYPE, INPUT_MENU_TYPE, AUDIO_DEVICE_MENU_TYPE, SEPARATOR_MENU_TYPE, COLOR_CORRECTION_MENU_TYPE, MAIN_3D_MENU_TYPE, SECOND_SCREEN_RELATIVE_POS_MENU_TYPE, USB_CONFLICT_RESOLUTION_MENU_TYPE, OPTIMIZE_3DS_MENU_TYPE, OPTIMIZE_SERIAL_KEY_ADD_MENU_TYPE, RECONNECT_MENU_TYPE };
enum CurrMenuType { DEFAULT_MENU_TYPE, CONNECT_MENU_TYPE, MAIN_MENU_TYPE, VIDEO_MENU_TYPE, AUDIO_MENU_TYPE, CROP_MENU_TYPE, TOP_PAR_MENU_TYPE, BOTTOM_PAR_MENU_TYPE, ROTATION_MENU_TYPE, OFFSET_MENU_TYPE, BFI_MENU_TYPE, LOAD_MENU_TYPE, SAVE_MENU_TYPE, RESOLUTION_MENU_TYPE, EXTRA_MENU_TYPE, STATUS_MENU_TYPE, LICENSES_MENU_TYPE, RELATIVE_POS_MENU_TYPE, SHORTCUTS_MENU_TYPE, ACTION_SELECTION_MENU_TYPE, SCALING_RATIO_MENU_TYPE, ISN_MENU_TYPE, VIDEO_EFFECTS_MENU_TYPE, INPUT_MENU_TYPE, AUDIO_DEVICE_MENU_TYPE, SEPARATOR_MENU_TYPE, COLOR_CORRECTION_MENU_TYPE, MAIN_3D_MENU_TYPE, SECOND_SCREEN_RELATIVE_POS_MENU_TYPE, USB_CONFLICT_RESOLUTION_MENU_TYPE, OPTIMIZE_3DS_MENU_TYPE, OPTIMIZE_SERIAL_KEY_ADD_MENU_TYPE, RECONNECT_MENU_TYPE, PARTNER_CTR_MENU_TYPE };
enum InputColorspaceMode { FULL_COLORSPACE, DS_COLORSPACE, GBA_COLORSPACE, INPUT_COLORSPACE_END };
enum FrameBlendingMode { NO_FRAME_BLENDING, FULL_FRAME_BLENDING, DS_3D_BOTH_SCREENS_FRAME_BLENDING, FRAME_BLENDING_END };

View File

@ -32,6 +32,7 @@
#include "ActionSelectionMenu.hpp"
#include "ScalingRatioMenu.hpp"
#include "ISNitroMenu.hpp"
#include "PartnerCTRMenu.hpp"
#include "VideoEffectsMenu.hpp"
#include "InputMenu.hpp"
#include "AudioDeviceMenu.hpp"
@ -191,6 +192,7 @@ private:
ShortcutMenu *shortcut_menu;
ActionSelectionMenu *action_selection_menu;
ISNitroMenu *is_nitro_menu;
PartnerCTRMenu *partner_ctr_menu;
ScalingRatioMenu *scaling_ratio_menu;
VideoEffectsMenu *video_effects_menu;
InputMenu *input_menu;
@ -299,8 +301,12 @@ private:
void is_nitro_capture_type_change(bool positive);
void is_nitro_capture_speed_change(bool positive);
void is_nitro_capture_reset_hw();
void generic_battery_change(bool positive, int &battery_percentage, const int *allowed_battery_levels, size_t num_levels);
void is_nitro_battery_change(bool positive);
void is_nitro_ac_adapter_change();
void partner_ctr_battery_change(bool positive);
void partner_ctr_ac_adapter_connected_change();
void partner_ctr_ac_adapter_charging_change();
void crop_value_change(int new_crop_value, bool do_print_notification = true, bool do_cycle = true);
void par_value_change(int new_par_value, bool is_top);
void offset_change(float &value, float change);
@ -408,6 +414,7 @@ private:
void setup_relative_pos_menu(bool reset_data = true);
void setup_scaling_ratio_menu(bool reset_data = true);
void setup_is_nitro_menu(bool reset_data = true);
void setup_partner_ctr_menu(bool reset_data = true);
void setup_video_effects_menu(bool reset_data = true);
void setup_input_menu(bool reset_data = true);
void setup_separator_menu(bool reset_data = true);

View File

@ -125,8 +125,8 @@ static int CaptureResetHardware(CaptureData* capture_data, std::chrono::time_poi
static int CaptureBatteryHandleHardware(CaptureData* capture_data, std::chrono::time_point<std::chrono::high_resolution_clock> &clock_last_battery_set, int &curr_battery_percentage, bool &curr_ac_adapter_connected) {
is_device_device_handlers* handlers = (is_device_device_handlers*)capture_data->handle;
const is_device_usb_device* usb_device_desc = (const is_device_usb_device*)capture_data->status.device.descriptor;
int loaded_battery_percentage = capture_data->status.battery_percentage;
bool loaded_ac_adapter_connected = capture_data->status.ac_adapter_connected;
int loaded_battery_percentage = capture_data->status.is_battery_percentage;
bool loaded_ac_adapter_connected = capture_data->status.is_ac_adapter_connected;
const auto curr_time_battery = std::chrono::high_resolution_clock::now();
const std::chrono::duration<double> diff_battery = curr_time_battery - clock_last_battery_set;
@ -174,8 +174,8 @@ void is_twl_acquisition_capture_main_loop(CaptureData* capture_data, ISDeviceCap
uint32_t last_read_frame_index = 0;
CaptureScreensType curr_capture_type = capture_data->status.capture_type;
CaptureSpeedsType curr_capture_speed = capture_data->status.capture_speed;
int curr_battery_percentage = capture_data->status.battery_percentage;
bool curr_ac_adapter_connected = capture_data->status.ac_adapter_connected;
int curr_battery_percentage = capture_data->status.is_battery_percentage;
bool curr_ac_adapter_connected = capture_data->status.is_ac_adapter_connected;
bool audio_enabled = true;
bool reprocess = false;
std::chrono::time_point<std::chrono::high_resolution_clock> clock_last_frame = std::chrono::high_resolution_clock::now();

View File

@ -18,6 +18,10 @@
// Such an action is allowed under EU law.
// No reverse engineering of the original software was done to create this.
#define RESET_TIMEOUT 4.0
#define BATTERY_TIMEOUT 5.0
#define SLEEP_RESET_TIME_MS 2000
#define SYNCH_VALUE_PARTNER_CTR PARTNER_CTR_CAPTURE_BASE_COMMAND
#define TOTAL_WANTED_CONCURRENTLY_RUNNING_BUFFER_SIZE 0x100000
@ -809,21 +813,98 @@ static int restart_captures_cc_reads(CaptureData* capture_data, CypressPartnerCT
return 0;
}
static bool has_battery_stuff_changed(CaptureData* capture_data, std::chrono::time_point<std::chrono::high_resolution_clock> &clock_last_battery_set, int &curr_battery_percentage, bool &curr_ac_adapter_connected, bool &curr_ac_adapter_charging) {
int loaded_battery_percentage = capture_data->status.partner_ctr_battery_percentage;
bool loaded_ac_adapter_connected = capture_data->status.partner_ctr_ac_adapter_connected;
bool loaded_ac_adapter_charging = capture_data->status.partner_ctr_ac_adapter_charging;
const auto curr_time_battery = std::chrono::high_resolution_clock::now();
const std::chrono::duration<double> diff_battery = curr_time_battery - clock_last_battery_set;
return !(((curr_battery_percentage == loaded_battery_percentage) || (diff_battery.count() <= BATTERY_TIMEOUT)) && (curr_ac_adapter_connected == loaded_ac_adapter_connected) && (curr_ac_adapter_charging == loaded_ac_adapter_charging));
}
static bool hardware_reset_requested(CaptureData* capture_data, std::chrono::time_point<std::chrono::high_resolution_clock> &clock_last_reset) {
bool reset_hardware = capture_data->status.reset_hardware;
capture_data->status.reset_hardware = false;
const auto curr_time = std::chrono::high_resolution_clock::now();
const std::chrono::duration<double> diff = curr_time - clock_last_reset;
// Do not reset too fast... In general.
return reset_hardware && (diff.count() > RESET_TIMEOUT);
}
static int CaptureBatteryHandleHardware(CaptureData* capture_data, std::chrono::time_point<std::chrono::high_resolution_clock> &clock_last_battery_set, int &curr_battery_percentage, bool &curr_ac_adapter_connected, bool &curr_ac_adapter_charging, bool force = false) {
cy_device_device_handlers* handlers = (cy_device_device_handlers*)capture_data->handle;
const cypart_device_usb_device* usb_device_desc = (const cypart_device_usb_device*)capture_data->status.device.descriptor;
int loaded_battery_percentage = capture_data->status.partner_ctr_battery_percentage;
bool loaded_ac_adapter_connected = capture_data->status.partner_ctr_ac_adapter_connected;
bool loaded_ac_adapter_charging = capture_data->status.partner_ctr_ac_adapter_charging;
const auto curr_time_battery = std::chrono::high_resolution_clock::now();
if(force || (curr_battery_percentage != loaded_battery_percentage)) {
int ret = set_battery_level(handlers, usb_device_desc, loaded_battery_percentage);
if(ret < 0) {
capture_error_print(true, capture_data, "Battery Set: Failed");
return ret;
}
clock_last_battery_set = curr_time_battery;
curr_battery_percentage = loaded_battery_percentage;
}
if(force || (curr_ac_adapter_connected != loaded_ac_adapter_connected) || (curr_ac_adapter_charging != loaded_ac_adapter_charging)) {
int ret = set_charge_kind(handlers, usb_device_desc, loaded_ac_adapter_connected, loaded_ac_adapter_charging);
if(ret < 0) {
capture_error_print(true, capture_data, "AC Adapter Set: Failed");
return ret;
}
curr_ac_adapter_connected = loaded_ac_adapter_connected;
curr_ac_adapter_charging = loaded_ac_adapter_charging;
}
return 0;
}
static int CaptureResetHardware(CaptureData* capture_data, std::chrono::time_point<std::chrono::high_resolution_clock> &clock_last_reset) {
cy_device_device_handlers* handlers = (cy_device_device_handlers*)capture_data->handle;
const cypart_device_usb_device* usb_device_desc = (const cypart_device_usb_device*)capture_data->status.device.descriptor;
const auto curr_time = std::chrono::high_resolution_clock::now();
clock_last_reset = curr_time;
int ret = hardware_reset(handlers, usb_device_desc);
if(ret < 0)
return ret;
default_sleep(SLEEP_RESET_TIME_MS);
return ret;
}
static bool cypart_device_acquisition_loop(CaptureData* capture_data, CypressPartnerCTRDeviceCaptureReceivedData* cypress_device_capture_recv_data, bool &stored_is_3d, bool could_use_3d) {
cy_device_device_handlers* handlers = (cy_device_device_handlers*)capture_data->handle;
const cypart_device_usb_device* usb_device_desc = (const cypart_device_usb_device*)capture_data->status.device.descriptor;
uint32_t index = 0;
uint64_t device_id = 0;
int curr_battery_percentage = capture_data->status.partner_ctr_battery_percentage;
bool curr_ac_adapter_connected = capture_data->status.partner_ctr_ac_adapter_connected;
bool curr_ac_adapter_charging = capture_data->status.partner_ctr_ac_adapter_charging;
std::string read_serial = "";
bool force_capture_start_key = false;
int ret = capture_start(handlers, usb_device_desc, read_serial);
std::chrono::time_point<std::chrono::high_resolution_clock> clock_last_capture_start = std::chrono::high_resolution_clock::now();
std::chrono::time_point<std::chrono::high_resolution_clock> clock_last_reset = std::chrono::high_resolution_clock::now();
std::chrono::time_point<std::chrono::high_resolution_clock> clock_last_battery_set = std::chrono::high_resolution_clock::now();
if (ret < 0) {
capture_error_print(true, capture_data, "Capture Start: Failed");
return false;
}
ret = CaptureBatteryHandleHardware(capture_data, clock_last_battery_set, curr_battery_percentage, curr_ac_adapter_connected, curr_ac_adapter_charging, true);
if (ret < 0)
return false;
CypressSetMaxTransferSize(handlers, get_cy_usb_info(usb_device_desc), 0x80000);
StartCaptureDma(handlers, usb_device_desc, stored_is_3d);
@ -848,9 +929,26 @@ static bool cypart_device_acquisition_loop(CaptureData* capture_data, CypressPar
}
}
bool is_new_3d = could_use_3d && get_3d_enabled(&capture_data->status);
if(is_new_3d != stored_is_3d) {
bool updated_battery = has_battery_stuff_changed(capture_data, clock_last_battery_set, curr_battery_percentage, curr_ac_adapter_connected, curr_ac_adapter_charging);
bool requested_reset = hardware_reset_requested(capture_data, clock_last_reset);
if((is_new_3d != stored_is_3d) || updated_battery || requested_reset) {
capture_data->status.cooldown_curr_in = FIX_PARTIAL_FIRST_FRAME_NUM + NUM_PARTNER_CTR_CYPRESS_CONCURRENTLY_RUNNING_BUFFERS;
wait_all_cypress_device_buffers_free(capture_data, cypress_device_capture_recv_data);
if(updated_battery) {
ret = CaptureBatteryHandleHardware(capture_data, clock_last_battery_set, curr_battery_percentage, curr_ac_adapter_connected, curr_ac_adapter_charging);
if(ret < 0)
return false;
}
if(requested_reset) {
ret = CaptureResetHardware(capture_data, clock_last_reset);
if(ret < 0) {
capture_error_print(true, capture_data, "Hardware Reset: Failed");
return false;
}
}
ret = restart_captures_cc_reads(capture_data, cypress_device_capture_recv_data, index, stored_is_3d, could_use_3d, false, clock_last_capture_start);
if(ret < 0) {
capture_error_print(true, capture_data, "Disconnected: Update mode error");
@ -946,6 +1044,15 @@ void usb_cypart_device_acquisition_cleanup(CaptureData* capture_data) {
cypress_partner_ctr_connection_end((cy_device_device_handlers*)capture_data->handle, (const cypart_device_usb_device*)capture_data->status.device.descriptor);
capture_data->handle = NULL;
}
bool is_device_partner_ctr(CaptureDevice* device) {
if(device == NULL)
return false;
if(device->cc_type != CAPTURE_CONN_PARTNER_CTR)
return false;
return true;
}
void usb_cypart_device_init() {
return usb_init();
}

View File

@ -208,10 +208,10 @@ void ISNitroMenu::prepare(float menu_scaling_factor, int view_size_x, int view_s
this->labels[index]->setText(this->setTextOptionString(real_index, get_capture_speed_name(capture_status->capture_speed)));
break;
case ISN_MENU_BATTERY_DEC:
this->labels[index]->setText(this->setTextOptionInt(real_index, capture_status->battery_percentage));
this->labels[index]->setText(this->setTextOptionInt(real_index, capture_status->is_battery_percentage));
break;
case ISN_MENU_AC_ADAPTER_TOGGLE:
this->labels[index]->setText(this->setTextOptionBool(real_index, capture_status->ac_adapter_connected));
this->labels[index]->setText(this->setTextOptionBool(real_index, capture_status->is_ac_adapter_connected));
break;
default:
break;

View File

@ -1,6 +1,7 @@
#include "MainMenu.hpp"
#include "usb_is_device_acquisition.hpp"
#include "cypress_optimize_3ds_acquisition.hpp"
#include "cypress_partner_ctr_acquisition.hpp"
#define NUM_TOTAL_MENU_OPTIONS (sizeof(pollable_options)/sizeof(pollable_options[0]))
@ -153,6 +154,13 @@ static const MainMenuOptionInfo opti_3ds_settings_option = {
.enabled_normal_mode = true, .enabled_mono_mode = true, .is_cc_specific = true,
.out_action = MAIN_MENU_OPTIMIZE_3DS_SETTINGS};
static const MainMenuOptionInfo partner_ctr_settings_option = {
.base_name = "Partner CTR Settings", .false_name = "",
.active_fullscreen = true, .active_windowed_screen = true,
.active_joint_screen = true, .active_top_screen = true, .active_bottom_screen = true,
.enabled_normal_mode = true, .enabled_mono_mode = true, .is_cc_specific = true,
.out_action = MAIN_MENU_PARTNER_CTR_SETTINGS};
static const MainMenuOptionInfo* pollable_options[] = {
&connect_option,
&windowed_option,
@ -169,6 +177,7 @@ static const MainMenuOptionInfo* pollable_options[] = {
&isn_settings_option,
&ist_settings_option,
&opti_3ds_settings_option,
&partner_ctr_settings_option,
&licenses_option,
&extra_settings_option,
&quit_option,
@ -212,6 +221,10 @@ static bool check_cc_specific_option(const MainMenuOptionInfo* option, CaptureDe
if((option->out_action == MAIN_MENU_OPTIMIZE_3DS_SETTINGS) && is_device_optimize_3ds(device))
return true;
#endif
#ifdef USE_PARTNER_CTR
if((option->out_action == MAIN_MENU_PARTNER_CTR_SETTINGS) && is_device_partner_ctr(device))
return true;
#endif
return false;
}

View File

@ -0,0 +1,143 @@
#include "PartnerCTRMenu.hpp"
#define NUM_TOTAL_MENU_OPTIONS (sizeof(pollable_options)/sizeof(pollable_options[0]))
struct PartnerCTRMenuOptionInfo {
const std::string base_name;
const std::string false_name;
const bool is_selectable;
const bool is_inc;
const std::string dec_str;
const std::string inc_str;
const PartnerCTRMenuOutAction inc_out_action;
const PartnerCTRMenuOutAction out_action;
};
static const PartnerCTRMenuOptionInfo partner_ctr_reset_option = {
.base_name = "Reset Hardware", .false_name = "", .is_selectable = true,
.is_inc = false, .dec_str = "", .inc_str = "", .inc_out_action = PCTR_MENU_NO_ACTION,
.out_action = PCTR_MENU_RESET};
static const PartnerCTRMenuOptionInfo partner_ctr_battery_percentage_option = {
.base_name = "Battery Percentage", .false_name = "", .is_selectable = true,
.is_inc = true, .dec_str = "-", .inc_str = "+", .inc_out_action = PCTR_MENU_BATTERY_INC,
.out_action = PCTR_MENU_BATTERY_DEC};
static const PartnerCTRMenuOptionInfo partner_ctr_ac_adapter_connected_option = {
.base_name = "Disconnect AC Adapter", .false_name = "Connect AC Adapter", .is_selectable = true,
.is_inc = false, .dec_str = "", .inc_str = "", .inc_out_action = PCTR_MENU_NO_ACTION,
.out_action = PCTR_MENU_AC_ADAPTER_CONNECTED_TOGGLE};
static const PartnerCTRMenuOptionInfo partner_ctr_ac_adapter_charging_option = {
.base_name = "Disable AC charging", .false_name = "Enable AC charging", .is_selectable = true,
.is_inc = false, .dec_str = "", .inc_str = "", .inc_out_action = PCTR_MENU_NO_ACTION,
.out_action = PCTR_MENU_AC_ADAPTER_CHARGING_TOGGLE};
static const PartnerCTRMenuOptionInfo* pollable_options[] = {
&partner_ctr_reset_option,
&partner_ctr_battery_percentage_option,
&partner_ctr_ac_adapter_connected_option,
&partner_ctr_ac_adapter_charging_option,
};
PartnerCTRMenu::PartnerCTRMenu(TextRectanglePool* text_rectangle_pool) : OptionSelectionMenu(){
this->options_indexes = new int[NUM_TOTAL_MENU_OPTIONS];
this->initialize(text_rectangle_pool);
this->num_enabled_options = 0;
}
PartnerCTRMenu::~PartnerCTRMenu() {
delete []this->options_indexes;
}
void PartnerCTRMenu::class_setup() {
this->num_options_per_screen = 5;
this->min_elements_text_scaling_factor = num_options_per_screen + 2;
this->width_factor_menu = 16;
this->width_divisor_menu = 9;
this->base_height_factor_menu = 12;
this->base_height_divisor_menu = 6;
this->min_text_size = 0.3f;
this->max_width_slack = 1.1f;
this->menu_color = sf::Color(30, 30, 60, 192);
this->title = "Partner CTR Settings";
this->show_back_x = true;
this->show_x = false;
this->show_title = true;
}
void PartnerCTRMenu::insert_data(CaptureDevice* device) {
this->num_enabled_options = 0;
for(size_t i = 0; i < NUM_TOTAL_MENU_OPTIONS; i++) {
bool valid = true;
if(valid) {
this->options_indexes[this->num_enabled_options] = (int)i;
this->num_enabled_options++;
}
}
this->prepare_options();
}
void PartnerCTRMenu::reset_output_option() {
this->selected_index = PartnerCTRMenuOutAction::PCTR_MENU_NO_ACTION;
}
void PartnerCTRMenu::set_output_option(int index, int action) {
if(index == BACK_X_OUTPUT_OPTION)
this->selected_index = PCTR_MENU_BACK;
else if((action == INC_ACTION) && this->is_option_inc_dec(index))
this->selected_index = pollable_options[this->options_indexes[index]]->inc_out_action;
else
this->selected_index = pollable_options[this->options_indexes[index]]->out_action;
}
size_t PartnerCTRMenu::get_num_options() {
return this->num_enabled_options;
}
std::string PartnerCTRMenu::get_string_option(int index, int action) {
if((action == INC_ACTION) && this->is_option_inc_dec(index))
return pollable_options[this->options_indexes[index]]->inc_str;
if((action == DEC_ACTION) && this->is_option_inc_dec(index))
return pollable_options[this->options_indexes[index]]->dec_str;
if(action == FALSE_ACTION)
return pollable_options[this->options_indexes[index]]->false_name;
return pollable_options[this->options_indexes[index]]->base_name;
}
bool PartnerCTRMenu::is_option_selectable(int index, int action) {
return pollable_options[this->options_indexes[index]]->is_selectable;
}
bool PartnerCTRMenu::is_option_inc_dec(int index) {
return pollable_options[this->options_indexes[index]]->is_inc;
}
void PartnerCTRMenu::prepare(float menu_scaling_factor, int view_size_x, int view_size_y, CaptureStatus* capture_status) {
int num_pages = this->get_num_pages();
if(this->future_data.page >= num_pages)
this->future_data.page = num_pages - 1;
int start = this->future_data.page * this->num_options_per_screen;
for(int i = 0; i < this->num_options_per_screen + 1; i++) {
int index = (i * this->single_option_multiplier) + this->elements_start_id;
if(!this->future_enabled_labels[index])
continue;
int real_index = start + i;
int option_index = this->options_indexes[real_index];
switch(pollable_options[option_index]->out_action) {
case PCTR_MENU_BATTERY_DEC:
this->labels[index]->setText(this->setTextOptionInt(real_index, capture_status->partner_ctr_battery_percentage));
break;
case PCTR_MENU_AC_ADAPTER_CONNECTED_TOGGLE:
this->labels[index]->setText(this->setTextOptionBool(real_index, capture_status->partner_ctr_ac_adapter_connected));
break;
case PCTR_MENU_AC_ADAPTER_CHARGING_TOGGLE:
this->labels[index]->setText(this->setTextOptionBool(real_index, capture_status->partner_ctr_ac_adapter_charging));
break;
default:
break;
}
}
this->base_prepare(menu_scaling_factor, view_size_x, view_size_y);
}

View File

@ -6,7 +6,8 @@
#define FPS_WINDOW_SIZE 64
static const int battery_levels[] = {1, 5, 12, 25, 50, 100};
static const int is_battery_levels[] = {1, 5, 12, 25, 50, 100};
static const int partner_ctr_battery_levels[] = {0, 1, 10, 30, 60, 100};
static const sf::VideoMode default_fs_mode_4_5k_macos = sf::VideoMode({4480, 2520});
static const sf::VideoMode default_fs_mode_4k_macos = sf::VideoMode({4096, 2304});
@ -117,6 +118,7 @@ void WindowScreen::init_menus() {
this->action_selection_menu = new ActionSelectionMenu(this->text_rectangle_pool);
this->scaling_ratio_menu = new ScalingRatioMenu(this->text_rectangle_pool);
this->is_nitro_menu = new ISNitroMenu(this->text_rectangle_pool);
this->partner_ctr_menu = new PartnerCTRMenu(this->text_rectangle_pool);
this->video_effects_menu = new VideoEffectsMenu(this->text_rectangle_pool);
this->input_menu = new InputMenu(this->text_rectangle_pool);
this->audio_device_menu = new AudioDeviceMenu(this->text_rectangle_pool);
@ -149,6 +151,7 @@ void WindowScreen::destroy_menus() {
delete this->action_selection_menu;
delete this->scaling_ratio_menu;
delete this->is_nitro_menu;
delete this->partner_ctr_menu;
delete this->video_effects_menu;
delete this->input_menu;
delete this->audio_device_menu;
@ -225,16 +228,15 @@ void WindowScreen::is_nitro_capture_reset_hw() {
this->capture_status->reset_hardware = true;
}
void WindowScreen::is_nitro_battery_change(bool positive) {
if(this->capture_status->battery_percentage < 1)
this->capture_status->battery_percentage = 1;
if(this->capture_status->battery_percentage > 100)
this->capture_status->battery_percentage = 100;
int closest_level = 0;
void WindowScreen::generic_battery_change(bool positive, int &battery_percentage, const int *allowed_battery_levels, size_t num_levels) {
if(battery_percentage < allowed_battery_levels[0])
battery_percentage = allowed_battery_levels[0];
if(battery_percentage > 100)
battery_percentage = 100;
size_t closest_level = 0;
int curr_diff = 100;
const int num_levels = sizeof(battery_levels) / sizeof(battery_levels[0]);
for(int i = 0; i < num_levels; i++) {
int level_diff = abs(battery_levels[i] - this->capture_status->battery_percentage);
for(size_t i = 0; i < num_levels; i++) {
int level_diff = abs(allowed_battery_levels[i] - battery_percentage);
if(level_diff < curr_diff) {
closest_level = i;
curr_diff = level_diff;
@ -244,13 +246,29 @@ void WindowScreen::is_nitro_battery_change(bool positive) {
closest_level -= 1;
if((positive) && (closest_level < (num_levels - 1)))
closest_level += 1;
if(battery_levels[closest_level] != this->capture_status->battery_percentage)
if(allowed_battery_levels[closest_level] != battery_percentage)
this->print_notification("Changing battery level...\nPlease wait...");
this->capture_status->battery_percentage = battery_levels[closest_level];
battery_percentage = allowed_battery_levels[closest_level];
}
void WindowScreen::is_nitro_battery_change(bool positive) {
this->generic_battery_change(positive, this->capture_status->is_battery_percentage, is_battery_levels, sizeof(is_battery_levels) / sizeof(is_battery_levels[0]));
}
void WindowScreen::is_nitro_ac_adapter_change() {
this->capture_status->ac_adapter_connected = !this->capture_status->ac_adapter_connected;
this->capture_status->is_ac_adapter_connected = !this->capture_status->is_ac_adapter_connected;
}
void WindowScreen::partner_ctr_battery_change(bool positive) {
this->generic_battery_change(positive, this->capture_status->partner_ctr_battery_percentage, partner_ctr_battery_levels, sizeof(partner_ctr_battery_levels) / sizeof(partner_ctr_battery_levels[0]));
}
void WindowScreen::partner_ctr_ac_adapter_connected_change() {
this->capture_status->partner_ctr_ac_adapter_connected = !this->capture_status->partner_ctr_ac_adapter_connected;
}
void WindowScreen::partner_ctr_ac_adapter_charging_change() {
this->capture_status->partner_ctr_ac_adapter_charging = !this->capture_status->partner_ctr_ac_adapter_charging;
}
void WindowScreen::padding_change() {
@ -1179,6 +1197,15 @@ void WindowScreen::setup_is_nitro_menu(bool reset_data) {
}
}
void WindowScreen::setup_partner_ctr_menu(bool reset_data) {
if(!this->can_setup_menu())
return;
if(this->curr_menu != PARTNER_CTR_MENU_TYPE) {
this->switch_to_menu(PARTNER_CTR_MENU_TYPE, this->partner_ctr_menu, reset_data);
this->partner_ctr_menu->insert_data(&this->capture_status->device);
}
}
void WindowScreen::setup_video_effects_menu(bool reset_data) {
if(!this->can_setup_menu())
return;
@ -1604,6 +1631,10 @@ void WindowScreen::poll(bool do_everything) {
this->setup_optimize_3ds_menu();
done = true;
break;
case MAIN_MENU_PARTNER_CTR_SETTINGS:
this->setup_partner_ctr_menu();
done = true;
break;
case MAIN_MENU_SHUTDOWN:
this->set_close(1);
this->setup_no_menu();
@ -2158,6 +2189,34 @@ void WindowScreen::poll(bool do_everything) {
}
this->loaded_menu_ptr->reset_output_option();
break;
case PARTNER_CTR_MENU_TYPE:
switch(this->partner_ctr_menu->selected_index) {
case PCTR_MENU_BACK:
this->setup_main_menu(false);
done = true;
break;
case PCTR_MENU_NO_ACTION:
break;
case PCTR_MENU_RESET:
this->is_nitro_capture_reset_hw();
break;
case PCTR_MENU_BATTERY_DEC:
this->partner_ctr_battery_change(false);
break;
case PCTR_MENU_BATTERY_INC:
this->partner_ctr_battery_change(true);
break;
case PCTR_MENU_AC_ADAPTER_CONNECTED_TOGGLE:
this->partner_ctr_ac_adapter_connected_change();
break;
case PCTR_MENU_AC_ADAPTER_CHARGING_TOGGLE:
this->partner_ctr_ac_adapter_charging_change();
break;
default:
break;
}
this->loaded_menu_ptr->reset_output_option();
break;
case VIDEO_EFFECTS_MENU_TYPE:
switch(this->video_effects_menu->selected_index) {
case VIDEO_EFFECTS_MENU_BACK:
@ -2454,6 +2513,8 @@ void WindowScreen::update_capture_specific_settings() {
}
if(this->curr_menu == ISN_MENU_TYPE)
this->setup_no_menu();
if(this->curr_menu == PARTNER_CTR_MENU_TYPE)
this->setup_no_menu();
if(this->curr_menu == OPTIMIZE_3DS_MENU_TYPE)
this->setup_no_menu();
if(this->curr_menu == OPTIMIZE_SERIAL_KEY_ADD_MENU_TYPE)
@ -2694,6 +2755,9 @@ void WindowScreen::prepare_menu_draws(int view_size_x, int view_size_y) {
case ISN_MENU_TYPE:
this->is_nitro_menu->prepare(menu_scaling_factor, view_size_x, view_size_y, this->capture_status);
break;
case PARTNER_CTR_MENU_TYPE:
this->partner_ctr_menu->prepare(menu_scaling_factor, view_size_x, view_size_y, this->capture_status);
break;
case VIDEO_EFFECTS_MENU_TYPE:
this->video_effects_menu->prepare(menu_scaling_factor, view_size_x, view_size_y, &this->loaded_info);
break;

View File

@ -199,18 +199,39 @@ static bool load(const std::string path, const std::string name, ScreenInfo &top
}
if(key == "is_battery_percentage") {
capture_status->battery_percentage = std::stoi(value);
capture_status->is_battery_percentage = std::stoi(value);
// Even though 1 is allowed, it spam-resets the Hardware...
// So don't allow it as the initial value!
if(capture_status->battery_percentage <= 5)
capture_status->battery_percentage = 5;
if(capture_status->battery_percentage > 100)
capture_status->battery_percentage = 100;
if(capture_status->is_battery_percentage <= 5)
capture_status->is_battery_percentage = 5;
if(capture_status->is_battery_percentage > 100)
capture_status->is_battery_percentage = 100;
continue;
}
if(key == "is_ac_adapter_connected") {
capture_status->ac_adapter_connected = std::stoi(value);
capture_status->is_ac_adapter_connected = std::stoi(value);
continue;
}
if(key == "partner_ctr_battery_percentage") {
capture_status->partner_ctr_battery_percentage = std::stoi(value);
// Even though 0 is allowed, it turns off the Hardware...
// So don't allow it as the initial value!
if(capture_status->partner_ctr_battery_percentage <= 1)
capture_status->partner_ctr_battery_percentage = 1;
if(capture_status->partner_ctr_battery_percentage > 100)
capture_status->partner_ctr_battery_percentage = 100;
continue;
}
if(key == "partner_ctr_ac_adapter_connected") {
capture_status->partner_ctr_ac_adapter_connected = std::stoi(value);
continue;
}
if(key == "partner_ctr_ac_adapter_charging") {
capture_status->partner_ctr_ac_adapter_charging = std::stoi(value);
continue;
}
@ -242,8 +263,11 @@ static bool load(const std::string path, const std::string name, ScreenInfo &top
static void defaults_reload(FrontendData *frontend_data, AudioData* audio_data, CaptureStatus* capture_status) {
capture_status->capture_type = CAPTURE_SCREENS_BOTH;
capture_status->capture_speed = CAPTURE_SPEEDS_FULL;
capture_status->battery_percentage = 100;
capture_status->ac_adapter_connected = true;
capture_status->is_battery_percentage = 100;
capture_status->is_ac_adapter_connected = true;
capture_status->partner_ctr_battery_percentage = 100;
capture_status->partner_ctr_ac_adapter_connected = false;
capture_status->partner_ctr_ac_adapter_charging = false;
capture_status->request_low_bw_format = true;
for(int i = 0; i < CC_POSSIBLE_DEVICES_END; i++)
capture_status->devices_allowed_scan[i] = true;
@ -333,8 +357,11 @@ static bool save(const std::string path, const std::string name, const std::stri
file << "last_connected_ds=" << display_data.last_connected_ds << std::endl;
file << "is_screen_capture_type=" << capture_status->capture_type << std::endl;
file << "is_speed_capture=" << capture_status->capture_speed << std::endl;
file << "is_battery_percentage=" << capture_status->battery_percentage << std::endl;
file << "is_ac_adapter_connected=" << capture_status->ac_adapter_connected << std::endl;
file << "is_battery_percentage=" << capture_status->is_battery_percentage << std::endl;
file << "is_ac_adapter_connected=" << capture_status->is_ac_adapter_connected << std::endl;
file << "partner_ctr_battery_percentage=" << capture_status->partner_ctr_battery_percentage << std::endl;
file << "partner_ctr_ac_adapter_connected=" << capture_status->partner_ctr_battery_percentage << std::endl;
file << "partner_ctr_ac_adapter_charging=" << capture_status->partner_ctr_battery_percentage << std::endl;
file << "optimize_o3ds_scan_for=" << capture_status->devices_allowed_scan[CC_OPTIMIZE_O3DS] << std::endl;
file << "nisetro_ds_scan_for=" << capture_status->devices_allowed_scan[CC_NISETRO_DS] << std::endl;
file << audio_data->save_audio_data();

View File

@ -1131,7 +1131,7 @@ void update_connected_3ds_ds(FrontendData* frontend_data, const CaptureDevice &o
}
void update_connected_specific_settings(FrontendData* frontend_data, const CaptureDevice &cc_device) {
if((cc_device.cc_type == CAPTURE_CONN_IS_NITRO) || (cc_device.cc_type == CAPTURE_CONN_CYPRESS_OPTIMIZE)) {
if((cc_device.cc_type == CAPTURE_CONN_IS_NITRO) || (cc_device.cc_type == CAPTURE_CONN_CYPRESS_OPTIMIZE) || (cc_device.cc_type == CAPTURE_CONN_PARTNER_CTR)) {
frontend_data->top_screen->update_capture_specific_settings();
frontend_data->bot_screen->update_capture_specific_settings();
frontend_data->joint_screen->update_capture_specific_settings();