Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/deps/DreamPicoPort-API
66 changes: 38 additions & 28 deletions core/hw/maple/maple_devs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2133,12 +2133,12 @@ struct DreamLinkVmu : public maple_sega_vmu
static u64 lastNotifyTime;
static u64 lastErrorNotifyTime;

DreamLinkVmu(std::shared_ptr<DreamLink> dreamlink) :
DreamLinkVmu(std::shared_ptr<DreamLink> dreamlink, bool hasStorage) :
dreamlink(dreamlink),
writeThread([this](){writeEntrypoint();})
{
// Initialize useRealVmuMemory with our config setting
useRealVmuMemory = config::UsePhysicalVmuMemory;
useRealVmuMemory = config::UsePhysicalVmuMemory && hasStorage;
}

virtual ~DreamLinkVmu() {
Expand Down Expand Up @@ -2578,7 +2578,38 @@ void createDreamLinkDevices(std::shared_ptr<DreamLink> dreamlink, bool gameStart
{
std::shared_ptr<maple_device> dev = MapleDevices[bus][i];

if ((dreamlink->getFunctionCode(i + 1) & MFID_1_Storage))
const u32 fnCode = dreamlink->getFunctionCode(i);
const bool isStorage = ((fnCode & MFID_1_Storage) != 0);
const bool isScreen = ((fnCode & MFID_2_LCD) != 0);
const bool isVibration = ((fnCode & MFID_8_Vibration) != 0);

if (i == 1 && isVibration)
{
bool rumbleFound = false;
std::shared_ptr<DreamLinkPurupuru> rumble;
for (const std::shared_ptr<DreamLinkPurupuru>& purupuru : dreamLinkPurupurus)
{
if (purupuru->dreamlink.get() == dreamlink.get())
{
rumbleFound = true;
rumble = purupuru;
break;
}
}

if (gameStart || stateLoaded || !rumbleFound)
{
if (!rumble)
{
rumble = std::make_shared<DreamLinkPurupuru>(dreamlink);
}

rumble->Setup(bus, i);

if (!rumbleFound) dreamLinkPurupurus.push_back(rumble);
}
}
else if (isStorage || isScreen)
{
bool vmuFound = false;
std::shared_ptr<DreamLinkVmu> vmu;
Expand All @@ -2596,13 +2627,13 @@ void createDreamLinkDevices(std::shared_ptr<DreamLink> dreamlink, bool gameStart
{
if (!vmu)
{
vmu = std::make_shared<DreamLinkVmu>(dreamlink);
vmu = std::make_shared<DreamLinkVmu>(dreamlink, isStorage);
}

if (gameStart)
{
// Update useRealVmuMemory in case config changed
vmu->useRealVmuMemory = config::UsePhysicalVmuMemory;
vmu->useRealVmuMemory = config::UsePhysicalVmuMemory && isStorage;
}
else if (stateLoaded)
{
Expand All @@ -2628,32 +2659,11 @@ void createDreamLinkDevices(std::shared_ptr<DreamLink> dreamlink, bool gameStart
if (!vmuFound) {
dreamLinkVmus[i].push_back(vmu);
}
}
}
else if (i == 1 && ((dreamlink->getFunctionCode(i + 1) & MFID_8_Vibration)))
{
bool rumbleFound = false;
std::shared_ptr<DreamLinkPurupuru> rumble;
for (const std::shared_ptr<DreamLinkPurupuru>& purupuru : dreamLinkPurupurus)
{
if (purupuru->dreamlink.get() == dreamlink.get())
{
rumbleFound = true;
rumble = purupuru;
break;
}
}

if (gameStart || stateLoaded || !rumbleFound)
{
if (!rumble)
if (gameStart && vmu->useRealVmuMemory)
{
rumble = std::make_shared<DreamLinkPurupuru>(dreamlink);
dreamlink->sendGameId(i, settings.content.gameId);
}

rumble->Setup(bus, i);

if (!rumbleFound) dreamLinkPurupurus.push_back(rumble);
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions core/sdl/dreamconn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,18 +130,18 @@ class DreamConnImp : public DreamConn
}

u32 getFunctionCode(int forPort) const override {
MapleDeviceType deviceType = expansionDevs.at(forPort - 1);
MapleDeviceType deviceType = expansionDevs.at(forPort);
if (deviceType == MDT_SegaVMU) {
return 0x0E000000;
return MFID_2_LCD | MFID_3_Clock; // storage not supported
}
else if (deviceType == MDT_PurupuruPack) {
return 0x00010000;
return MFID_8_Vibration;
}
return 0;
}

std::array<u32, 3> getFunctionDefinitions(int forPort) const override {
MapleDeviceType deviceType = expansionDevs.at(forPort - 1);
MapleDeviceType deviceType = expansionDevs.at(forPort);
if (deviceType == MDT_SegaVMU)
// For clock, LCD, storage
return std::array<u32, 3>{0x403f7e7e, 0x00100500, 0x00410f00};
Expand Down
9 changes: 6 additions & 3 deletions core/sdl/dreamlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
#ifdef USE_DREAMLINK_DEVICES

// This file contains abstraction layer for access to different kinds of remote peripherals.
// This includes both real Dreamcast controllers, VMUs, rumble packs etc. but also emulated VMUs.
// This includes both real Dreamcast controllers, VMUs, jump packs etc. but also emulated VMUs.

#include "types.h"
#include "emulator.h"
Expand Down Expand Up @@ -95,11 +95,11 @@ class DreamLink : public std::enable_shared_from_this<DreamLink>
//! When called, do teardown stuff like reset screen
virtual inline void gameTermination() {}

//! @param[in] forPort The port number to get the function code of (1 or 2)
//! @param[in] forPort The port number to get the function code of
//! @return the device type for the given port
virtual u32 getFunctionCode(int forPort) const = 0;

//! @param[in] forPort The port number to get the function definitions of (1 or 2)
//! @param[in] forPort The port number to get the function definitions of
//! @return the 3 function definitions for the supported function codes
virtual std::array<u32, 3> getFunctionDefinitions(int forPort) const = 0;

Expand Down Expand Up @@ -154,6 +154,9 @@ class DreamLink : public std::enable_shared_from_this<DreamLink>

//! Disconnect from the hardware controller
virtual void disconnect() = 0;

//! Sends the current game id to a DreamLink backed expansion device if supported
virtual void sendGameId(int expansion, const std::string& gameId) {}
};

class DreamLinkGamepad : public SDLGamepad
Expand Down
42 changes: 38 additions & 4 deletions core/sdl/dreampicoport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1117,6 +1117,27 @@ class DreamPicoPortImp : public DreamPicoPort
return dpp_comms->send(txMsg, rxMsg, timeout_ms);
}

void sendGameId(int expansion, const std::string& gameId) override {
if (!dpp_comms || hw_info.hardware_bus < 0)
return;

if (gameId.empty() || expansion < 0 || expansion > 1)
return;

MapleMsg msg{};
msg.command = 33;
msg.destAP = (hw_info.hardware_bus << 6) | (1u << expansion);
msg.originAP = hw_info.hardware_bus << 6;
msg.setWord(MFID_1_Storage, 0);

const size_t idSize = 12;
const size_t copyLength = std::min(gameId.size(), idSize);
memcpy(&msg.data[4], gameId.data(), copyLength);
msg.size = 4;

dpp_comms->send(msg, timeout_ms);
}

void gameTermination() override {
// Need a short delay to wait for last screen draw to complete
std::this_thread::sleep_for(std::chrono::milliseconds(10));
Expand All @@ -1128,7 +1149,19 @@ class DreamPicoPortImp : public DreamPicoPort
return software_bus;
}

//! Transform flycast port index into DreamPicoPort port index
static int fcPortToDppPort(int forPort) {
// Flycast uses port index 5 for main peripheral and 0 is the first sub-peripheral slot
// DreamPicoPort uses port index 0 for main peripheral and 1 is the first sub-peripheral slot
if (forPort >= 5) {
return 0;
} else {
return forPort + 1;
}
}

u32 getFunctionCode(int forPort) const override {
forPort = fcPortToDppPort(forPort);
u32 mask = 0;
if ((int)peripherals.size() > forPort) {
for (const auto& peripheral : peripherals[forPort]) {
Expand All @@ -1140,6 +1173,7 @@ class DreamPicoPortImp : public DreamPicoPort
}

std::array<u32, 3> getFunctionDefinitions(int forPort) const override {
forPort = fcPortToDppPort(forPort);
std::array<u32, 3> arr{0, 0, 0};
if ((int)peripherals.size() > forPort) {
std::size_t idx = 0;
Expand Down Expand Up @@ -1212,7 +1246,7 @@ class DreamPicoPortImp : public DreamPicoPort
}

bool needsRefresh() override {
// TODO: implementing this method may also help to support hot plugging of VMUs/rumble packs here.
// TODO: implementing this method may also help to support hot plugging of VMUs/jump packs here.
return false;
}

Expand Down Expand Up @@ -1277,7 +1311,7 @@ class DreamPicoPortImp : public DreamPicoPort
int vibrationCount = 0;

if (software_bus >= 0 && static_cast<std::size_t>(software_bus) < config::MapleExpansionDevices.size()) {
u32 portOneFn = getFunctionCode(1);
u32 portOneFn = getFunctionCode(0);
if (portOneFn & MFID_1_Storage) {
config::MapleExpansionDevices[software_bus][0] = MDT_SegaVMU;
++vmuCount;
Expand All @@ -1286,7 +1320,7 @@ class DreamPicoPortImp : public DreamPicoPort
config::MapleExpansionDevices[software_bus][0] = MDT_None;
}

u32 portTwoFn = getFunctionCode(2);
u32 portTwoFn = getFunctionCode(1);
if (portTwoFn & MFID_8_Vibration) {
config::MapleExpansionDevices[software_bus][1] = MDT_PurupuruPack;
++vibrationCount;
Expand All @@ -1302,7 +1336,7 @@ class DreamPicoPortImp : public DreamPicoPort

NOTICE_LOG(
INPUT,
"Connected to DreamPicoPort[%d]: Type:%s, VMU:%d, Rumble Pack:%d",
"Connected to DreamPicoPort[%d]: Type:%s, VMU:%d, Jump Pack:%d",
software_bus,
getName().c_str(),
vmuCount,
Expand Down
4 changes: 2 additions & 2 deletions core/ui/settings_controls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1031,8 +1031,8 @@ void gui_settings_controls(bool& maple_devices_changed)
#ifdef USE_DREAMLINK_DEVICES
{
DisabledScope scope(game_started);
OptionCheckbox("Use Physical VMU Memory", config::UsePhysicalVmuMemory,
"Enables direct read/write access to physical VMU memory via DreamPicoPort/DreamConn. "
OptionCheckbox("Use Physical VMU Memory When Available", config::UsePhysicalVmuMemory,
"Enables direct read/write access to physical VMU memory via DreamPicoPort/network device. "
"This is not compatible with load state events.");
}
#endif
Expand Down
Loading