From 927b0da09a22379d97f5fd65f894275d0258ec8c Mon Sep 17 00:00:00 2001 From: TomCh Date: Tue, 18 Jul 2023 05:02:55 +0900 Subject: [PATCH] Support Robocom's Interface Module protection dongles (#1247, PR#1248) --- help/cfg-advanced.html | 5 +- source/Configuration/PageAdvanced.cpp | 5 +- source/CopyProtectionDongles.cpp | 103 +++++++++++++++++++++++--- source/CopyProtectionDongles.h | 3 +- source/Joystick.cpp | 24 +++++- 5 files changed, 122 insertions(+), 18 deletions(-) diff --git a/help/cfg-advanced.html b/help/cfg-advanced.html index aef2ee21..f738b0c7 100644 --- a/help/cfg-advanced.html +++ b/help/cfg-advanced.html @@ -85,8 +85,9 @@ From the drop-down menu, select a device to use in the internal Game I/O Connect Supported devices are: NB. Copy protection dongles can interfere with joysticks (eg. buttons may be hardwired to a fixed state), so only use dongles with the intended software.
NB. Copy protection dongles can interfere with RGB cards (eg. unexpected video modes may get selected).
diff --git a/source/Configuration/PageAdvanced.cpp b/source/Configuration/PageAdvanced.cpp index 6fe7f76a..2a6786c0 100644 --- a/source/Configuration/PageAdvanced.cpp +++ b/source/Configuration/PageAdvanced.cpp @@ -47,7 +47,10 @@ const TCHAR CPageAdvanced::m_CloneChoices[] = const TCHAR CPageAdvanced::m_gameIOConnectorChoices[] = "Empty\0" "SDS DataKey - SpeedStar\0" /* Protection dongle for Southwestern Data Systems "SpeedStar" Applesoft Compiler */ - "Cortechs Corp - CodeWriter\0"; /* Protection key for Dynatech Microsoftware / Cortechs Corp "CodeWriter" */ + "Cortechs Corp - CodeWriter\0" /* Protection key for Dynatech Microsoftware / Cortechs Corp "CodeWriter" */ + "Robocom Ltd - Robo 500\0" /* Interface Module for Robocom Ltd's Robo 500 */ + "Robocom Ltd - Robo 1000\0" /* Interface Module for Robocom Ltd's Robo 1000 */ + "Robocom Ltd - Robo 1500\0"; /* Interface Module for Robocom Ltd's Robo 1500 */ INT_PTR CALLBACK CPageAdvanced::DlgProc(HWND hWnd, UINT message, WPARAM wparam, LPARAM lparam) diff --git a/source/CopyProtectionDongles.cpp b/source/CopyProtectionDongles.cpp index bcbb833f..93aa6b67 100644 --- a/source/CopyProtectionDongles.cpp +++ b/source/CopyProtectionDongles.cpp @@ -26,8 +26,9 @@ Emulate hardware copy protection dongles for Apple II Currently supported: - - Southwestern Data Systems DataKey for SpeedStar Applesoft Compiler (Matthew D'Asaro Dec 2022) - - Dynatech Microsoftware / Cortechs Corp protection key for "CodeWriter" + - Southwestern Data Systems' datakey for SpeedStar Applesoft Compiler (Matthew D'Asaro Dec 2022) + - Dynatech Microsoftware / Cortechs Corp's protection key for "CodeWriter" + - Robocom Ltd's Interface Module for Robo Graphics 500/1000/1500 & RoboCAD 1/2 (BitStik joystick plugs in on top) */ #include "StdAfx.h" #include @@ -41,12 +42,12 @@ static DONGLETYPE copyProtectionDongleType = DT_EMPTY; static const BYTE codewriterInitialLFSR = 0x6B; // %1101011 (7-bit LFSR) static BYTE codewriterLFSR = codewriterInitialLFSR; -static void codeWriterResetLFSR() +static void CodeWriterResetLFSR() { codewriterLFSR = codewriterInitialLFSR; } -static void codeWriterClockLFSR() +static void CodeWriterClockLFSR() { BYTE bit = ((codewriterLFSR >> 1) ^ (codewriterLFSR >> 0)) & 1; codewriterLFSR = (codewriterLFSR >> 1) | (bit << 6); @@ -73,9 +74,9 @@ void DongleControl(WORD address) if (copyProtectionDongleType == DT_CODEWRITER) { if ((AN == 3 && state == true) || MemGetAnnunciator(3)) // reset or was already reset? (ie. takes precedent over AN2) - codeWriterResetLFSR(); + CodeWriterResetLFSR(); else if (AN == 2 && state == false && MemGetAnnunciator(2) == true) // AN2 true->false edge? - codeWriterClockLFSR(); + CodeWriterClockLFSR(); } } @@ -103,15 +104,51 @@ int CopyProtectionDonglePB2(void) { switch (copyProtectionDongleType) { - case DT_SDSSPEEDSTAR: // Southwestern Data Systems DataKey for SpeedStar Applesoft Compiler + case DT_SDSSPEEDSTAR: return SdsSpeedStar(); - case DT_CODEWRITER: // Dynatech Microsoftware / Cortechs Corp protection key for "CodeWriter" + case DT_CODEWRITER: return codewriterLFSR & 1; default: return -1; - break; + } +} + +// Returns the copy protection dongle state of PDL(n). A return value of -1 means not used by copy protection dongle +int CopyProtectionDonglePDL(UINT pdl) +{ + if (copyProtectionDongleType != DT_ROBOCOM500 && copyProtectionDongleType != DT_ROBOCOM1000 && copyProtectionDongleType != DT_ROBOCOM1500) + return -1; + + bool roboComInterfaceModulePower = !MemGetAnnunciator(3); + if (!roboComInterfaceModulePower || pdl != 3) + return -1; + + UINT roboComInterfaceModuleMode = ((UINT)MemGetAnnunciator(2) << 2) | ((UINT)MemGetAnnunciator(1) << 1) | (UINT)MemGetAnnunciator(0); + + switch (copyProtectionDongleType) + { + case DT_ROBOCOM500: + { + static BYTE robo500[8] = { 0x3F,0x2E,0x54,0x54,0x2E,0x22,0x72,0x17 }; // PDL3 lower bound + return robo500[roboComInterfaceModuleMode] + 1; + } + + case DT_ROBOCOM1000: + { + static BYTE robo1000[8] = { 0x17,0x72,0x22,0x2E,0x54,0x54,0x2E,0x3F }; // PDL3 lower bound + return robo1000[roboComInterfaceModuleMode] + 1; + } + + case DT_ROBOCOM1500: + { + static BYTE robo1500[8] = { 0x72,0x17,0x2E,0x17,0x22,0x3F,0x54,0x22 }; // PDL3 lower bound + return robo1500[roboComInterfaceModuleMode] + 1; + } + + default: + return -1; } } @@ -122,6 +159,7 @@ int CopyProtectionDonglePB2(void) // Unit version history: // 1: Add SDS SpeedStar dongle // 2: Add Cortechs Corp CodeWriter protection key +// Add Robocom Ltd - Robo 500/1000/1500 Interface Modules static const UINT kUNIT_VERSION = 2; static const std::string& GetSnapshotStructName_SDSSpeedStar(void) @@ -132,7 +170,25 @@ static const std::string& GetSnapshotStructName_SDSSpeedStar(void) static const std::string& GetSnapshotStructName_CodeWriter(void) { - static const std::string name("Cortechs Corp CodeWriter protection key"); + static const std::string name("Cortechs Corp - CodeWriter protection key"); + return name; +} + +static const std::string& GetSnapshotStructName_Robocom500(void) +{ + static const std::string name("Robocom Ltd - Robo 500 Interface Module"); + return name; +} + +static const std::string& GetSnapshotStructName_Robocom1000(void) +{ + static const std::string name("Robocom Ltd - Robo 1000 Interface Module"); + return name; +} + +static const std::string& GetSnapshotStructName_Robocom1500(void) +{ + static const std::string name("Robocom Ltd - Robo 1500 Interface Module"); return name; } @@ -148,6 +204,21 @@ void CopyProtectionDongleSaveSnapshot(YamlSaveHelper& yamlSaveHelper) yamlSaveHelper.SaveString(SS_YAML_KEY_DEVICE, GetSnapshotStructName_CodeWriter()); yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_CODEWRITER_INDEX, codewriterLFSR); } + else if (copyProtectionDongleType == DT_ROBOCOM500) + { + yamlSaveHelper.SaveString(SS_YAML_KEY_DEVICE, GetSnapshotStructName_Robocom500()); + // NB. No state for this dongle + } + else if (copyProtectionDongleType == DT_ROBOCOM1000) + { + yamlSaveHelper.SaveString(SS_YAML_KEY_DEVICE, GetSnapshotStructName_Robocom1000()); + // NB. No state for this dongle + } + else if (copyProtectionDongleType == DT_ROBOCOM1500) + { + yamlSaveHelper.SaveString(SS_YAML_KEY_DEVICE, GetSnapshotStructName_Robocom1500()); + // NB. No state for this dongle + } else { _ASSERT(0); @@ -176,6 +247,18 @@ void CopyProtectionDongleLoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT versi copyProtectionDongleType = DT_CODEWRITER; codewriterLFSR = yamlLoadHelper.LoadUint(SS_YAML_KEY_CODEWRITER_INDEX); } + else if (device == GetSnapshotStructName_Robocom500()) + { + copyProtectionDongleType = DT_ROBOCOM500; + } + else if (device == GetSnapshotStructName_Robocom1000()) + { + copyProtectionDongleType = DT_ROBOCOM1000; + } + else if (device == GetSnapshotStructName_Robocom1500()) + { + copyProtectionDongleType = DT_ROBOCOM1500; + } else { _ASSERT(0); diff --git a/source/CopyProtectionDongles.h b/source/CopyProtectionDongles.h index bbff9a98..b5276002 100644 --- a/source/CopyProtectionDongles.h +++ b/source/CopyProtectionDongles.h @@ -3,7 +3,7 @@ #include "Common.h" // Must be in the same order as in PageAdvanced.cpp -enum DONGLETYPE { DT_EMPTY, DT_SDSSPEEDSTAR, DT_CODEWRITER }; +enum DONGLETYPE { DT_EMPTY, DT_SDSSPEEDSTAR, DT_CODEWRITER, DT_ROBOCOM500, DT_ROBOCOM1000, DT_ROBOCOM1500 }; void SetCopyProtectionDongleType(DONGLETYPE type); DONGLETYPE GetCopyProtectionDongleType(void); @@ -11,6 +11,7 @@ void DongleControl(WORD address); int CopyProtectionDonglePB0(void); int CopyProtectionDonglePB1(void); int CopyProtectionDonglePB2(void); +int CopyProtectionDonglePDL(UINT pdl); void CopyProtectionDongleSaveSnapshot(class YamlSaveHelper& yamlSaveHelper); void CopyProtectionDongleLoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT version); diff --git a/source/Joystick.cpp b/source/Joystick.cpp index b2483055..db7c751f 100644 --- a/source/Joystick.cpp +++ b/source/Joystick.cpp @@ -622,7 +622,7 @@ BYTE __stdcall JoyReadButton(WORD pc, WORD address, BYTE, BYTE, ULONG nExecutedC pressed = !swapButtons0and1 ? CheckButton0Pressed() : CheckButton1Pressed(); const UINT button0 = !swapButtons0and1 ? 0 : 1; DoAutofire(button0, pressed); - if(CopyProtectionDonglePB0() >= 0) //If a copy protection dongle needs PB0, this overrides the joystick + if (CopyProtectionDonglePB0() >= 0) //If a copy protection dongle needs PB0, this overrides the joystick pressed = CopyProtectionDonglePB0(); } break; @@ -682,9 +682,9 @@ BYTE __stdcall JoyReadPosition(WORD programcounter, WORD address, BYTE, BYTE, UL BOOL nPdlCntrActive = g_nCumulativeCycles <= g_paddleInactiveCycle[address & 3]; - // If no joystick connected, then this is always active (GH#778) + // If no joystick connected, then this is always active (GH#778) && no copy-protection dongle connected const UINT joyNum = (address & 2) ? 1 : 0; // $C064..$C067 - if (joyinfo[joytype[joyNum]] == DEVICE_NONE) + if (joyinfo[joytype[joyNum]] == DEVICE_NONE && CopyProtectionDonglePDL(address & 3) < 0) nPdlCntrActive = TRUE; return MemReadFloatingBus(nPdlCntrActive, nExecutedCycles); @@ -699,6 +699,12 @@ void JoyReset() } //=========================================================================== + +static void SetPaddleInactiveCycle(UINT pdl, UINT pdlPos) +{ + g_paddleInactiveCycle[pdl] = g_nCumulativeCycles + (UINT64)((double)pdlPos * PDL_CNTR_INTERVAL); +} + void JoyResetPosition(ULONG nExecutedCycles) { CpuCalcCycles(nExecutedCycles); @@ -754,7 +760,17 @@ void JoyResetPosition(ULONG nExecutedCycles) if (pdlPos >= 255) pdlPos = 287; - g_paddleInactiveCycle[pdl] = g_nCumulativeCycles + (UINT64)((double)pdlPos * PDL_CNTR_INTERVAL); + SetPaddleInactiveCycle(pdl, pdlPos); + } + + // Protection dongle overrides the PDL timer + // . eg. needed when Robocom PDL3 is still timing-out from the extended-255 count (eg. 287) + // . really if it were at 255 (ie. not connected), then on enabling the dongle it switches to (eg) 23 it should timeout immediately + for (UINT pdl = 0; pdl < 4; pdl++) + { + int pdlPosDongle = CopyProtectionDonglePDL(pdl); + if (pdlPosDongle >= 0) + SetPaddleInactiveCycle(pdl, pdlPosDongle); } }