Stop tracking old code directories

This commit is contained in:
ndeadly 2020-08-26 21:24:20 +02:00
parent 15c8d7630c
commit 165d2e87b3
38 changed files with 0 additions and 3057 deletions

View file

@ -1,26 +0,0 @@
#pragma once
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
inline uint16_t __bswap_16(uint16_t val) {
return (val << 8) | (val >> 8 );
}
inline uint32_t __bswap_32(uint32_t val) {
val = ((val << 8) & 0xFF00FF00 ) | ((val >> 8) & 0xFF00FF );
return (val << 16) | (val >> 16);
}
inline uint64_t __bswap_64(uint64_t val) {
val = ((val << 8) & 0xFF00FF00FF00FF00ULL ) | ((val >> 8) & 0x00FF00FF00FF00FFULL );
val = ((val << 16) & 0xFFFF0000FFFF0000ULL ) | ((val >> 16) & 0x0000FFFF0000FFFFULL );
return (val << 32) | (val >> 32);
}
#ifdef __cplusplus
}
#endif

View file

@ -1,25 +0,0 @@
#pragma once
namespace mc::log {
//const constexpr char *app = "sdmc:/missioncontrol-applet.log";
//const constexpr char *sys = "sdmc:/missioncontrol-sysmodule.log";
//void Write(const char *location, const char *fmt, ...);
//void WriteData(const char *location, void *data, size_t size);
class Logger {
public:
Logger(const char *location);
void write(const char *fmt, ...);
void writeData(void *data, size_t size);
private:
Mutex m_logMutex;
const char *m_location;
};
}

View file

@ -1,19 +0,0 @@
#pragma once
#include <cstring>
#include <switch.h>
#define BTM_COD_MAJOR_PERIPHERAL 0x05
#define BTM_COD_MINOR_GAMEPAD 0x08
#define BTM_COD_MINOR_JOYSTICK 0x04
inline bool bdcmp(const BluetoothAddress *addr1, const BluetoothAddress *addr2) {
//return (*(uint64_t *)addr1 & 0xffffffffffff0000) == (*(uint64_t *)addr2 & 0xffffffffffff0000);
return std::memcmp(addr1, addr2, sizeof(BluetoothAddress)) == 0;
}
inline bool isController(const BluetoothDeviceClass *cod) {
return ( (((uint8_t *)cod)[1] & 0x0f) == BTM_COD_MAJOR_PERIPHERAL ) &&
( ((((uint8_t *)cod)[2] & 0x0f) == BTM_COD_MINOR_GAMEPAD) ||
((((uint8_t *)cod)[2] & 0x0f) == BTM_COD_MINOR_JOYSTICK) );
}

View file

@ -1,149 +0,0 @@
#include <cstdio>
#include <cstdarg>
#include <ctype.h>
#include <switch.h>
#include "logger.hpp"
namespace mc::log {
/*
namespace {
Mutex logMutex;
}
void Write(const char *location, const char *fmt, ...) {
mutexLock(&logMutex);
FILE *fp = std::fopen(location, "a");
va_list va;
va_start(va, fmt);
std::vfprintf(fp, fmt, va);
va_end(va);
std::fprintf(fp, "\n");
std::fclose(fp);
mutexUnlock(&logMutex);
}
void WriteData(const char *location, void *data, size_t size) {
mutexLock(&logMutex);
FILE *fp = std::fopen(location, "a");
unsigned int i = 0;
while (i < size) {
// Print offset
std::fprintf(fp, " %04x", i);
std::fprintf(fp, " |");
// Print line of hex
unsigned int j;
for (j = 0; j < 16; ++j) {
if (i + j < size) {
std::fprintf(fp, " %02x", ((char *)data)[i+j]);
}
else {
break;
}
}
// Print separator
for (unsigned int k = 0; k < 16-j; ++k)
{
fprintf(fp, " ");
}
fprintf(fp, " | ");
// Print line of ascii
for (unsigned int j = 0; j < 16; ++j) {
if (i + j < size) {
char c = ((char *)data)[i+j];
std::fprintf(fp, "%c", isprint(c) ? c: 0x2e);
}
else {
break;
}
}
std::fprintf(fp, "\n");
i += 16;
}
std::fclose(fp);
mutexUnlock(&logMutex);
}
*/
Logger::Logger(const char *location) : m_location(location) {
mutexInit(&m_logMutex);
};
void Logger::write(const char *fmt, ...) {
mutexLock(&m_logMutex);
FILE *fp = std::fopen(m_location, "a");
va_list va;
va_start(va, fmt);
std::vfprintf(fp, fmt, va);
va_end(va);
std::fprintf(fp, "\n");
std::fclose(fp);
mutexUnlock(&m_logMutex);
}
void Logger::writeData(void *data, size_t size) {
mutexLock(&m_logMutex);
FILE *fp = std::fopen(m_location, "a");
unsigned int i = 0;
while (i < size) {
// Print offset
std::fprintf(fp, " %04x", i);
std::fprintf(fp, " |");
// Print line of hex
unsigned int j;
for (j = 0; j < 16; ++j) {
if (i + j < size) {
std::fprintf(fp, " %02x", ((char *)data)[i+j]);
}
else {
break;
}
}
// Print separator
for (unsigned int k = 0; k < 16-j; ++k)
{
fprintf(fp, " ");
}
fprintf(fp, " | ");
// Print line of ascii
for (unsigned int j = 0; j < 16; ++j) {
if (i + j < size) {
char c = ((char *)data)[i+j];
std::fprintf(fp, "%c", isprint(c) ? c: 0x2e);
}
else {
break;
}
}
std::fprintf(fp, "\n");
i += 16;
}
std::fclose(fp);
mutexUnlock(&m_logMutex);
}
}

View file

@ -1,222 +0,0 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITPRO)),)
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
endif
TOPDIR ?= $(CURDIR)
include $(DEVKITPRO)/libnx/switch_rules
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
# ROMFS is the directory containing data to be added to RomFS, relative to the Makefile (Optional)
#
# NO_ICON: if set to anything, do not use icon.
# NO_NACP: if set to anything, no .nacp file is generated.
# APP_TITLE is the name of the app stored in the .nacp file (Optional)
# APP_AUTHOR is the author of the app stored in the .nacp file (Optional)
# APP_VERSION is the version of the app stored in the .nacp file (Optional)
# APP_TITLEID is the titleID of the app stored in the .nacp file (Optional)
# ICON is the filename of the icon (.jpg), relative to the project folder.
# If not set, it attempts to use one of the following (in this order):
# - <Project name>.jpg
# - icon.jpg
# - <libnx folder>/default_icon.jpg
#
# CONFIG_JSON is the filename of the NPDM config file (.json), relative to the project folder.
# If not set, it attempts to use one of the following (in this order):
# - <Project name>.json
# - config.json
# If a JSON file is provided or autodetected, an ExeFS PFS0 (.nsp) is built instead
# of a homebrew executable (.nro). This is intended to be used for sysmodules.
# NACP building is skipped as well.
#---------------------------------------------------------------------------------
TARGET := $(notdir $(CURDIR))
BUILD := build
SOURCES := source source/bluetooth source/gamepad source/gamepad/controllers
DATA := data
INCLUDES := include ../common/include
#ROMFS := romfs
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
CFLAGS := -g -Wall -O2 -ffunction-sections \
$(ARCH) $(DEFINES)
CFLAGS += $(INCLUDE) -D__SWITCH__
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
LIBS := -lnx
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(PORTLIBS) $(LIBNX)
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET)
export TOPDIR := $(CURDIR)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
ifeq ($(strip $(CONFIG_JSON)),)
jsons := $(wildcard *.json)
ifneq (,$(findstring $(TARGET).json,$(jsons)))
export APP_JSON := $(TOPDIR)/$(TARGET).json
else
ifneq (,$(findstring config.json,$(jsons)))
export APP_JSON := $(TOPDIR)/config.json
endif
endif
else
export APP_JSON := $(TOPDIR)/$(CONFIG_JSON)
endif
ifeq ($(strip $(ICON)),)
icons := $(wildcard *.jpg)
ifneq (,$(findstring $(TARGET).jpg,$(icons)))
export APP_ICON := $(TOPDIR)/$(TARGET).jpg
else
ifneq (,$(findstring icon.jpg,$(icons)))
export APP_ICON := $(TOPDIR)/icon.jpg
endif
endif
else
export APP_ICON := $(TOPDIR)/$(ICON)
endif
ifeq ($(strip $(NO_ICON)),)
export NROFLAGS += --icon=$(APP_ICON)
endif
ifeq ($(strip $(NO_NACP)),)
export NROFLAGS += --nacp=$(CURDIR)/$(TARGET).nacp
endif
ifneq ($(APP_TITLEID),)
export NACPFLAGS += --titleid=$(APP_TITLEID)
endif
ifneq ($(ROMFS),)
export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)
endif
.PHONY: $(BUILD) clean all
#---------------------------------------------------------------------------------
all: $(BUILD)
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
ifeq ($(strip $(APP_JSON)),)
@rm -fr $(BUILD) $(TARGET).nro $(TARGET).nacp $(TARGET).elf
else
@rm -fr $(BUILD) $(TARGET).nsp $(TARGET).nso $(TARGET).npdm $(TARGET).elf
endif
#---------------------------------------------------------------------------------
else
.PHONY: all
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
ifeq ($(strip $(APP_JSON)),)
all : $(OUTPUT).nro
ifeq ($(strip $(NO_NACP)),)
$(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp
else
$(OUTPUT).nro : $(OUTPUT).elf
endif
else
all : $(OUTPUT).nsp
$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm
$(OUTPUT).nso : $(OUTPUT).elf
endif
$(OUTPUT).elf : $(OFILES)
$(OFILES_SRC) : $(HFILES_BIN)
#---------------------------------------------------------------------------------
# you need a rule like this for each extension you use as binary data
#---------------------------------------------------------------------------------
%.bin.o %_bin.h : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

View file

@ -1,19 +0,0 @@
#pragma once
#include <atomic>
#include <memory>
namespace mc::bluetooth::hid {
const constexpr size_t event_buffer_size = 0x480;
const constexpr size_t thread_stack_size = 0x4000;
extern std::atomic<bool> exitFlag;
void Initialise(void);
void Cleanup(void);
void PrepareForSleep(void);
void PrepareForWake(void);
void OnWake(void);
}

View file

@ -1,21 +0,0 @@
#include <switch.h>
#include "gamepad/virtualcontroller.hpp"
namespace mc::controller {
class AbstractedPadVirtualController : public VirtualController {
public:
AbstractedPadVirtualController();
~AbstractedPadVirtualController();
Result connect(void);
Result disconnect(void);
Result setState(const SwitchProGamepadState* state);
private:
uint8_t m_uniqueId;
HiddbgAbstractedPadState m_state;
};
}

View file

@ -1,41 +0,0 @@
#pragma once
#include <switch.h>
namespace mc::controller {
class BluetoothDatabase {
public:
static const uint8_t max_devices = 10;
static constexpr const char * default_location = "sdmc:/config/MissionControl/bluetooth.db";
BluetoothDatabase();
BluetoothDatabase(const char *location);
Result reload(void);
Result addDevice(const BluetoothDevice *device);
Result removeDevice(const BluetoothAddress *address);
const BluetoothDevice *search(const BluetoothAddress *address);
const BluetoothDevice *operator[](uint8_t index);
const BluetoothDevice *deviceAt(uint8_t index);
uint8_t indexOf(const BluetoothAddress *address);
uint8_t size(void);
private:
Result loadDatabase(void);
Result storeDatabase(void);
struct {
uint8_t size;
BluetoothDevice devices[BluetoothDatabase::max_devices];
} m_database;
const char * m_location;
};
}

View file

@ -1,26 +0,0 @@
#pragma once
#include <switch.h>
#include "gamepad/hidinterface.hpp"
namespace mc::controller {
class BluetoothInterface : public HidInterface {
public:
BluetoothInterface() : HidInterface(HidInterfaceType_Bluetooth) {};
Result connect(void);
Result disconnect(void);
Result wake(void);
Result sendData(const uint8_t *buffer, uint16_t length);
const BluetoothAddress& address(void) const;
void setAddress(const BluetoothAddress *address);
private:
BluetoothAddress m_address;
};
}

View file

@ -1,38 +0,0 @@
#pragma once
#include <memory>
#include <vector>
#include <switch.h>
#include "gamepad/bluetoothdatabase.hpp"
#include "gamepad/controllers.hpp"
namespace mc::controller {
class ControllerManager {
public:
ControllerManager();
~ControllerManager();
static ControllerType identify(uint16_t vid, uint16_t pid);
static ControllerType identify(const HardwareID *hwId);
static ControllerType identify(const BluetoothDevice *device);
Result registerBluetoothControllers(void);
Result attachBluetoothController(const BluetoothAddress *address);
Result removeBluetoothController(const BluetoothAddress *address);
Result receiveBluetoothReport(const BluetoothAddress *address, const HidReport *report);
//Result attachUsbController();
//Result removeUsbController();
//Result receiveUsbReport(, const HidReport *report);
void removeControllers(void);
private:
std::unique_ptr<BluetoothDatabase> m_database;
std::vector<std::unique_ptr<HidGamepad>> m_controllers;
};
}

View file

@ -1,8 +0,0 @@
#pragma once
#include "gamepad/controllers/joycon.hpp"
#include "gamepad/controllers/switchpro.hpp"
#include "gamepad/controllers/wiimote.hpp"
#include "gamepad/controllers/wiiupro.hpp"
#include "gamepad/controllers/dualshock4.hpp"
#include "gamepad/controllers/xboxone.hpp"

View file

@ -1,119 +0,0 @@
#pragma once
#include <switch.h>
#include "gamepad/hidgamepad.hpp"
namespace mc::controller {
enum Dualshock4ControllerVariant {
Dualshock4ControllerVariant_V1,
Dualshock4ControllerVariant_V2,
Dualshock4ControllerVariant_Unknown
};
enum Dualshock4DPadDirection {
Dualshock4DPad_N,
Dualshock4DPad_NE,
Dualshock4DPad_E,
Dualshock4DPad_SE,
Dualshock4DPad_S,
Dualshock4DPad_SW,
Dualshock4DPad_W,
Dualshock4DPad_NW,
Dualshock4DPad_Released
};
struct Dualshock4StickData {
uint8_t x;
uint8_t y;
};
struct Dualshock4ButtonData {
uint8_t dpad : 4;
uint8_t square : 1;
uint8_t cross : 1;
uint8_t circle : 1;
uint8_t triangle : 1;
uint8_t L1 : 1;
uint8_t R1 : 1;
uint8_t L2 : 1;
uint8_t R2 : 1;
uint8_t share : 1;
uint8_t options : 1;
uint8_t L3 : 1;
uint8_t R3 : 1;
uint8_t ps : 1;
uint8_t tpad : 1;
uint8_t counter : 6;
};
struct Dualshock4OutputReport0x11 {
struct {
uint8_t data[75];
};
uint32_t crc;
} __attribute__((packed));
struct Dualshock4InputReport0x01 {
Dualshock4StickData left_stick;
Dualshock4StickData right_stick;
Dualshock4ButtonData buttons;
uint8_t left_trigger;
uint8_t right_trigger;
};
/* This report is sent once the GET REPORT FEATURE 0x02 is received */
struct Dualshock4InputReport0x11 {
uint8_t _unk[2];
Dualshock4StickData left_stick;
Dualshock4StickData right_stick;
Dualshock4ButtonData buttons;
uint8_t left_trigger;
uint8_t right_trigger;
uint16_t timestamp;
uint8_t battery;
uint16_t vel_x;
uint16_t vel_y;
uint16_t vel_z;
uint16_t acc_x;
uint16_t acc_y;
uint16_t acc_z;
uint32_t _unk0;
uint8_t battery_level : 4;
uint8_t usb : 1;
uint8_t mic : 1;
uint8_t phone : 1;
uint8_t : 0;
uint16_t _unk2;
uint8_t tpad_packets;
uint8_t packet_counter;
};
union Dualshock4ReportData {
Dualshock4InputReport0x01 report0x01;
Dualshock4InputReport0x11 report0x11;
};
class Dualshock4Controller : public HidGamepad {
public:
static constexpr const HardwareID hardwareIds[] = {
{0x054c, 0x05c4}, // Official Dualshock4 v1
{0x054c, 0x09cc} // Official Dualshock4 v2
};
Dualshock4Controller(HidInterfaceType iface);
Result receiveReport(const HidReport *report);
private:
void mapStickValues(JoystickPosition *dst, const Dualshock4StickData *src);
void handleInputReport0x01(const Dualshock4ReportData *data);
void handleInputReport0x11(const Dualshock4ReportData *data);
};
}

View file

@ -1,77 +0,0 @@
#pragma once
#include <switch.h>
#include "gamepad/hidgamepad.hpp"
namespace mc::controller {
union JoyconStickData {
struct __attribute__ ((__packed__)) {
uint16_t x : 12;
uint16_t : 0;
uint8_t : 8;
};
struct __attribute__ ((__packed__)) {
uint8_t : 8;
uint16_t : 4;
uint16_t y : 12;
};
};
struct JoyconButtonData {
uint8_t Y : 1;
uint8_t X : 1;
uint8_t B : 1;
uint8_t A : 1;
uint8_t : 2; // SR, SL (Right Joy)
uint8_t R : 1;
uint8_t ZR : 1;
uint8_t minus : 1;
uint8_t plus : 1;
uint8_t rstick_press : 1;
uint8_t lstick_press : 1;
uint8_t home : 1;
uint8_t capture : 1;
uint8_t : 0;
uint8_t dpad_down : 1;
uint8_t dpad_up : 1;
uint8_t dpad_right : 1;
uint8_t dpad_left : 1;
uint8_t : 2; // SR, SL (Left Joy)
uint8_t L : 1;
uint8_t ZL : 1;
};
union JoyconReportData {
struct {
uint8_t conn_info : 4;
uint8_t battery : 4;
uint8_t timer;
JoyconButtonData buttons;
JoyconStickData left_stick;
JoyconStickData right_stick;
} report0x30;
};
class JoyconController : public HidGamepad {
public:
static constexpr const HardwareID hardwareIds[] = {
{0x057e, 2006}, // Official Joycon(L) Controller
{0x057e, 2007}, // Official Joycon(R) Controller
};
JoyconController(HidInterfaceType iface) : HidGamepad(iface) {};
Result receiveReport(const HidReport *report);
private:
void mapStickValues(JoystickPosition *dst, const JoyconStickData *src);
void handleInputReport0x30(const JoyconReportData *data);
};
}

View file

@ -1,76 +0,0 @@
#pragma once
#include <switch.h>
#include "gamepad/hidgamepad.hpp"
namespace mc::controller {
union SwitchProStickData {
struct __attribute__ ((__packed__)) {
uint16_t x : 12;
uint16_t : 0;
uint8_t : 8;
};
struct __attribute__ ((__packed__)) {
uint8_t : 8;
uint16_t : 4;
uint16_t y : 12;
};
};
struct SwitchProButtonData {
uint8_t Y : 1;
uint8_t X : 1;
uint8_t B : 1;
uint8_t A : 1;
uint8_t : 2; // SR, SL (Right Joy)
uint8_t R : 1;
uint8_t ZR : 1;
uint8_t minus : 1;
uint8_t plus : 1;
uint8_t rstick_press : 1;
uint8_t lstick_press : 1;
uint8_t home : 1;
uint8_t capture : 1;
uint8_t : 0;
uint8_t dpad_down : 1;
uint8_t dpad_up : 1;
uint8_t dpad_right : 1;
uint8_t dpad_left : 1;
uint8_t : 2; // SR, SL (Left Joy)
uint8_t L : 1;
uint8_t ZL : 1;
};
union SwitchProReportData {
struct {
uint8_t conn_info : 4;
uint8_t battery : 4;
uint8_t timer;
SwitchProButtonData buttons;
SwitchProStickData left_stick;
SwitchProStickData right_stick;
} report0x30;
};
class SwitchProController : public HidGamepad {
public:
static constexpr const HardwareID hardwareIds[] = {
{0x057e, 0x2009} // Official Switch Pro Controller
};
SwitchProController(HidInterfaceType iface) : HidGamepad(iface) {};
Result receiveReport(const HidReport *report);
private:
void mapStickValues(JoystickPosition *dst, const SwitchProStickData *src);
void handleInputReport0x30(const SwitchProReportData *data);
};
}

View file

@ -1,57 +0,0 @@
#pragma once
#include <switch.h>
#include "gamepad/hidgamepad.hpp"
namespace mc::controller {
enum WiimoteLEDs {
WiimoteLEDs_P1 = 0x10,
WiimoteLEDs_P2 = 0x20,
WiimoteLEDs_P3 = 0x40,
WiimoteLEDs_P4 = 0x80,
};
struct WiimoteButtonData {
uint8_t dpad_left : 1;
uint8_t dpad_right : 1;
uint8_t dpad_down : 1;
uint8_t dpad_up : 1;
uint8_t plus : 1;
uint8_t : 0;
uint8_t two : 1;
uint8_t one : 1;
uint8_t B : 1;
uint8_t A : 1;
uint8_t minus : 1;
uint8_t : 2;
uint8_t home : 1;
};
union WiimoteReportData {
struct {
WiimoteButtonData buttons;
uint8_t _unk;
} report0x30;
};
Result write_wiimote_memory(const BluetoothAddress *bd_addr, uint32_t address, const uint8_t *data, uint8_t length);
class WiimoteController : public HidGamepad {
public:
static constexpr const HardwareID hardwareIds[] = {
{0x057e, 0x0306}, // Official wiimote
};
WiimoteController(HidInterfaceType iface);
Result receiveReport(const HidReport *report);
private:
void handleInputReport0x30(const WiimoteReportData *data);
};
}

View file

@ -1,77 +0,0 @@
#pragma once
#include <switch.h>
#include "gamepad/controllers/wiimote.hpp"
#include "gamepad/hidgamepad.hpp"
namespace mc::controller {
struct WiiUProButtonData {
uint8_t : 1;
uint8_t R : 1;
uint8_t plus : 1;
uint8_t home : 1;
uint8_t minus : 1;
uint8_t L : 1;
uint8_t dpad_down : 1;
uint8_t dpad_right : 1;
uint8_t dpad_up : 1;
uint8_t dpad_left : 1;
uint8_t ZR : 1;
uint8_t X : 1;
uint8_t A : 1;
uint8_t Y : 1;
uint8_t B : 1;
uint8_t ZL : 1;
uint8_t rstick_press : 1;
uint8_t lstick_press : 1;
uint8_t : 0;
};
union WiiUProReportData {
struct {
WiimoteButtonData core_buttons;
/*
uint8_t left_stick_x : 6;
uint8_t right_stick_x2 : 2;
uint8_t left_stick_y : 6;
uint8_t right_stick_x1 : 2;
uint8_t right_stick_x0 : 1;
uint8_t left_trigger_1 : 2;
uint8_t right_stick_y : 5;
uint8_t left_trigger_0 : 3;
uint8_t right_trigger : 5;
*/
uint16_t left_stick_x;
uint16_t right_stick_x;
uint16_t left_stick_y;
uint16_t right_stick_y;
WiiUProButtonData buttons;
} report0x34;
};
class WiiUProController : public HidGamepad {
public:
static constexpr const HardwareID hardwareIds[] = {
{0x057e, 0x0330}, // Official Wii U Pro Controller
};
WiiUProController(HidInterfaceType iface);
Result receiveReport(const HidReport *report);
private:
void mapStickValues(JoystickPosition *dst, uint16_t x, uint16_t y);
void handleInputReport0x20(const WiiUProReportData *data);
void handleInputReport0x34(const WiiUProReportData *data);
};
}

View file

@ -1,75 +0,0 @@
#pragma once
#include <switch.h>
#include "gamepad/hidgamepad.hpp"
namespace mc::controller {
enum XboxOneDPadDirection {
XboxOneDPad_Released,
XboxOneDPad_N,
XboxOneDPad_NE,
XboxOneDPad_E,
XboxOneDPad_SE,
XboxOneDPad_S,
XboxOneDPad_SW,
XboxOneDPad_W,
XboxOneDPad_NW
};
struct XboxOneStickData {
uint16_t x;
uint16_t y;
};
struct XboxOneButtonData {
uint8_t dpad;
uint8_t A : 1;
uint8_t B : 1;
uint8_t X : 1;
uint8_t Y : 1;
uint8_t LB : 1;
uint8_t RB : 1;
uint8_t view : 1;
uint8_t menu : 1;
uint8_t lstick_press : 1;
uint8_t rstick_press : 1;
uint8_t : 0;
};
union XboxOneReportData {
struct {
XboxOneStickData left_stick;
XboxOneStickData right_stick;
uint16_t left_trigger;
uint16_t right_trigger;
XboxOneButtonData buttons;
} report0x01;
struct {
uint8_t guide : 1;
} report0x02;
};
class XboxOneController : public HidGamepad {
public:
static constexpr const HardwareID hardwareIds[] = {
{0x045e, 0x02e0}, // Official Xbox One S Controller (old FW?)
{0x045e, 0x02fd} // Official Xbox One S Controller
};
XboxOneController(HidInterfaceType iface);
Result receiveReport(const HidReport *report);
private:
void mapStickValues(JoystickPosition *dst, const XboxOneStickData *src);
void handleInputReport0x01(const XboxOneReportData *data);
void handleInputReport0x02(const XboxOneReportData *data);
};
}

View file

@ -1,24 +0,0 @@
#pragma once
#include <switch.h>
#include "gamepad/virtualcontroller.hpp"
namespace mc::controller {
class HdlsVirtualController : public VirtualController {
public:
HdlsVirtualController();
~HdlsVirtualController();
Result connect(void);
Result disconnect(void);
Result setState(const SwitchProGamepadState* state);
private:
uint64_t m_handle;
HiddbgHdlsDeviceInfo m_device;
HiddbgHdlsState m_state;
};
}

View file

@ -1,59 +0,0 @@
#pragma once
#include <memory>
#include <cmath>
#include <switch.h>
#include "gamepad/bluetoothinterface.hpp"
#include "gamepad/abstractedpad.hpp"
#include "gamepad/hdls.hpp"
namespace mc::controller {
enum ControllerType {
ControllerType_Joycon,
ControllerType_SwitchPro,
ControllerType_WiiUPro,
ControllerType_Wiimote,
ControllerType_Dualshock4,
ControllerType_XboxOne,
ControllerType_Unknown
};
struct HardwareID {
uint16_t vid;
uint16_t pid;
};
/* Convert an unsigned joystick value of arbitrary precision to int32 used by libnx */
inline int32_t unsigned_to_signed(uint32_t x, uint8_t nbits) {
return x * UINT16_MAX / (powf(2, nbits) - 1) + INT16_MIN;
}
class HidGamepad {
public:
friend class ControllerManager;
HidGamepad(HidInterfaceType type);
virtual ~HidGamepad() {};
//HidInterfaceType interfaceType(void) { return m_interface->type(); }
virtual Result receiveReport(const HidReport *report) = 0;
void setInnerDeadzone(float percentage);
void setOuterDeadzone(float percentage);
protected:
uint16_t m_innerDeadzone;
uint16_t m_outerDeadzone;
std::unique_ptr<BluetoothInterface> m_btInterface;
std::unique_ptr<VirtualController> m_virtual;
SwitchProGamepadState m_state;
};
}

View file

@ -1,27 +0,0 @@
#pragma once
#include <switch.h>
namespace mc::controller {
enum HidInterfaceType {
HidInterfaceType_Bluetooth,
HidInterfaceType_Usb
};
class HidInterface {
public:
HidInterface(HidInterfaceType type) : m_type(type) {};
HidInterfaceType type(void) { return m_type; }
virtual Result connect(void) = 0;
virtual Result disconnect(void) = 0;
private:
HidInterfaceType m_type;
};
}

View file

@ -1,48 +0,0 @@
#pragma once
#include <switch.h>
namespace mc::controller {
struct SwitchProGamepadState {
uint8_t Y : 1;
uint8_t X : 1;
uint8_t B : 1;
uint8_t A : 1;
uint8_t : 2; // SR, SL (Right Joy)
uint8_t R : 1;
uint8_t ZR : 1;
uint8_t minus : 1;
uint8_t plus : 1;
uint8_t rstick_press : 1;
uint8_t lstick_press : 1;
uint8_t home : 1;
uint8_t capture : 1;
uint8_t : 0;
uint8_t dpad_down : 1;
uint8_t dpad_up : 1;
uint8_t dpad_right : 1;
uint8_t dpad_left : 1;
uint8_t : 2; // SR, SL (Left Joy)
uint8_t L : 1;
uint8_t ZL : 1;
JoystickPosition left_stick;
JoystickPosition right_stick;
};
class VirtualController {
public:
virtual ~VirtualController() {};
virtual Result connect(void) = 0;
virtual Result disconnect(void) = 0;
virtual Result setState(const SwitchProGamepadState* state) = 0;
};
}

View file

@ -1,11 +0,0 @@
#pragma once
#include <cstdarg>
#include <cstdio>
namespace mc::log {
void Write(const char *fmt, ...);
void WriteData(void *data, size_t size);
}

View file

@ -1,225 +0,0 @@
#include <cstring>
#include "bluetooth/hid.hpp"
#include "gamepad/controllermanager.hpp"
#include "log.hpp"
namespace mc::bluetooth::hid {
std::atomic<bool> exitFlag(false);
namespace {
static Event btmDeviceInfoEvent = {};
static Event btmDeviceConditionEvent = {};
static Thread btmDeviceEventThread;
static BtmDeviceCondition connectedDevices = {};
static Event hidEvent = {};
static Thread hidEventThread;
static uint8_t hidEventBuffer[event_buffer_size] = {};
static Event hidReportEvent = {};
static Thread hidReportEventThread;
static uint8_t hidReportEventBuffer[event_buffer_size] = {};
std::unique_ptr<mc::controller::ControllerManager> controllerManager;
void handleConnectionStateEvent(const HidEventData *eventData) {
//mc::log::Write("Hid Connection State: %d", eventData->connectionState.state);
switch(eventData->connectionState.state) {
case HidConnectionState_Connected:
controllerManager->attachBluetoothController(&eventData->connectionState.address);
break;
case HidConnectionState_Disconnected:
controllerManager->removeBluetoothController(&eventData->connectionState.address);
break;
default:
break;
}
}
void hidEventThreadFunc(void* arg) {
Result rc;
HidEventType eventType;
HidEventData *eventData = reinterpret_cast<HidEventData *>(hidEventBuffer);
while (!exitFlag) {
if (R_SUCCEEDED(eventWait(&hidEvent, 1e9))) {
rc = btdrvGetHidEventInfo(&eventType, hidEventBuffer, sizeof(hidEventBuffer));
if R_FAILED(rc)
fatalThrow(rc);
eventClear(&hidEvent);
switch (eventType) {
case HidEvent_ConnectionState:
handleConnectionStateEvent(eventData);
break;
default:
//mc::log::Write("Unexpected Hid event: %d", eventType);
break;
}
}
}
}
void hidReportEventThreadFunc(void* arg) {
Result rc;
HidEventType eventType;
HidEventData *eventData = reinterpret_cast<HidEventData *>(hidReportEventBuffer);
while (!exitFlag) {
if (R_SUCCEEDED(eventWait(&hidReportEvent, 1e9))) {
rc = btdrvGetHidReportEventInfo(&eventType, hidReportEventBuffer, sizeof(hidReportEventBuffer));
if R_FAILED(rc)
fatalThrow(rc);
switch (eventType) {
case HidEvent_GetReport:
if (eventData->getReport.status == HidStatus_Ok) {
//mc::log::WriteData(&eventData->getReport.report_data.report, eventData->getReport.report_data.size);
controllerManager->receiveBluetoothReport(&eventData->getReport.address, &eventData->getReport.report_data.report);
}
break;
default:
mc::log::Write("Unexpected Hid report event: %d", eventType);
mc::log::WriteData(&eventData->getReport.report_data.report, eventData->getReport.report_data.size);
break;
}
}
}
}
}
void btmDeviceEventThreadFunc(void* arg) {
Result rc;
BtmDeviceCondition devices;
while (!exitFlag) {
if (R_SUCCEEDED(eventWait(&btmDeviceConditionEvent, 1e9))) {
rc = btmGetDeviceCondition(&devices);
if R_FAILED(rc)
fatalThrow(rc);
eventClear(&btmDeviceConditionEvent);
mc::log::Write("Device condition event");
for (int i = 0; i < devices.connected_count; ++i) {
mc::log::WriteData(&devices.devices[i], sizeof(BtmConnectedDevice));
}
int i;
if (devices.connected_count > connectedDevices.connected_count) {
i = devices.connected_count - 1;
controllerManager->attachBluetoothController(&devices.devices[i].address);
}
else if (devices.connected_count < connectedDevices.connected_count) {
/*
for (i = 0; i < ) {
}
controllerManager->removeBluetoothController();
*/
}
std::memcpy(&connectedDevices, &devices, sizeof(BtmDeviceCondition));
}
}
}
void Initialise(void) {
Result rc;
/* Init HID events */
rc = btdrvInitializeHid(&hidEvent, 1);
if R_FAILED(rc)
fatalThrow(rc);
uint8_t flags;
rc = btmAcquireDeviceConditionEvent(&btmDeviceConditionEvent, &flags);
if R_FAILED(rc)
fatalThrow(rc);
rc = btdrvRegisterHidReportEvent(&hidReportEvent);
if R_FAILED(rc)
fatalThrow(rc);
/* Init threads */
rc = threadCreate(&hidEventThread, hidEventThreadFunc, nullptr, nullptr, thread_stack_size, 0x2C, -2);
if R_FAILED(rc)
fatalThrow(rc);
rc = threadCreate(&hidReportEventThread, hidReportEventThreadFunc, nullptr, nullptr, thread_stack_size, 0x2C, -2);
if R_FAILED(rc)
fatalThrow(rc);
rc = threadCreate(&btmDeviceEventThread, btmDeviceEventThreadFunc, nullptr, nullptr, thread_stack_size, 0x2C, -2);
if R_FAILED(rc)
fatalThrow(rc);
/* Init controller manager */
controllerManager = std::make_unique<mc::controller::ControllerManager>();
//controllerManager->registerBluetoothControllers();
/* Start threads */
rc = threadStart(&hidEventThread);
if R_FAILED(rc)
fatalThrow(rc);
rc = threadStart(&hidReportEventThread);
if R_FAILED(rc)
fatalThrow(rc);
/*
rc = threadStart(&btmDeviceEventThread);
if R_FAILED(rc)
fatalThrow(rc);
*/
}
void Cleanup(void) {
/* Wait for all threads to finish */
threadWaitForExit(&btmDeviceEventThread);
threadWaitForExit(&hidReportEventThread);
threadWaitForExit(&hidEventThread);
/* Cleanup threads */
threadClose(&btmDeviceEventThread);
threadClose(&hidReportEventThread);
threadClose(&hidEventThread);
/* Cleanup events */
eventClose(&btmDeviceConditionEvent);
eventClose(&hidReportEvent);
eventClose(&hidEvent);
/* Cleanup Bluetooth HID interface */
//btdrvFinalizeHid();
}
void PrepareForSleep(void) {
mc::log::Write("Console preparing for sleep");
controllerManager->removeControllers();
}
void PrepareForWake(void) {
//controllerManager->registerBluetoothControllers();
mc::log::Write("Console preparing for wake");
}
void OnWake(void) {
mc::log::Write("Console awake");
}
}

View file

@ -1,66 +0,0 @@
#include <cstring>
#include "gamepad/abstractedpad.hpp"
namespace mc::controller {
AbstractedPadVirtualController::AbstractedPadVirtualController() {
std::memset(&m_state, 0, sizeof(HiddbgAbstractedPadState));
m_state.type = BIT(0); //maybe equivalent to HidDeviceTypeBits_FullKey
m_state.npadInterfaceType = NpadInterfaceType_Bluetooth;
m_state.flags = 0xff; //Don't know if needs to be this value
m_state.state.batteryCharge = 4;
m_state.singleColorBody = RGBA8_MAXALPHA(45, 45, 45);
m_state.singleColorButtons = RGBA8_MAXALPHA(230, 230, 230);
/* Todo: keep track of assigned ids and set this properly */
m_uniqueId = 0;
}
AbstractedPadVirtualController::~AbstractedPadVirtualController() {
this->disconnect();
}
Result AbstractedPadVirtualController::connect(void) {
return hiddbgSetAutoPilotVirtualPadState(m_uniqueId, &m_state);
}
Result AbstractedPadVirtualController::disconnect(void) {
return hiddbgUnsetAutoPilotVirtualPadState(m_uniqueId);
}
Result AbstractedPadVirtualController::setState(const SwitchProGamepadState* state) {
m_state.state.buttons = 0;
m_state.state.buttons |= state->A ? KEY_A : 0;
m_state.state.buttons |= state->B ? KEY_B : 0;
m_state.state.buttons |= state->X ? KEY_X : 0;
m_state.state.buttons |= state->Y ? KEY_Y : 0;
m_state.state.buttons |= state->dpad_down ? KEY_DDOWN : 0;
m_state.state.buttons |= state->dpad_up ? KEY_DUP : 0;
m_state.state.buttons |= state->dpad_right ? KEY_DRIGHT : 0;
m_state.state.buttons |= state->dpad_left ? KEY_DLEFT : 0;
m_state.state.buttons |= state->L ? KEY_L : 0;
m_state.state.buttons |= state->ZL ? KEY_ZL : 0;
m_state.state.buttons |= state->lstick_press ? KEY_LSTICK : 0;
m_state.state.buttons |= state->R ? KEY_R : 0;
m_state.state.buttons |= state->ZR ? KEY_ZR : 0;
m_state.state.buttons |= state->rstick_press ? KEY_RSTICK : 0;
m_state.state.buttons |= state->minus ? KEY_MINUS : 0;
m_state.state.buttons |= state->plus ? KEY_PLUS : 0;
m_state.state.buttons |= state->capture ? KEY_CAPTURE : 0;
m_state.state.buttons |= state->home ? KEY_HOME : 0;
m_state.state.joysticks[JOYSTICK_LEFT].dx = state->left_stick.dx;
m_state.state.joysticks[JOYSTICK_LEFT].dy = state->left_stick.dy;
m_state.state.joysticks[JOYSTICK_RIGHT].dx = state->right_stick.dx;
m_state.state.joysticks[JOYSTICK_RIGHT].dy = state->right_stick.dy;
return hiddbgSetAutoPilotVirtualPadState(m_uniqueId, &m_state);
}
}

View file

@ -1,134 +0,0 @@
#include <cstdio>
#include <cstring>
#include "gamepad/bluetoothdatabase.hpp"
#include "utils.hpp"
#include "logger.hpp"
namespace mc::controller {
BluetoothDatabase::BluetoothDatabase() : m_location(BluetoothDatabase::default_location) {
this->loadDatabase();
}
BluetoothDatabase::BluetoothDatabase(const char *location) : m_location(location) {
this->loadDatabase();
}
Result BluetoothDatabase::loadDatabase(void) {
FILE *fp = std::fopen(m_location, "rb");
if (fp == nullptr) {
//mc::log::Write("Error opening bluetooth database");
return -1;
}
//mc::log::Write("Reading bluetooth database...");
std::fread(&m_database, sizeof(m_database), 1, fp);
std::fclose(fp);
if (std::ferror(fp)) {
//mc::log::Write("Error loading bluetooth database");
return -1;
}
return 0;
}
Result BluetoothDatabase::storeDatabase(void) {
FILE *fp = std::fopen(m_location, "wb");
if (fp == nullptr) {
//mc::log::Write("Error opening bluetooth database");
return -1;
}
//mc::log::Write("Writing bluetooth database...");
std::fwrite(&m_database, sizeof(m_database), 1, fp);
std::fclose(fp);
if (std::ferror(fp)) {
//mc::log::Write("Error writing bluetooth database");
return -1;
}
return 0;
}
Result BluetoothDatabase::reload(void) {
return this->loadDatabase();
}
Result BluetoothDatabase::addDevice(const BluetoothDevice *device) {
if (device == nullptr) {
//mc::log::Write("BluetoothDatabase::addDevice: device is nullptr");
return -1;
}
/* Check if device is already in database */
const BluetoothDevice *existing = this->search(&device->address);
if (existing) {
//mc::log::Write("Copying over exiting database entry...");
/* Overwrite existing database entry */
std::memcpy(const_cast<BluetoothDevice *>(existing), device, sizeof(BluetoothDevice));
}
else if (m_database.size < BluetoothDatabase::max_devices) {
//mc::log::Write("Adding new device to bluetooth database...");
/* Add new device to the database */
std::memcpy(&m_database.devices[m_database.size++], device, sizeof(BluetoothDevice));
}
else {
return -1;
}
return this->storeDatabase();
}
Result BluetoothDatabase::removeDevice(const BluetoothAddress *address) {
/* Locate index of device in database */
uint8_t index = this->indexOf(address);
if (index >= 0) {
/* remove device from database and shift remaining devices down */
std::memcpy(&m_database.devices[index], &m_database.devices[index+1], (m_database.size-index-1) * sizeof(BluetoothDevice));
std::memset(&m_database.devices[--m_database.size], 0, sizeof(BluetoothDevice));
}
return this->storeDatabase();
}
const BluetoothDevice *BluetoothDatabase::search(const BluetoothAddress *address) {
for (uint8_t i = 0; i < m_database.size; ++i) {
if (bdcmp(address, &m_database.devices[i].address)) {
return &m_database.devices[i];
}
}
return nullptr;
}
const BluetoothDevice *BluetoothDatabase::operator[](uint8_t index) {
return this->deviceAt(index);
}
const BluetoothDevice *BluetoothDatabase::deviceAt(uint8_t index) {
if (index < m_database.size) {
return &m_database.devices[index];
}
return nullptr;
}
uint8_t BluetoothDatabase::indexOf(const BluetoothAddress *address) {
for (uint8_t i = 0; i < m_database.size; ++i) {
if (bdcmp(address, &m_database.devices[i].address)) {
return i;
}
}
return -1;
}
uint8_t BluetoothDatabase::size(void) {
return m_database.size;
}
}

View file

@ -1,30 +0,0 @@
#include <cstring>
#include "gamepad/bluetoothinterface.hpp"
namespace mc::controller {
Result BluetoothInterface::connect(void) {
return btdrvOpenHidConnection(&m_address);
}
Result BluetoothInterface::disconnect(void) {
return btdrvCloseHidConnection(&m_address);
}
Result BluetoothInterface::wake(void) {
return btdrvTriggerConnection(&m_address, 0);
}
Result BluetoothInterface::sendData(const uint8_t *buffer, uint16_t length) {
return btdrvWriteHidData2(&m_address, buffer, length);
}
const BluetoothAddress& BluetoothInterface::address(void) const {
return m_address;
}
void BluetoothInterface::setAddress(const BluetoothAddress *address) {
std::memcpy(&m_address, address, sizeof(BluetoothAddress));
}
}

View file

@ -1,226 +0,0 @@
#include <algorithm>
#include "gamepad/controllermanager.hpp"
#include "gamepad/bluetoothinterface.hpp"
#include "utils.hpp"
#include "log.hpp"
namespace mc::controller {
ControllerManager::ControllerManager() {
if (hosversionAtLeast(7, 0, 0)) {
Result rc = hiddbgAttachHdlsWorkBuffer();
if R_FAILED(rc)
fatalThrow(rc);
}
m_database = std::make_unique<BluetoothDatabase>();
}
ControllerManager::~ControllerManager() {
if (hosversionAtLeast(7, 0, 0)) {
Result rc = hiddbgReleaseHdlsWorkBuffer();
if R_FAILED(rc)
fatalThrow(rc);
}
}
ControllerType ControllerManager::identify(uint16_t vid, uint16_t pid) {
for (HardwareID hwId : JoyconController::hardwareIds) {
if ( (vid == hwId.vid) && (pid == hwId.pid) ) {
return ControllerType_Joycon;
}
}
for (HardwareID hwId : SwitchProController::hardwareIds) {
if ( (vid == hwId.vid) && (pid == hwId.pid) ) {
return ControllerType_SwitchPro;
}
}
for (HardwareID hwId : WiiUProController::hardwareIds) {
if ( (vid == hwId.vid) && (pid == hwId.pid) ) {
return ControllerType_WiiUPro;
}
}
for (HardwareID hwId : WiimoteController::hardwareIds) {
if ( (vid == hwId.vid) && (pid == hwId.pid) ) {
return ControllerType_Wiimote;
}
}
for (HardwareID hwId : Dualshock4Controller::hardwareIds) {
if ( (vid == hwId.vid) && (pid == hwId.pid) ) {
return ControllerType_Dualshock4;
}
}
for (HardwareID hwId : XboxOneController::hardwareIds) {
if ( (vid == hwId.vid) && (pid == hwId.pid) ) {
return ControllerType_XboxOne;
}
}
return ControllerType_Unknown;
}
ControllerType ControllerManager::identify(const HardwareID *hwId) {
return ControllerManager::identify(hwId->vid, hwId->pid);
}
ControllerType ControllerManager::identify(const BluetoothDevice *device) {
return ControllerManager::identify(device->vid, device->pid);
}
Result ControllerManager::registerBluetoothControllers(void) {
Result rc;
/* Register database entries with bluetooth module */
for (uint8_t i = 0; i < m_database->size(); ++i) {
rc = btdrvAddPairedDeviceInfo(m_database->deviceAt(i));
if R_FAILED(rc)
fatalThrow(rc);
}
//mc::log::Write("Registered pairing database with bluetooth module");
return 0;
}
Result ControllerManager::attachBluetoothController(const BluetoothAddress *address) {
const BluetoothDevice *device = m_database->search(address);
if (device) {
switch (this->identify(device)) {
case ControllerType_SwitchPro:
m_controllers.push_back(std::make_unique<SwitchProController>(HidInterfaceType_Bluetooth));
break;
case ControllerType_WiiUPro:
m_controllers.push_back(std::make_unique<WiiUProController>(HidInterfaceType_Bluetooth));
break;
case ControllerType_Wiimote:
m_controllers.push_back(std::make_unique<WiimoteController>(HidInterfaceType_Bluetooth));
break;
case ControllerType_Dualshock4:
{
m_controllers.push_back(std::make_unique<Dualshock4Controller>(HidInterfaceType_Bluetooth));
/*
// This definitely doesn't belong here
uint8_t r = 0xff;
uint8_t g = 0x00;
uint8_t b = 0x00;
Dualshock4OutputReport0x11 report = {0xa2, 0x11, 0xc0, 0x20, 0xf3, 0x04, 0x00, 0x00, 0x00, r, g, b};
report.crc = crc32Calculate(report.data, sizeof(report.data));
BluetoothHidData hidData = {};
hidData.length = sizeof(report) - 1;
std::memcpy(&hidData.data, &report.data[1], hidData.length);
Result rc = btdrvHidSetReport(address, HidReportType_OutputReport, &hidData);
*/
}
break;
case ControllerType_XboxOne:
m_controllers.push_back(std::make_unique<XboxOneController>(HidInterfaceType_Bluetooth));
break;
default:
//mc::log::Write("Unrecognised device: <%04x:%04x>", device->vid, device->pid);
return -1;
}
// Pretty filthy hack until I work out how to structure this better
m_controllers.back()->m_btInterface->setAddress(address);
/*
mc::log::Write("ControllerManager::attachBluetoothController: Attached bluetooth controller [%02x:%02x:%02x:%02x:%02x:%02x]",
((uint8_t *)address)[0],
((uint8_t *)address)[1],
((uint8_t *)address)[2],
((uint8_t *)address)[3],
((uint8_t *)address)[4],
((uint8_t *)address)[5]
);
*/
return 0;
}
return -1;
}
Result ControllerManager::removeBluetoothController(const BluetoothAddress *address) {
for (auto it = m_controllers.begin(); it < m_controllers.end(); ++it) {
if ((*it)->m_btInterface != nullptr) {
if (bdcmp(&(*it)->m_btInterface->address(), address)) {
m_controllers.erase(it);
/*
mc::log::Write("ControllerManager::removeBluetoothController: Removed bluetooth controller [%02x:%02x:%02x:%02x:%02x:%02x]",
((uint8_t *)address)[0],
((uint8_t *)address)[1],
((uint8_t *)address)[2],
((uint8_t *)address)[3],
((uint8_t *)address)[4],
((uint8_t *)address)[5]
);
*/
return 0;
}
}
}
/*
mc::log::Write("ControllerManager::removeBluetoothController: Couldn't located controller [%02x:%02x:%02x:%02x:%02x:%02x]",
((uint8_t *)address)[0],
((uint8_t *)address)[1],
((uint8_t *)address)[2],
((uint8_t *)address)[3],
((uint8_t *)address)[4],
((uint8_t *)address)[5]
);
*/
return -1;
}
void ControllerManager::removeControllers(void) {
//mc::log::Write("Removing all controllers");
m_controllers.clear();
}
Result ControllerManager::receiveBluetoothReport(const BluetoothAddress *address, const HidReport *report) {
for (auto it = m_controllers.begin(); it < m_controllers.end(); ++it) {
if ((*it)->m_btInterface != nullptr) {
if (bdcmp(&(*it)->m_btInterface->address(), address)) {
(*it)->receiveReport(report);
return 0;
}
}
}
/*
mc::log::Write("ControllerManager::receiveBluetoothReport: Controller not found [%02x:%02x:%02x:%02x:%02x:%02x] ",
((uint8_t *)address)[0],
((uint8_t *)address)[1],
((uint8_t *)address)[2],
((uint8_t *)address)[3],
((uint8_t *)address)[4],
((uint8_t *)address)[5]
);
*/
return -1;
}
}

View file

@ -1,136 +0,0 @@
#include <cstring>
#include <cmath>
#include "gamepad/controllers/dualshock4.hpp"
namespace mc::controller {
namespace {
const constexpr uint8_t dualshock4_joystick_nbits = 8;
}
Dualshock4Controller::Dualshock4Controller(HidInterfaceType iface) : HidGamepad(iface) {
this->setInnerDeadzone(0.1);
}
void Dualshock4Controller::mapStickValues(JoystickPosition *dst, const Dualshock4StickData *src) {
dst->dx = unsigned_to_signed(src->x, dualshock4_joystick_nbits);
dst->dy = -unsigned_to_signed(src->y, dualshock4_joystick_nbits);
float angle = atan2(dst->dy, dst->dx);
float magnitude = hypot(dst->dx, dst->dy);
if (magnitude < m_innerDeadzone) {
dst->dx = 0;
dst->dy = 0;
}
else if (magnitude > m_outerDeadzone) {
dst->dx = JOYSTICK_MAX * cos(angle);
dst->dy = JOYSTICK_MAX * sin(angle);
}
}
Result Dualshock4Controller::receiveReport(const HidReport *report) {
const Dualshock4ReportData *reportData = reinterpret_cast<const Dualshock4ReportData *>(&report->data);
switch(report->id) {
case 0x01:
handleInputReport0x01(reportData);
break;
case 0x11:
handleInputReport0x11(reportData);
break;
default:
return -1;
}
return 0;
}
void Dualshock4Controller::handleInputReport0x01(const Dualshock4ReportData *data) {
std::memset(&m_state, 0, sizeof(m_state));
this->mapStickValues(&m_state.left_stick, &data->report0x01.left_stick);
this->mapStickValues(&m_state.right_stick, &data->report0x01.right_stick);
m_state.dpad_left = (data->report0x01.buttons.dpad == Dualshock4DPad_W) ||
(data->report0x01.buttons.dpad == Dualshock4DPad_NW) ||
(data->report0x01.buttons.dpad == Dualshock4DPad_SW);
m_state.dpad_up = (data->report0x01.buttons.dpad == Dualshock4DPad_N) ||
(data->report0x01.buttons.dpad == Dualshock4DPad_NE) ||
(data->report0x01.buttons.dpad == Dualshock4DPad_NW);
m_state.dpad_right = (data->report0x01.buttons.dpad == Dualshock4DPad_E) ||
(data->report0x01.buttons.dpad == Dualshock4DPad_NE) ||
(data->report0x01.buttons.dpad == Dualshock4DPad_SE);
m_state.dpad_down = (data->report0x01.buttons.dpad == Dualshock4DPad_S) ||
(data->report0x01.buttons.dpad == Dualshock4DPad_SE) ||
(data->report0x01.buttons.dpad == Dualshock4DPad_SW);
m_state.Y = data->report0x01.buttons.square;
m_state.X = data->report0x01.buttons.triangle;
m_state.B = data->report0x01.buttons.cross;
m_state.A = data->report0x01.buttons.circle;
m_state.L = data->report0x01.buttons.L1;
m_state.ZL = data->report0x01.buttons.L2;
m_state.lstick_press = data->report0x01.buttons.L3;
m_state.R = data->report0x01.buttons.R1;
m_state.ZR = data->report0x01.buttons.R2;
m_state.rstick_press = data->report0x01.buttons.R3;
m_state.minus = data->report0x01.buttons.share;
m_state.plus = data->report0x01.buttons.options;
m_state.capture = data->report0x01.buttons.tpad;
m_state.home = data->report0x01.buttons.ps;
m_virtual->setState(&m_state);
}
void Dualshock4Controller::handleInputReport0x11(const Dualshock4ReportData *data) {
std::memset(&m_state, 0, sizeof(m_state));
this->mapStickValues(&m_state.left_stick, &data->report0x11.left_stick);
this->mapStickValues(&m_state.right_stick, &data->report0x11.right_stick);
m_state.dpad_left = (data->report0x11.buttons.dpad == Dualshock4DPad_W) ||
(data->report0x11.buttons.dpad == Dualshock4DPad_NW) ||
(data->report0x11.buttons.dpad == Dualshock4DPad_SW);
m_state.dpad_up = (data->report0x11.buttons.dpad == Dualshock4DPad_N) ||
(data->report0x11.buttons.dpad == Dualshock4DPad_NE) ||
(data->report0x11.buttons.dpad == Dualshock4DPad_NW);
m_state.dpad_right = (data->report0x11.buttons.dpad == Dualshock4DPad_E) ||
(data->report0x11.buttons.dpad == Dualshock4DPad_NE) ||
(data->report0x11.buttons.dpad == Dualshock4DPad_SE);
m_state.dpad_down = (data->report0x11.buttons.dpad == Dualshock4DPad_S) ||
(data->report0x11.buttons.dpad == Dualshock4DPad_SE) ||
(data->report0x11.buttons.dpad == Dualshock4DPad_SW);
m_state.Y = data->report0x11.buttons.square;
m_state.X = data->report0x11.buttons.triangle;
m_state.B = data->report0x11.buttons.cross;
m_state.A = data->report0x11.buttons.circle;
m_state.L = data->report0x11.buttons.L1;
m_state.ZL = data->report0x11.buttons.L2;
m_state.lstick_press = data->report0x11.buttons.L3;
m_state.R = data->report0x11.buttons.R1;
m_state.ZR = data->report0x11.buttons.R2;
m_state.rstick_press = data->report0x11.buttons.R3;
m_state.minus = data->report0x11.buttons.share;
m_state.plus = data->report0x11.buttons.options;
m_state.capture = data->report0x11.buttons.tpad;
m_state.home = data->report0x11.buttons.ps;
m_virtual->setState(&m_state);
}
}

View file

@ -1,78 +0,0 @@
#include <cstring>
#include <cmath>
#include "gamepad/controllers/joycon.hpp"
namespace mc::controller {
namespace {
const constexpr uint8_t joycon_joystick_nbits = 12;
}
void JoyconController::mapStickValues(JoystickPosition *dst, const JoyconStickData *src) {
dst->dx = unsigned_to_signed(src->x, joycon_joystick_nbits);
dst->dy = -unsigned_to_signed(src->y, joycon_joystick_nbits);
float angle = atan2(dst->dy, dst->dx);
float magnitude = hypot(dst->dx, dst->dy);
if (magnitude < m_innerDeadzone) {
dst->dx = 0;
dst->dy = 0;
}
else if (magnitude > m_outerDeadzone) {
dst->dx = JOYSTICK_MAX * cos(angle);
dst->dy = JOYSTICK_MAX * sin(angle);
}
}
Result JoyconController::receiveReport(const HidReport *report) {
const JoyconReportData *reportData = reinterpret_cast<const JoyconReportData *>(&report->data);
switch(report->id) {
case 0x30:
handleInputReport0x30(reportData);
break;
default:
return -1;
}
return 0;
}
void JoyconController::handleInputReport0x30(const JoyconReportData *data) {
std::memset(&m_state, 0, sizeof(m_state));
this->mapStickValues(&m_state.left_stick, &data->report0x30.left_stick);
this->mapStickValues(&m_state.right_stick, &data->report0x30.right_stick);
m_state.dpad_left = data->report0x30.buttons.dpad_left;
m_state.dpad_up = data->report0x30.buttons.dpad_up;
m_state.dpad_right = data->report0x30.buttons.dpad_right;
m_state.dpad_down = data->report0x30.buttons.dpad_down;
m_state.A = data->report0x30.buttons.A;
m_state.B = data->report0x30.buttons.B;
m_state.X = data->report0x30.buttons.X;
m_state.Y = data->report0x30.buttons.Y;
m_state.L = data->report0x30.buttons.L;
m_state.ZL = data->report0x30.buttons.ZL;
m_state.lstick_press = data->report0x30.buttons.lstick_press;
m_state.R = data->report0x30.buttons.R;
m_state.ZR = data->report0x30.buttons.ZR;
m_state.rstick_press = data->report0x30.buttons.rstick_press;
m_state.minus = data->report0x30.buttons.minus;
m_state.plus = data->report0x30.buttons.plus;
m_state.capture = data->report0x30.buttons.capture;
m_state.home = data->report0x30.buttons.home;
m_virtual->setState(&m_state);
}
}

View file

@ -1,78 +0,0 @@
#include <cstring>
#include <cmath>
#include "gamepad/controllers/switchpro.hpp"
namespace mc::controller {
namespace {
const constexpr uint8_t switchpro_joystick_nbits = 12;
}
void SwitchProController::mapStickValues(JoystickPosition *dst, const SwitchProStickData *src) {
dst->dx = unsigned_to_signed(src->x, switchpro_joystick_nbits);
dst->dy = -unsigned_to_signed(src->y, switchpro_joystick_nbits);
float angle = atan2(dst->dy, dst->dx);
float magnitude = hypot(dst->dx, dst->dy);
if (magnitude < m_innerDeadzone) {
dst->dx = 0;
dst->dy = 0;
}
else if (magnitude > m_outerDeadzone) {
dst->dx = JOYSTICK_MAX * cos(angle);
dst->dy = JOYSTICK_MAX * sin(angle);
}
}
Result SwitchProController::receiveReport(const HidReport *report) {
const SwitchProReportData *reportData = reinterpret_cast<const SwitchProReportData *>(&report->data);
switch(report->id) {
case 0x30:
handleInputReport0x30(reportData);
break;
default:
return -1;
}
return 0;
}
void SwitchProController::handleInputReport0x30(const SwitchProReportData *data) {
std::memset(&m_state, 0, sizeof(m_state));
this->mapStickValues(&m_state.left_stick, &data->report0x30.left_stick);
this->mapStickValues(&m_state.right_stick, &data->report0x30.right_stick);
m_state.dpad_left = data->report0x30.buttons.dpad_left;
m_state.dpad_up = data->report0x30.buttons.dpad_up;
m_state.dpad_right = data->report0x30.buttons.dpad_right;
m_state.dpad_down = data->report0x30.buttons.dpad_down;
m_state.A = data->report0x30.buttons.A;
m_state.B = data->report0x30.buttons.B;
m_state.X = data->report0x30.buttons.X;
m_state.Y = data->report0x30.buttons.Y;
m_state.L = data->report0x30.buttons.L;
m_state.ZL = data->report0x30.buttons.ZL;
m_state.lstick_press = data->report0x30.buttons.lstick_press;
m_state.R = data->report0x30.buttons.R;
m_state.ZR = data->report0x30.buttons.ZR;
m_state.rstick_press = data->report0x30.buttons.rstick_press;
m_state.minus = data->report0x30.buttons.minus;
m_state.plus = data->report0x30.buttons.plus;
m_state.capture = data->report0x30.buttons.capture;
m_state.home = data->report0x30.buttons.home;
m_virtual->setState(&m_state);
}
}

View file

@ -1,80 +0,0 @@
#include <cstring>
#include "gamepad/controllers/wiimote.hpp"
#include "byteswap.h"
#include "log.hpp"
namespace mc::controller {
WiimoteController::WiimoteController(HidInterfaceType iface) : HidGamepad(iface) {
//this->setInnerDeadzone(0.1);
/*
uint8_t reportdata[] = {0x11, 0x10}; // set player led
BluetoothHidData hidData = {};
hidData.length = sizeof(reportdata);
std::memcpy(&hidData.data, &reportdata, sizeof(reportdata));
btdrvHidSetReport(&address, HidReportType_OutputReport, &hidData);
*/
}
Result write_wiimote_memory(const BluetoothAddress *bd_addr, uint32_t address, const uint8_t *data, uint8_t length) {
const struct {
uint8_t id;
uint32_t address;
uint8_t length;
uint8_t data[0x10];
} __attribute__((packed)) report = {0x16, __bswap_32(address), length, *data};
//std::memcpy(report.data, data, length);
BluetoothHidData hidData = {};
hidData.length = sizeof(report);
std::memcpy(&hidData.data, &report, sizeof(report));
mc::log::Write("Writing to wii remote control registers");
mc::log::WriteData(&hidData.data, hidData.length);
return btdrvWriteHidData(bd_addr, &hidData);
}
Result WiimoteController::receiveReport(const HidReport *report) {
const WiimoteReportData *reportData = reinterpret_cast<const WiimoteReportData *>(&report->data);
switch(report->id) {
case 0x30:
handleInputReport0x30(reportData);
break;
default:
return -1;
}
return 0;
}
void WiimoteController::handleInputReport0x30(const WiimoteReportData *data) {
std::memset(&m_state, 0, sizeof(m_state));
m_state.dpad_left = data->report0x30.buttons.dpad_up;
m_state.dpad_up = data->report0x30.buttons.dpad_right;
m_state.dpad_right = data->report0x30.buttons.dpad_down;
m_state.dpad_down = data->report0x30.buttons.dpad_left;
m_state.A = data->report0x30.buttons.two;
m_state.B = data->report0x30.buttons.one;
m_state.L = data->report0x30.buttons.B;
m_state.R = data->report0x30.buttons.A;
m_state.plus = data->report0x30.buttons.plus;
m_state.minus = data->report0x30.buttons.minus;
m_state.home = data->report0x30.buttons.home;
m_virtual->setState(&m_state);
}
}

View file

@ -1,135 +0,0 @@
#include <cstring>
#include "gamepad/controllers/wiiupro.hpp"
#include "log.hpp"
namespace mc::controller {
namespace {
const constexpr uint8_t wiiupro_joystick_nbits = 12;
Result send_init_1(const BluetoothAddress *address) {
const uint8_t data[] = {0x55};
return write_wiimote_memory(address, 0x04a400f0, data, sizeof(data));
}
Result send_init_2(const BluetoothAddress *address) {
const uint8_t data[] = {0x00};
return write_wiimote_memory(address, 0x04a400fb, data, sizeof(data));
}
Result set_report_mode(const BluetoothAddress *address, uint8_t mode) {
uint8_t data[] = {0x12, 0x00, mode};
BluetoothHidData hidData = {};
hidData.length = sizeof(data);
std::memcpy(&hidData.data, data, sizeof(data));
return btdrvWriteHidData(address, &hidData);
}
Result set_player_leds(const BluetoothAddress *address, uint8_t mask) {
uint8_t data[] = {0x11, mask}; // set player led
BluetoothHidData hidData = {};
hidData.length = sizeof(data);
std::memcpy(&hidData.data, data, sizeof(data));
return btdrvWriteHidData(address, &hidData);
}
}
WiiUProController::WiiUProController(HidInterfaceType iface) : HidGamepad(iface) {
this->setInnerDeadzone(0.15);
}
void WiiUProController::mapStickValues(JoystickPosition *dst, uint16_t x, uint16_t y) {
dst->dx = 2*unsigned_to_signed(x, wiiupro_joystick_nbits);
dst->dy = 2*unsigned_to_signed(y, wiiupro_joystick_nbits);
float angle = atan2(dst->dy, dst->dx);
float magnitude = hypot(dst->dx, dst->dy);
if (magnitude < m_innerDeadzone) {
dst->dx = 0;
dst->dy = 0;
}
else if (magnitude > m_outerDeadzone) {
dst->dx = JOYSTICK_MAX * cos(angle);
dst->dy = JOYSTICK_MAX * sin(angle);
}
}
Result WiiUProController::receiveReport(const HidReport *report) {
const WiiUProReportData *reportData = reinterpret_cast<const WiiUProReportData *>(&report->data);
switch(report->id) {
case 0x20: //extension connected
handleInputReport0x20(reportData);
break;
case 0x22: // Acknowledgement
break;
case 0x32: // Buttons + Ext bytes
break;
case 0x34: // Buttons + Ext bytes
handleInputReport0x34(reportData);
break;
default:
return -1;
}
return 0;
}
void WiiUProController::handleInputReport0x20(const WiiUProReportData *data) {
Result rc;
const BluetoothAddress address = this->m_btInterface->address();
rc = set_player_leds(&address, WiimoteLEDs_P1);
rc = send_init_1(&address);
rc = send_init_2(&address);
rc = set_report_mode(&address, 0x34);
}
void WiiUProController::handleInputReport0x34(const WiiUProReportData *data) {
std::memset(&m_state, 0, sizeof(m_state));
/*
this->mapStickValues(&m_state.left_stick, data->report0x34.left_stick_x, data->report0x34.left_stick_y, 6);
this->mapStickValues(&m_state.right_stick,
data->report0x34.right_stick_x0 | (data->report0x34.right_stick_x1 << 1) | (data->report0x34.right_stick_x2 << 3),
data->report0x34.right_stick_y, 5);
*/
this->mapStickValues(&m_state.left_stick, data->report0x34.left_stick_x, data->report0x34.left_stick_y);
this->mapStickValues(&m_state.right_stick, data->report0x34.right_stick_x, data->report0x34.right_stick_y);
m_state.dpad_left = !data->report0x34.buttons.dpad_left;
m_state.dpad_up = !data->report0x34.buttons.dpad_up;
m_state.dpad_right = !data->report0x34.buttons.dpad_right;
m_state.dpad_down = !data->report0x34.buttons.dpad_down;
m_state.A = !data->report0x34.buttons.A;
m_state.B = !data->report0x34.buttons.B;
m_state.X = !data->report0x34.buttons.X;
m_state.Y = !data->report0x34.buttons.Y;
m_state.L = !data->report0x34.buttons.L;
m_state.ZL = !data->report0x34.buttons.ZL;
m_state.lstick_press = !data->report0x34.buttons.lstick_press;
m_state.R = !data->report0x34.buttons.R;
m_state.ZR = !data->report0x34.buttons.ZR;
m_state.rstick_press = !data->report0x34.buttons.rstick_press;
m_state.plus = !data->report0x34.buttons.plus;
m_state.minus = !data->report0x34.buttons.minus;
m_state.home = !data->report0x34.buttons.home;
m_virtual->setState(&m_state);
}
}

View file

@ -1,102 +0,0 @@
#include <cstring>
#include <cmath>
#include "gamepad/controllers/xboxone.hpp"
namespace mc::controller {
namespace {
const constexpr uint8_t xboxone_joystick_nbits = 16;
}
XboxOneController::XboxOneController(HidInterfaceType iface) : HidGamepad(iface) {
this->setInnerDeadzone(0.1);
}
void XboxOneController::mapStickValues(JoystickPosition *dst, const XboxOneStickData *src) {
dst->dx = unsigned_to_signed(src->x, xboxone_joystick_nbits);
dst->dy = -unsigned_to_signed(src->y, xboxone_joystick_nbits);
float angle = atan2(dst->dy, dst->dx);
float magnitude = hypot(dst->dx, dst->dy);
if (magnitude < m_innerDeadzone) {
dst->dx = 0;
dst->dy = 0;
}
else if (magnitude > m_outerDeadzone) {
dst->dx = JOYSTICK_MAX * cos(angle);
dst->dy = JOYSTICK_MAX * sin(angle);
}
}
Result XboxOneController::receiveReport(const HidReport *report) {
const XboxOneReportData *reportData = reinterpret_cast<const XboxOneReportData *>(&report->data);
switch(report->id) {
case 0x01:
handleInputReport0x01(reportData);
break;
case 0x02:
handleInputReport0x02(reportData);
break;
default:
return -1;
}
return 0;
}
void XboxOneController::handleInputReport0x01(const XboxOneReportData *data) {
std::memset(&m_state, 0, sizeof(m_state));
this->mapStickValues(&m_state.left_stick, &data->report0x01.left_stick);
this->mapStickValues(&m_state.right_stick, &data->report0x01.right_stick);
m_state.dpad_left = (data->report0x01.buttons.dpad == XboxOneDPad_W) ||
(data->report0x01.buttons.dpad == XboxOneDPad_NW) ||
(data->report0x01.buttons.dpad == XboxOneDPad_SW);
m_state.dpad_up = (data->report0x01.buttons.dpad == XboxOneDPad_N) ||
(data->report0x01.buttons.dpad == XboxOneDPad_NE) ||
(data->report0x01.buttons.dpad == XboxOneDPad_NW);
m_state.dpad_right = (data->report0x01.buttons.dpad == XboxOneDPad_E) ||
(data->report0x01.buttons.dpad == XboxOneDPad_NE) ||
(data->report0x01.buttons.dpad == XboxOneDPad_SE);
m_state.dpad_down = (data->report0x01.buttons.dpad == XboxOneDPad_S) ||
(data->report0x01.buttons.dpad == XboxOneDPad_SE) ||
(data->report0x01.buttons.dpad == XboxOneDPad_SW);
m_state.A = data->report0x01.buttons.B;
m_state.B = data->report0x01.buttons.A;
m_state.X = data->report0x01.buttons.Y;
m_state.Y = data->report0x01.buttons.X;
m_state.L = data->report0x01.buttons.LB;
m_state.ZL = data->report0x01.left_trigger > 0;
m_state.lstick_press = data->report0x01.buttons.lstick_press;
m_state.R = data->report0x01.buttons.RB;
m_state.ZR = data->report0x01.right_trigger > 0;
m_state.rstick_press = data->report0x01.buttons.rstick_press;
m_state.minus = data->report0x01.buttons.view;
m_state.plus = data->report0x01.buttons.menu;
//m_state.capture = ;
//m_state.home = ;
m_virtual->setState(&m_state);
}
void XboxOneController::handleInputReport0x02(const XboxOneReportData *data) {
std::memset(&m_state, 0, sizeof(m_state));
m_state.home = data->report0x02.guide;
m_virtual->setState(&m_state);
}
}

View file

@ -1,80 +0,0 @@
#include <cstring>
#include "gamepad/hdls.hpp"
#include "logger.hpp"
namespace mc::controller {
HdlsVirtualController::HdlsVirtualController() {
m_handle = INVALID_HANDLE;
std::memset(&m_device, 0, sizeof(HiddbgHdlsDeviceInfo));
m_device.deviceType = HidDeviceType_FullKey3;
m_device.npadInterfaceType = NpadInterfaceType_Bluetooth;
// Set official pro controller colours
m_device.singleColorBody = RGBA8_MAXALPHA(45, 45, 45);
m_device.singleColorButtons = RGBA8_MAXALPHA(230, 230, 230);
m_device.colorLeftGrip = RGBA8_MAXALPHA(70, 70, 70);
m_device.colorRightGrip = RGBA8_MAXALPHA(70, 70, 70);
std::memset(&m_state, 0, sizeof(HiddbgHdlsState));
m_state.batteryCharge = 4;
}
HdlsVirtualController::~HdlsVirtualController() {
//mc::log::Write("~HdlsVirtualController() called");
this->disconnect();
}
Result HdlsVirtualController::connect(void) {
//mc::log::Write("Connecting Hdls virtual device");
return hiddbgAttachHdlsVirtualDevice(&m_handle, &m_device);
}
Result HdlsVirtualController::disconnect(void) {
//mc::log::Write("Disconnecting Hdls virtual device");
return hiddbgDetachHdlsVirtualDevice(m_handle);
}
Result HdlsVirtualController::setState(const SwitchProGamepadState* state) {
if (m_handle != INVALID_HANDLE) {
m_state.buttons = 0;
m_state.buttons |= state->A ? KEY_A : 0;
m_state.buttons |= state->B ? KEY_B : 0;
m_state.buttons |= state->X ? KEY_X : 0;
m_state.buttons |= state->Y ? KEY_Y : 0;
m_state.buttons |= state->dpad_down ? KEY_DDOWN : 0;
m_state.buttons |= state->dpad_up ? KEY_DUP : 0;
m_state.buttons |= state->dpad_right ? KEY_DRIGHT : 0;
m_state.buttons |= state->dpad_left ? KEY_DLEFT : 0;
m_state.buttons |= state->L ? KEY_L : 0;
m_state.buttons |= state->ZL ? KEY_ZL : 0;
m_state.buttons |= state->lstick_press ? KEY_LSTICK : 0;
m_state.buttons |= state->R ? KEY_R : 0;
m_state.buttons |= state->ZR ? KEY_ZR : 0;
m_state.buttons |= state->rstick_press ? KEY_RSTICK : 0;
m_state.buttons |= state->minus ? KEY_MINUS : 0;
m_state.buttons |= state->plus ? KEY_PLUS : 0;
m_state.buttons |= state->capture ? KEY_CAPTURE : 0;
m_state.buttons |= state->home ? KEY_HOME : 0;
m_state.joysticks[JOYSTICK_LEFT].dx = state->left_stick.dx;
m_state.joysticks[JOYSTICK_LEFT].dy = state->left_stick.dy;
m_state.joysticks[JOYSTICK_RIGHT].dx = state->right_stick.dx;
m_state.joysticks[JOYSTICK_RIGHT].dy = state->right_stick.dy;
return hiddbgSetHdlsState(m_handle, &m_state);
}
//mc::log::Write("HdlsVirtualController::setState: handle is invalid");
return -1;
}
}

View file

@ -1,48 +0,0 @@
#include "gamepad/hidgamepad.hpp"
#include "gamepad/bluetoothinterface.hpp"
namespace mc::controller {
namespace {
const constexpr int default_deadzone_percent = 0.05;
}
HidGamepad::HidGamepad(HidInterfaceType iface) {
/* Assign HIDinterface */
switch (iface) {
case HidInterfaceType_Bluetooth:
m_btInterface = std::make_unique<BluetoothInterface>();
break;
case HidInterfaceType_Usb: // Not yet implemented
m_btInterface = nullptr;
break;
default:
fatalThrow(-1);
}
/* Assign virtual controller */
if (hosversionAtLeast(7, 0, 0)) {
m_virtual = std::make_unique<HdlsVirtualController>();
} else if (hosversionAtLeast(5, 0, 0)) {
m_virtual = std::make_unique<AbstractedPadVirtualController>();
} else {
fatalThrow(-1);
}
this->setInnerDeadzone(default_deadzone_percent);
this->setOuterDeadzone(default_deadzone_percent);
m_virtual->connect();
}
void HidGamepad::setInnerDeadzone(float percentage) {
m_innerDeadzone = JOYSTICK_MAX * percentage;
}
void HidGamepad::setOuterDeadzone(float percentage) {
m_outerDeadzone = JOYSTICK_MAX * (1.0 - percentage);
}
}

View file

@ -1,79 +0,0 @@
#include "log.hpp"
#include <ctype.h>
#include <switch.h>
namespace mc::log {
namespace {
Mutex logMutex;
const constexpr char *location = "sdmc:/missioncontrol-sysmodule.log";
}
void Write(const char *fmt, ...) {
mutexLock(&logMutex);
FILE *fp = std::fopen(location, "a");
va_list va;
va_start(va, fmt);
std::vfprintf(fp, fmt, va);
va_end(va);
std::fprintf(fp, "\n");
std::fclose(fp);
mutexUnlock(&logMutex);
}
void WriteData(void *data, size_t size) {
mutexLock(&logMutex);
FILE *fp = std::fopen(location, "a");
unsigned int i = 0;
while (i < size) {
// Print offset
std::fprintf(fp, " %04x", i);
std::fprintf(fp, " |");
// Print line of hex
unsigned int j;
for (j = 0; j < 16; ++j) {
if (i + j < size) {
std::fprintf(fp, " %02x", ((char *)data)[i+j]);
}
else {
break;
}
}
// Print separator
for (unsigned int k = 0; k < 16-j; ++k)
{
fprintf(fp, " ");
}
fprintf(fp, " | ");
// Print line of ascii
for (unsigned int j = 0; j < 16; ++j) {
if (i + j < size) {
char c = ((char *)data)[i+j];
std::fprintf(fp, "%c", isprint(c) ? c: 0x2e);
}
else {
break;
}
}
std::fprintf(fp, "\n");
i += 16;
}
std::fclose(fp);
mutexUnlock(&logMutex);
}
}

View file

@ -1,144 +0,0 @@
#include <switch.h>
#include "bluetooth/hid.hpp"
#include "log.hpp"
// Adjust size as needed.
#define INNER_HEAP_SIZE 0x40000
#ifdef __cplusplus
extern "C" {
#endif
u32 __nx_applet_type = AppletType_None;
size_t nx_inner_heap_size = INNER_HEAP_SIZE;
char nx_inner_heap[INNER_HEAP_SIZE];
void __libnx_initheap(void) {
void* addr = nx_inner_heap;
size_t size = nx_inner_heap_size;
// Newlib
extern char* fake_heap_start;
extern char* fake_heap_end;
fake_heap_start = (char*)addr;
fake_heap_end = (char*)addr + size;
}
void __attribute__((weak)) __appInit(void) {
Result rc;
rc = smInitialize();
if (R_FAILED(rc))
fatalThrow(MAKERESULT(Module_Libnx, LibnxError_InitFail_SM));
// Ensure system firmware version has been set before we start doing IPC that relies on it
if (hosversionGet() == 0) {
rc = setsysInitialize();
if (R_SUCCEEDED(rc)) {
SetSysFirmwareVersion fw;
rc = setsysGetFirmwareVersion(&fw);
if (R_SUCCEEDED(rc))
hosversionSet(MAKEHOSVERSION(fw.major, fw.minor, fw.micro));
setsysExit();
}
}
rc = fsInitialize();
if (R_FAILED(rc))
fatalThrow(MAKERESULT(Module_Libnx, LibnxError_InitFail_FS));
fsdevMountSdmc();
rc = pscmInitialize();
if R_FAILED(rc)
fatalThrow(rc);
rc = btdrvInitialize();
if (R_FAILED(rc))
fatalThrow(rc);
rc = btmInitialize();
if (R_FAILED(rc))
fatalThrow(rc);
rc = hiddbgInitialize();
if R_FAILED(rc)
fatalThrow(rc);
}
void __attribute__((weak)) userAppExit(void);
void __attribute__((weak)) __appExit(void) {
hiddbgExit();
btmExit();
btdrvExit();
pscmExit();
fsdevUnmountAll();
fsExit();
smExit();
}
#ifdef __cplusplus
}
#endif
int main(int argc, char* argv[]) {
Result rc;
PscPmModule pmModule = {};
PscPmState pmState;
uint32_t pmFlags;
/* Init power management */
PscPmModuleId pmModuleId = static_cast<PscPmModuleId>(0xbd);
const uint16_t deps[] = { PscPmModuleId_Bluetooth }; //PscPmModuleId_Bluetooth, PscPmModuleId_Btm, PscPmModuleId_Hid ??
rc = pscmGetPmModule(&pmModule, pmModuleId, deps, sizeof(deps) / sizeof(u16), true);
if (R_FAILED(rc))
fatalThrow(rc);
/* Init bluetooth HID */
mc::bluetooth::hid::Initialise();
mc::log::Write("HID initialised");
while (!mc::bluetooth::hid::exitFlag) {
/* Check power management events */
if (R_SUCCEEDED(eventWait(&pmModule.event, UINT64_MAX))) {
rc = pscPmModuleGetRequest(&pmModule, &pmState, &pmFlags);
if (R_SUCCEEDED(rc)) {
switch(pmState) {
case PscPmState_Awake:
mc::bluetooth::hid::OnWake();
break;
case PscPmState_ReadyAwaken:
mc::bluetooth::hid::PrepareForWake();
break;
case PscPmState_ReadySleep:
mc::bluetooth::hid::PrepareForSleep();
break;
case PscPmState_ReadyShutdown:
case PscPmState_ReadyAwakenCritical:
case PscPmState_ReadySleepCritical:
default:
break;
}
rc = pscPmModuleAcknowledge(&pmModule, pmState);
}
}
}
/* Cleanup bluetooth HID */
mc::bluetooth::hid::Cleanup();
/* Cleanup power management */
eventClose(&pmModule.event);
pscPmModuleFinalize(&pmModule);
pscPmModuleClose(&pmModule);
return 0;
}

View file

@ -1,172 +0,0 @@
{
"name": "bdsm",
"title_id": "0x010000000000b100",
"title_id_range_min": "0x010000000000b100",
"title_id_range_max": "0x010000000000b100",
"main_thread_stack_size": "0x00004000",
"main_thread_priority": 18,
"default_cpu_id": 3,
"process_category": 0,
"is_retail": true,
"pool_partition": 2,
"is_64_bit": true,
"address_space_type": 1,
"filesystem_access": {
"permissions": "0xffffffffffffffff"
},
"service_access": ["*"],
"service_host": ["*"],
"kernel_capabilities": [{
"type": "kernel_flags",
"value": {
"highest_thread_priority": 63,
"lowest_thread_priority": 12,
"lowest_cpu_id": 3,
"highest_cpu_id": 3
}
}, {
"type": "syscalls",
"value": {
"svcUnknown": "0x00",
"svcSetHeapSize": "0x01",
"svcSetMemoryPermission": "0x02",
"svcSetMemoryAttribute": "0x03",
"svcMapMemory": "0x04",
"svcUnmapMemory": "0x05",
"svcQueryMemory": "0x06",
"svcExitProcess": "0x07",
"svcCreateThread": "0x08",
"svcStartThread": "0x09",
"svcExitThread": "0x0a",
"svcSleepThread": "0x0b",
"svcGetThreadPriority": "0x0c",
"svcSetThreadPriority": "0x0d",
"svcGetThreadCoreMask": "0x0e",
"svcSetThreadCoreMask": "0x0f",
"svcGetCurrentProcessorNumber": "0x10",
"svcSignalEvent": "0x11",
"svcClearEvent": "0x12",
"svcMapSharedMemory": "0x13",
"svcUnmapSharedMemory": "0x14",
"svcCreateTransferMemory": "0x15",
"svcCloseHandle": "0x16",
"svcResetSignal": "0x17",
"svcWaitSynchronization": "0x18",
"svcCancelSynchronization": "0x19",
"svcArbitrateLock": "0x1a",
"svcArbitrateUnlock": "0x1b",
"svcWaitProcessWideKeyAtomic": "0x1c",
"svcSignalProcessWideKey": "0x1d",
"svcGetSystemTick": "0x1e",
"svcConnectToNamedPort": "0x1f",
"svcSendSyncRequestLight": "0x20",
"svcSendSyncRequest": "0x21",
"svcSendSyncRequestWithUserBuffer": "0x22",
"svcSendAsyncRequestWithUserBuffer": "0x23",
"svcGetProcessId": "0x24",
"svcGetThreadId": "0x25",
"svcBreak": "0x26",
"svcOutputDebugString": "0x27",
"svcReturnFromException": "0x28",
"svcGetInfo": "0x29",
"svcFlushEntireDataCache": "0x2a",
"svcFlushDataCache": "0x2b",
"svcMapPhysicalMemory": "0x2c",
"svcUnmapPhysicalMemory": "0x2d",
"svcGetFutureThreadInfo": "0x2e",
"svcGetLastThreadInfo": "0x2f",
"svcGetResourceLimitLimitValue": "0x30",
"svcGetResourceLimitCurrentValue": "0x31",
"svcSetThreadActivity": "0x32",
"svcGetThreadContext3": "0x33",
"svcWaitForAddress": "0x34",
"svcSignalToAddress": "0x35",
"svcUnknown": "0x36",
"svcUnknown": "0x37",
"svcUnknown": "0x38",
"svcUnknown": "0x39",
"svcUnknown": "0x3a",
"svcUnknown": "0x3b",
"svcDumpInfo": "0x3c",
"svcDumpInfoNew": "0x3d",
"svcUnknown": "0x3e",
"svcUnknown": "0x3f",
"svcCreateSession": "0x40",
"svcAcceptSession": "0x41",
"svcReplyAndReceiveLight": "0x42",
"svcReplyAndReceive": "0x43",
"svcReplyAndReceiveWithUserBuffer": "0x44",
"svcCreateEvent": "0x45",
"svcUnknown": "0x46",
"svcUnknown": "0x47",
"svcMapPhysicalMemoryUnsafe": "0x48",
"svcUnmapPhysicalMemoryUnsafe": "0x49",
"svcSetUnsafeLimit": "0x4a",
"svcCreateCodeMemory": "0x4b",
"svcControlCodeMemory": "0x4c",
"svcSleepSystem": "0x4d",
"svcReadWriteRegister": "0x4e",
"svcSetProcessActivity": "0x4f",
"svcCreateSharedMemory": "0x50",
"svcMapTransferMemory": "0x51",
"svcUnmapTransferMemory": "0x52",
"svcCreateInterruptEvent": "0x53",
"svcQueryPhysicalAddress": "0x54",
"svcQueryIoMapping": "0x55",
"svcCreateDeviceAddressSpace": "0x56",
"svcAttachDeviceAddressSpace": "0x57",
"svcDetachDeviceAddressSpace": "0x58",
"svcMapDeviceAddressSpaceByForce": "0x59",
"svcMapDeviceAddressSpaceAligned": "0x5a",
"svcMapDeviceAddressSpace": "0x5b",
"svcUnmapDeviceAddressSpace": "0x5c",
"svcInvalidateProcessDataCache": "0x5d",
"svcStoreProcessDataCache": "0x5e",
"svcFlushProcessDataCache": "0x5f",
"svcDebugActiveProcess": "0x60",
"svcBreakDebugProcess": "0x61",
"svcTerminateDebugProcess": "0x62",
"svcGetDebugEvent": "0x63",
"svcContinueDebugEvent": "0x64",
"svcGetProcessList": "0x65",
"svcGetThreadList": "0x66",
"svcGetDebugThreadContext": "0x67",
"svcSetDebugThreadContext": "0x68",
"svcQueryDebugProcessMemory": "0x69",
"svcReadDebugProcessMemory": "0x6a",
"svcWriteDebugProcessMemory": "0x6b",
"svcSetHardwareBreakPoint": "0x6c",
"svcGetDebugThreadParam": "0x6d",
"svcUnknown": "0x6e",
"svcGetSystemInfo": "0x6f",
"svcCreatePort": "0x70",
"svcManageNamedPort": "0x71",
"svcConnectToPort": "0x72",
"svcSetProcessMemoryPermission": "0x73",
"svcMapProcessMemory": "0x74",
"svcUnmapProcessMemory": "0x75",
"svcQueryProcessMemory": "0x76",
"svcMapProcessCodeMemory": "0x77",
"svcUnmapProcessCodeMemory": "0x78",
"svcCreateProcess": "0x79",
"svcStartProcess": "0x7a",
"svcTerminateProcess": "0x7b",
"svcGetProcessInfo": "0x7c",
"svcCreateResourceLimit": "0x7d",
"svcSetResourceLimitLimitValue": "0x7e",
"svcCallSecureMonitor": "0x7f"
}
}, {
"type": "min_kernel_version",
"value": "0x0030"
}, {
"type": "handle_table_size",
"value": 1023
}, {
"type": "debug_flags",
"value": {
"allow_debug": false,
"force_debug": true
}
}]
}