From b9fdd5070bdbc68628450a39593b1ba85fa904c1 Mon Sep 17 00:00:00 2001 From: Flyinghead Date: Fri, 20 Dec 2024 20:02:58 +0100 Subject: [PATCH] dreamconn: detect dreamconn+ with VID/PID. Send maple data as text. Create DreamConn gamepad when detected. Send/receive maple data in ascii dump form. Simplify maple device creation. Issue #1305 --- core/hw/maple/maple_cfg.cpp | 5 +- core/hw/maple/maple_devs.cpp | 95 +++++++++++++++++-------- core/hw/maple/maple_devs.h | 4 +- core/hw/maple/maple_helper.cpp | 9 --- core/hw/maple/maple_helper.h | 15 ---- core/hw/maple/maple_if.cpp | 12 +++- core/sdl/dreamconn.cpp | 123 +++++++++++++++++++++++---------- core/sdl/dreamconn.h | 43 +++++++++++- core/sdl/sdl.cpp | 16 ++--- core/sdl/sdl_gamepad.h | 2 - 10 files changed, 209 insertions(+), 115 deletions(-) diff --git a/core/hw/maple/maple_cfg.cpp b/core/hw/maple/maple_cfg.cpp index 4cc0f51ab..72245b9ec 100644 --- a/core/hw/maple/maple_cfg.cpp +++ b/core/hw/maple/maple_cfg.cpp @@ -215,10 +215,7 @@ static void mcfg_Create(MapleDeviceType type, u32 bus, u32 port, s32 player_num { delete MapleDevices[bus][port]; maple_device* dev = maple_Create(type); - dev->Setup(maple_GetAddress(bus, port), player_num); - dev->config = new MapleConfigMap(dev); - dev->OnSetup(); - MapleDevices[bus][port] = dev; + dev->Setup(bus, port, player_num); } static void createNaomiDevices() diff --git a/core/hw/maple/maple_devs.cpp b/core/hw/maple/maple_devs.cpp index b0cfcf84b..ed3f210bc 100755 --- a/core/hw/maple/maple_devs.cpp +++ b/core/hw/maple/maple_devs.cpp @@ -32,15 +32,19 @@ const char* maple_densha_controller_name = "TAITO 001 Controller"; const char* maple_sega_brand = "Produced By or Under License From SEGA ENTERPRISES,LTD."; //fill in the info -void maple_device::Setup(u32 port, int playerNum) +void maple_device::Setup(u32 bus, u32 port, int playerNum) { - maple_port = port; - bus_port = maple_GetPort(port); - bus_id = maple_GetBusId(port); + maple_port = (bus << 6) | (1 << port); + bus_port = port; + bus_id = bus; logical_port[0] = 'A' + bus_id; logical_port[1] = bus_port == 5 ? 'x' : '1' + bus_port; logical_port[2] = 0; player_num = playerNum == -1 ? bus_id : playerNum; + + config = new MapleConfigMap(this); + OnSetup(); + MapleDevices[bus][port] = this; } maple_device::~maple_device() { @@ -683,7 +687,7 @@ struct maple_sega_vmu: maple_base case MFID_2_LCD: { DEBUG_LOG(MAPLE, "VMU %s LCD write", logical_port); - r32(); + r32(); // PT, phase, block# rptr(lcd_data,192); u8 white=0xff,black=0x00; @@ -1719,7 +1723,7 @@ struct RFIDReaderWriter : maple_base u32 resp = Dma(command, &buffer_in[1], buffer_in_len - 4, &buffer_out[1], outlen); if (reci & 0x20) - reci |= maple_GetAttachedDevices(maple_GetBusId(reci)); + reci |= maple_GetAttachedDevices(bus_id); verify(u8(outlen / 4) * 4 == outlen); buffer_out[0] = (resp << 0 ) | (reci << 8) | (send << 16) | ((outlen / 4) << 24); @@ -2107,63 +2111,94 @@ maple_device* maple_Create(MapleDeviceType type) struct DreamConnVmu : public maple_sega_vmu { - DreamConn& dreamconn; + std::shared_ptr dreamconn; - DreamConnVmu(DreamConn& dreamconn) : dreamconn(dreamconn) { + DreamConnVmu(std::shared_ptr dreamconn) : dreamconn(dreamconn) { } u32 dma(u32 cmd) override { if (cmd == MDCF_BlockWrite && *(u32 *)dma_buffer_in == MFID_2_LCD) + { // send the raw maple msg - dreamconn.send(dma_buffer_in - 4, dma_count_in + 4); + const MapleMsg *msg = reinterpret_cast(dma_buffer_in - 4); + dreamconn->send(*msg); + } return maple_sega_vmu::dma(cmd); } + + void copy(maple_sega_vmu *other) + { + memcpy(flash_data, other->flash_data, sizeof(flash_data)); + memcpy(lcd_data, other->lcd_data, sizeof(lcd_data)); + memcpy(lcd_data_decoded, other->lcd_data_decoded, sizeof(lcd_data_decoded)); + fullSaveNeeded = other->fullSaveNeeded; + } + + void updateScreen() + { + MapleMsg msg; + msg.command = MDCF_BlockWrite; + msg.destAP = maple_port; + msg.originAP = bus_id << 6; + msg.size = 2 + sizeof(lcd_data) / 4; + *(u32 *)&msg.data[0] = MFID_2_LCD; + *(u32 *)&msg.data[4] = 0; // PT, phase, block# + memcpy(&msg.data[8], lcd_data, sizeof(lcd_data)); + dreamconn->send(msg); + } }; struct DreamConnPurupuru : public maple_sega_purupuru { - DreamConn& dreamconn; + std::shared_ptr dreamconn; - DreamConnPurupuru(DreamConn& dreamconn) : dreamconn(dreamconn) { + DreamConnPurupuru(std::shared_ptr dreamconn) : dreamconn(dreamconn) { } u32 dma(u32 cmd) override { + const MapleMsg *msg = reinterpret_cast(dma_buffer_in - 4); switch (cmd) { case MDCF_BlockWrite: - dreamconn.send(dma_buffer_in - 4, dma_count_in + 4); + dreamconn->send(*msg); break; - case MDCF_SetCondition: - dreamconn.send(dma_buffer_in - 4, dma_count_in + 4); + dreamconn->send(*msg); break; } return maple_sega_purupuru::dma(cmd); } }; -void createDreamConnDevices(DreamConn& dreamconn) +void createDreamConnDevices(std::shared_ptr dreamconn, bool gameStart) { - const int bus = dreamconn.getBus(); - if (dreamconn.hasVmu() && dynamic_cast(MapleDevices[bus][0]) == nullptr) + const int bus = dreamconn->getBus(); + if (dreamconn->hasVmu()) { - delete MapleDevices[bus][0]; - DreamConnVmu *dev = new DreamConnVmu(dreamconn); - dev->Setup((bus << 6) | 1); - dev->config = new MapleConfigMap(dev); - dev->OnSetup(); - MapleDevices[bus][0] = dev; + maple_device *dev = MapleDevices[bus][0]; + if (gameStart || (dev != nullptr && dev->get_device_type() == MDT_SegaVMU)) + { + DreamConnVmu *vmu = new DreamConnVmu(dreamconn); + vmu->Setup(bus, 0); + if (!gameStart) { + // if loading a state, copy data from the regular vmu and send a screen update + vmu->copy(static_cast(dev)); + vmu->updateScreen(); + } + delete dev; + } } - if (dreamconn.hasRumble() && dynamic_cast(MapleDevices[bus][1]) == nullptr) + if (dreamconn->hasRumble()) { - delete MapleDevices[bus][1]; - DreamConnPurupuru *dev = new DreamConnPurupuru(dreamconn); - dev->Setup((bus << 6) | 2); - dev->config = new MapleConfigMap(dev); - dev->OnSetup(); - MapleDevices[bus][1] = dev; + maple_device *dev = MapleDevices[bus][1]; + if (gameStart || (dev != nullptr && dev->get_device_type() == MDT_PurupuruPack)) + { + delete dev; + DreamConnPurupuru *rumble = new DreamConnPurupuru(dreamconn); + rumble->Setup(bus, 1); + } } } diff --git a/core/hw/maple/maple_devs.h b/core/hw/maple/maple_devs.h index 7f97e5af4..89f1e5836 100755 --- a/core/hw/maple/maple_devs.h +++ b/core/hw/maple/maple_devs.h @@ -131,7 +131,7 @@ struct maple_device MapleConfigMap* config; //fill in the info - void Setup(u32 port, int playerNum = -1); + void Setup(u32 bus, u32 port = 5, int playerNum = -1); virtual void OnSetup() {}; virtual ~maple_device(); @@ -246,7 +246,7 @@ struct maple_base: maple_device u32 resp = Dma(command, &buffer_in[1], buffer_in_len - 4, &buffer_out[1], outlen); if (reci & 0x20) - reci |= maple_GetAttachedDevices(maple_GetBusId(reci)); + reci |= maple_GetAttachedDevices(bus_id); verify(u8(outlen / 4) * 4 == outlen); buffer_out[0] = (resp << 0 ) | (send << 8) | (reci << 16) | ((outlen / 4) << 24); diff --git a/core/hw/maple/maple_helper.cpp b/core/hw/maple/maple_helper.cpp index 03c509103..6e683d972 100644 --- a/core/hw/maple/maple_helper.cpp +++ b/core/hw/maple/maple_helper.cpp @@ -1,15 +1,6 @@ #include "maple_helper.h" #include "maple_if.h" -u32 maple_GetPort(u32 addr) -{ - for (int i=0;i<6;i++) - { - if ((1<> 6; -} - -u32 maple_GetPort(u32 addr); u32 maple_GetAttachedDevices(u32 bus); - -//device : 0 .. 4 -> subdevice , 5 -> main device :) -static inline u32 maple_GetAddress(u32 bus, u32 port) -{ - u32 rv = bus << 6; - rv |= 1 << port; - - return rv; -} diff --git a/core/hw/maple/maple_if.cpp b/core/hw/maple/maple_if.cpp index 168edeb35..e446057a9 100644 --- a/core/hw/maple/maple_if.cpp +++ b/core/hw/maple/maple_if.cpp @@ -124,6 +124,14 @@ static void maple_SB_MDSTAR_Write(u32 addr, u32 data) } #endif +static u32 getPort(u32 addr) +{ + for (int i = 0; i < 6; i++) + if ((1 << i) & addr) + return i; + return 5; +} + static void maple_DoDma() { verify(SB_MDEN & 1); @@ -202,8 +210,8 @@ static void maple_DoDma() //Number of additional words in frame u32 inlen = (frame_header >> 24) & 0xFF; - u32 port = maple_GetPort(reci); - u32 bus = maple_GetBusId(reci); + u32 port = getPort(reci); + u32 bus = reci >> 6; if (MapleDevices[bus][5] && MapleDevices[bus][port]) { diff --git a/core/sdl/dreamconn.cpp b/core/sdl/dreamconn.cpp index 1747f2d64..6d944a462 100644 --- a/core/sdl/dreamconn.cpp +++ b/core/sdl/dreamconn.cpp @@ -20,41 +20,42 @@ #if defined(_WIN32) && !defined(TARGET_UWP) #include "hw/maple/maple_devs.h" +#include +#include +#include -void createDreamConnDevices(DreamConn& dreamconn); +void createDreamConnDevices(std::shared_ptr dreamconn, bool gameStart); -struct MapleMsg +bool MapleMsg::send(sock_t sock) const { - u8 command; - u8 destAP; - u8 originAP; - u8 size; - u8 data[1024]; + std::ostringstream out; + out.fill('0'); + out << std::hex << std::uppercase + << std::setw(2) << (u32)command << " " + << std::setw(2) << (u32)destAP << " " + << std::setw(2) << (u32)originAP << " " + << std::setw(2) << (u32)size; + const u32 sz = getDataSize(); + for (u32 i = 0; i < sz; i++) + out << " " << std::setw(2) << (u32)data[i]; + out << "\r\n"; + std::string s = out.str(); + return ::send(sock, s.c_str(), s.length(), 0) == (int)s.length(); +} - u32 getDataSize() const { - return size * 4; - } - - template - void setData(const T& p) { - memcpy(data, &p, sizeof(T)); - this->size = (sizeof(T) + 3) / 4; - } - - bool send(sock_t sock) { - u32 sz = getDataSize() + 4; - return ::send(sock, (const char *)this, sz, 0) == sz; - } - bool receive(sock_t sock) - { - if (::recv(sock, (char *)this, 4, 0) != 4) - return false; - if (getDataSize() == 0) - return true; - return ::recv(sock, (char *)data, getDataSize(), 0) == getDataSize(); - } -}; -static_assert(sizeof(MapleMsg) == 1028); +bool MapleMsg::receive(sock_t sock) +{ + std::string str(11, ' '); + if (::recv(sock, (char *)str.data(), str.length(), 0) != (int)str.length()) + return false; + sscanf(str.c_str(), "%hhx %hhx %hhx %hhx", &command, &destAP, &originAP, &size); + str = std::string(getDataSize() * 3 + 2, ' '); + if (::recv(sock, (char *)str.data(), str.length(), 0) != (int)str.length()) + return false; + for (unsigned i = 0; i < getDataSize(); i++) + sscanf(&str[i * 3 + 1], "%hhx", &data[i]); + return true; +} void DreamConn::connect() { @@ -91,13 +92,10 @@ void DreamConn::connect() } expansionDevs = msg.originAP & 0x1f; NOTICE_LOG(INPUT, "Connected to DreamConn[%d]: VMU:%d, Rumble Pack:%d", bus, hasVmu(), hasRumble()); - - EventManager::listen(Event::Resume, handleEvent, this); } void DreamConn::disconnect() { - EventManager::unlisten(Event::Resume, handleEvent, this); if (VALID(sock)) { NOTICE_LOG(INPUT, "Disconnected from DreamConn[%d]", bus); closesocket(sock); @@ -105,16 +103,54 @@ void DreamConn::disconnect() sock = INVALID_SOCKET; } -bool DreamConn::send(const u8* data, int size) +bool DreamConn::send(const MapleMsg& msg) { if (VALID(sock)) - return ::send(sock, (const char *)data, size, 0) == size; + return msg.send(sock); else return false; } -void DreamConn::handleEvent(Event event, void *arg) { - createDreamConnDevices(*static_cast(arg)); +bool DreamConnGamepad::isDreamConn(int deviceIndex) +{ + char guid_str[33] {}; + SDL_JoystickGetGUIDString(SDL_JoystickGetDeviceGUID(deviceIndex), guid_str, sizeof(guid_str)); + NOTICE_LOG(INPUT, "GUID: %s VID:%c%c%c%c PID:%c%c%c%c", guid_str, + guid_str[10], guid_str[11], guid_str[8], guid_str[9], + guid_str[18], guid_str[19], guid_str[16], guid_str[17]); + // DreamConn VID:4457 PID:4443 + return memcmp("5744000043440000", guid_str + 8, 16) == 0; +} + +DreamConnGamepad::DreamConnGamepad(int maple_port, int joystick_idx, SDL_Joystick* sdl_joystick) + : SDLGamepad(maple_port, joystick_idx, sdl_joystick) +{ + EventManager::listen(Event::Start, handleEvent, this); + EventManager::listen(Event::LoadState, handleEvent, this); +} + +DreamConnGamepad::~DreamConnGamepad() { + EventManager::unlisten(Event::Start, handleEvent, this); + EventManager::unlisten(Event::LoadState, handleEvent, this); +} + +void DreamConnGamepad::set_maple_port(int port) +{ + if (port < 0 || port >= 4) { + dreamconn.reset(); + } + else if (dreamconn == nullptr || dreamconn->getBus() != port) { + dreamconn.reset(); + dreamconn = std::make_shared(port); + } + SDLGamepad::set_maple_port(port); +} + +void DreamConnGamepad::handleEvent(Event event, void *arg) +{ + DreamConnGamepad *gamepad = static_cast(arg); + if (gamepad->dreamconn != nullptr) + createDreamConnDevices(gamepad->dreamconn, event == Event::Start); } #else @@ -124,4 +160,15 @@ void DreamConn::connect() { void DreamConn::disconnect() { } +bool DreamConnGamepad::isDreamConn(int deviceIndex) { + return false; +} +DreamConnGamepad::DreamConnGamepad(int maple_port, int joystick_idx, SDL_Joystick* sdl_joystick) + : SDLGamepad(maple_port, joystick_idx, sdl_joystick) { +} +DreamConnGamepad::~DreamConnGamepad() { +} +void DreamConnGamepad::set_maple_port(int port) { + SDLGamepad::set_maple_port(port); +} #endif diff --git a/core/sdl/dreamconn.h b/core/sdl/dreamconn.h index 60bd56cf8..f74e88d4d 100644 --- a/core/sdl/dreamconn.h +++ b/core/sdl/dreamconn.h @@ -20,8 +20,31 @@ #include "types.h" #include "network/net_platform.h" #include "emulator.h" +#include "sdl_gamepad.h" + +struct MapleMsg +{ + u8 command; + u8 destAP; + u8 originAP; + u8 size; + u8 data[1024]; + + u32 getDataSize() const { + return size * 4; + } + + template + void setData(const T& p) { + memcpy(data, &p, sizeof(T)); + this->size = (sizeof(T) + 3) / 4; + } + + bool send(sock_t sock) const; + bool receive(sock_t sock); +}; +static_assert(sizeof(MapleMsg) == 1028); -// TODO Need a way to detect DreamConn+ controllers class DreamConn { const int bus; @@ -37,7 +60,7 @@ public: disconnect(); } - bool send(const u8* data, int size); + bool send(const MapleMsg& msg); int getBus() const { return bus; @@ -52,5 +75,19 @@ public: private: void connect(); void disconnect(); - static void handleEvent(Event event, void *arg); +}; + +class DreamConnGamepad : public SDLGamepad +{ +public: + DreamConnGamepad(int maple_port, int joystick_idx, SDL_Joystick* sdl_joystick); + ~DreamConnGamepad(); + + void set_maple_port(int port) override; + static bool isDreamConn(int deviceIndex); + +private: + static void handleEvent(Event event, void *arg); + + std::shared_ptr dreamconn; }; diff --git a/core/sdl/sdl.cpp b/core/sdl/sdl.cpp index 7f77e452f..a93c19e3c 100644 --- a/core/sdl/sdl.cpp +++ b/core/sdl/sdl.cpp @@ -39,6 +39,7 @@ static u32 windowFlags; #define WINDOW_WIDTH 640 #define WINDOW_HEIGHT 480 +std::map> SDLGamepad::sdl_gamepads; static std::unordered_map> sdl_mice; static std::shared_ptr sdl_keyboard; static bool window_fullscreen; @@ -49,7 +50,6 @@ static bool mouseCaptured; static std::string clipboardText; static std::string barcode; static u64 lastBarcodeTime; -static std::unique_ptr dreamconns[4]; static KeyboardLayout detectKeyboardLayout(); static bool handleBarcodeScanner(const SDL_Event& event); @@ -82,7 +82,11 @@ static void sdl_open_joystick(int index) #ifdef __SWITCH__ std::shared_ptr gamepad = std::make_shared(index < MAPLE_PORTS ? index : -1, index, pJoystick); #else - std::shared_ptr gamepad = std::make_shared(index < MAPLE_PORTS ? index : -1, index, pJoystick); + std::shared_ptr gamepad; + if (DreamConnGamepad::isDreamConn(index)) + gamepad = std::make_shared(index < MAPLE_PORTS ? index : -1, index, pJoystick); + else + gamepad = std::make_shared(index < MAPLE_PORTS ? index : -1, index, pJoystick); #endif SDLGamepad::AddSDLGamepad(gamepad); } catch (const FlycastException& e) { @@ -262,18 +266,10 @@ void input_sdl_init() if (settings.input.keyboardLangId == KeyboardLayout::US) settings.input.keyboardLangId = detectKeyboardLayout(); barcode.clear(); - for (unsigned i = 0; i < std::size(dreamconns); i++) - { - std::string key = "DreamConn" + std::to_string(i); - if (cfgLoadBool("input", key.c_str(), false)) - dreamconns[i] = std::make_unique(i); - } } void input_sdl_quit() { - for (auto& dc : dreamconns) - dc.reset(); EventManager::unlisten(Event::Terminate, emuEventCallback); EventManager::unlisten(Event::Pause, emuEventCallback); EventManager::unlisten(Event::Resume, emuEventCallback); diff --git a/core/sdl/sdl_gamepad.h b/core/sdl/sdl_gamepad.h index 76a0d47a0..46bbd0b45 100644 --- a/core/sdl/sdl_gamepad.h +++ b/core/sdl/sdl_gamepad.h @@ -676,8 +676,6 @@ private: int damperEffectId = -1; }; -std::map> SDLGamepad::sdl_gamepads; - class SDLMouse : public Mouse { public: