diff --git a/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs b/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs index fa4743348c..6eeb983f3a 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs @@ -1,6 +1,7 @@ //TODO hook up newer file ID stuff, think about how to combine it with the disc ID //TODO change display manager to not require 0xFF alpha channel set on videoproviders. check gdi+ and opengl! this will get us a speedup in some places //TODO Disc.Structure.Sessions[0].length_aba was 0 +//TODO disc lights using System; using System.Runtime.InteropServices; @@ -22,7 +23,31 @@ namespace BizHawk.Emulation.Cores.Sony.PSX public unsafe class Octoshock : IEmulator, IVideoProvider, ISoundProvider { public string SystemId { get { return "NULL"; } } - public static readonly ControllerDefinition NullController = new ControllerDefinition { Name = "Null Controller" }; + + public static readonly ControllerDefinition DualShockController = new ControllerDefinition + { + Name = "DualShock Controller", + BoolButtons = + { + "Up", "Down", "Left", "Right", + "Select", "Start", + "Square", "Triangle", "Circle", "Cross", + "L1", "R1", "L2", "R2", "L3", "R3", + "MODE", + }, + FloatControls = + { + "LStick X", "LStick Y", + "RStick X", "RStick Y", + }, + FloatRanges = + { + new[] {0.0f, 128.0f, 255.0f}, + new[] {255.0f, 128.0f, 0.0f}, + new[] {0.0f, 128.0f, 255.0f}, + new[] {255.0f, 128.0f, 0.0f}, + } + }; public string BoardName { get { return null; } } @@ -185,6 +210,7 @@ namespace BizHawk.Emulation.Cores.Sony.PSX OctoshockDll.shock_OpenTray(psx); OctoshockDll.shock_SetDisc(psx, discInterface.OctoshockHandle); OctoshockDll.shock_CloseTray(psx); + OctoshockDll.shock_Peripheral_Connect(psx, 0x01, OctoshockDll.ePeripheralType.DualShock); OctoshockDll.shock_PowerOn(psx); } @@ -219,8 +245,43 @@ namespace BizHawk.Emulation.Cores.Sony.PSX Frame = 0; } + void SetInput() + { + uint buttons = 0; + + //dualshock style + if(Controller["Select"]) buttons |= 1; + if (Controller["L3"]) buttons |= 2; + if (Controller["R3"]) buttons |= 4; + if (Controller["Start"]) buttons |= 8; + if (Controller["Up"]) buttons |= 16; + if (Controller["Right"]) buttons |= 32; + if (Controller["Down"]) buttons |= 64; + if (Controller["Left"]) buttons |= 128; + if (Controller["L2"]) buttons |= 256; + if (Controller["R2"]) buttons |= 512; + if (Controller["L1"]) buttons |= 1024; + if (Controller["R1"]) buttons |= 2048; + if (Controller["Triangle"]) buttons |= 4096; + if (Controller["Circle"]) buttons |= 8192; + if (Controller["Cross"]) buttons |= 16384; + if (Controller["Square"]) buttons |= 32768; + if (Controller["MODE"]) buttons |= 65536; + + byte left_x = (byte)Controller.GetFloat("LStick X"); + byte left_y = (byte)Controller.GetFloat("LStick Y"); + byte right_x = (byte)Controller.GetFloat("RStick X"); + byte right_y = (byte)Controller.GetFloat("RStick Y"); + + OctoshockDll.shock_Peripheral_SetPadInput(psx, 0x01, buttons, left_x, left_y, right_x, right_y); + } + public void FrameAdvance(bool render, bool rendersound) { + Frame++; + + SetInput(); + OctoshockDll.shock_Step(psx, OctoshockDll.eShockStep.Frame); OctoshockDll.ShockFramebufferInfo fb = new OctoshockDll.ShockFramebufferInfo(); @@ -251,10 +312,7 @@ namespace BizHawk.Emulation.Cores.Sony.PSX } } - [FeatureNotImplemented] - public ControllerDefinition ControllerDefinition { get { return NullController; } } - - [FeatureNotImplemented] + public ControllerDefinition ControllerDefinition { get { return DualShockController; } } public IController Controller { get; set; } public int Frame diff --git a/BizHawk.Emulation.Cores/Consoles/Sony/PSX/OctoshockDll.cs b/BizHawk.Emulation.Cores/Consoles/Sony/PSX/OctoshockDll.cs index f8f7fa7358..f31b9935db 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sony/PSX/OctoshockDll.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sony/PSX/OctoshockDll.cs @@ -1,5 +1,4 @@ -//API TODO -//get rid of the 2048 byte reader +//TODO - make sure msvc builds with 32bit enums and get rid of the extra marshalling fluff here using System; using System.Runtime.InteropServices; @@ -25,9 +24,21 @@ public unsafe static class OctoshockDll Normalize = 1 } + public enum ePeripheralType + { + None = 0, //can be used to signify disconnection + + Pad = 1, //SCPH-1080 + DualShock = 2, //SCPH-1200 + DualAnalog = 3, //SCPH-1180 + + Multitap = 10, + }; + public const int SHOCK_OK = 0; public const int SHOCK_ERROR = -1; public const int SHOCK_NOCANDO = -2; + public const int SHOCK_INVALID_ADDRESS = -3; [StructLayout(LayoutKind.Sequential)] public struct ShockDiscInfo @@ -82,6 +93,17 @@ public unsafe static class OctoshockDll [DllImport("octoshock.dll")] public static extern int shock_Destroy(IntPtr psx); + [DllImport("octoshock.dll")] + + public static extern int shock_Peripheral_Connect( + IntPtr psx, + int address, + [MarshalAs(UnmanagedType.I4)] ePeripheralType type + ); + + [DllImport("octoshock.dll")] + public static extern int shock_Peripheral_SetPadInput(IntPtr psx, int address, uint buttons, byte left_x, byte left_y, byte right_x, byte right_y); + [DllImport("octoshock.dll")] public static extern int shock_PowerOn(IntPtr psx); diff --git a/output/defctrl.json b/output/defctrl.json index c5806beb5a..8233f41aaf 100644 --- a/output/defctrl.json +++ b/output/defctrl.json @@ -629,6 +629,25 @@ "P2 A": "", "Power": "" }, + "DualShock Controller": { + "Up": "X1 DpadUp,UpArrow", + "Down": "X1 DpadDown,DownArrow", + "Left": "X1 DpadLeft,LeftArrow", + "Right": "X1 DpadRight,RightArrow", + "Select": "X1 Back,Space", + "Start": "X1 Start,Return", + "Square": "X1 X,A", + "Triangle": "X1 Y,S", + "Circle": "X1 B,X", + "Cross": "X1 A,Z", + "L1": "X1 LeftShoulder,Q", + "R1": "X1 RightShoulder,W", + "L2": "X1 LeftTrigger,E", + "R2": "X1 RightTrigger,R", + "L3": "X1 LeftThumb,T", + "R3": "X1 RightThumb,Y", + "MODE": "A" + }, "Lynx Controller": { "Up": "UpArrow", "Down": "DownArrow", @@ -942,6 +961,28 @@ } }, "WonderSwan Controller": {}, - "Lynx Controller": {} + "Lynx Controller": {}, + "DualShock Controller": { + "LStick X": { + "Value": "X1 LeftThumbX", + "Mult": 1.0, + "Deadzone": 0.1 + }, + "LStick Y": { + "Value": "X1 LeftThumbY", + "Mult": 1.0, + "Deadzone": 0.1 + }, + "RStick X": { + "Value": "X1 RightThumbX", + "Mult": 1.0, + "Deadzone": 0.1 + }, + "RStick Y": { + "Value": "X1 RightThumbY", + "Mult": 1.0, + "Deadzone": 0.1 + } + } } } \ No newline at end of file diff --git a/output/dll/octoshock.dll b/output/dll/octoshock.dll index 82e973c111..a18d029c1b 100644 Binary files a/output/dll/octoshock.dll and b/output/dll/octoshock.dll differ diff --git a/psx/octoshock/psx/input/dualshock.cpp b/psx/octoshock/psx/input/dualshock.cpp index 994227533e..f1847e9587 100644 --- a/psx/octoshock/psx/input/dualshock.cpp +++ b/psx/octoshock/psx/input/dualshock.cpp @@ -291,19 +291,24 @@ void InputDevice_DualShock::UpdateInput(const void *data) buttons[1] = d8[1]; cur_ana_button_state = d8[2] & 0x01; - for(int stick = 0; stick < 2; stick++) - { - for(int axis = 0; axis < 2; axis++) - { - const uint8* aba = &d8[3] + stick * 8 + axis * 4; - int32 tmp; + //OCTOSHOCK EDIT - so we can set values directly + //for(int stick = 0; stick < 2; stick++) + //{ + // for(int axis = 0; axis < 2; axis++) + // { + // //const uint8* aba = &d8[3] + stick * 8 + axis * 4; + // //int32 tmp; - tmp = 32767 + MDFN_de16lsb(&aba[0]) - MDFN_de16lsb(&aba[2]); - tmp = (tmp * 0x100) / 0xFFFF; + // //tmp = 32767 + MDFN_de16lsb(&aba[0]) - MDFN_de16lsb(&aba[2]); + // //tmp = (tmp * 0x100) / 0xFFFF; + // + // } + //} + axes[0][0] = d8[3]; + axes[0][1] = d8[4]; + axes[1][0] = d8[5]; + axes[1][1] = d8[6]; - axes[stick][axis] = tmp; - } - } //printf("%3d:%3d, %3d:%3d\n", axes[0][0], axes[0][1], axes[1][0], axes[1][1]); diff --git a/psx/octoshock/psx/psx.cpp b/psx/octoshock/psx/psx.cpp index 5e82bbc6d7..3b53173714 100644 --- a/psx/octoshock/psx/psx.cpp +++ b/psx/octoshock/psx/psx.cpp @@ -1323,6 +1323,98 @@ struct ShockState bool power; } s_ShockState; + +struct ShockPeripheral +{ + ePeripheralType type; + u8 buffer[16]; +}; + +struct { + + ShockPeripheral ports[2]; + + void Initialize() + { + for(int i=0;i<2;i++) + { + ports[i].type = ePeripheralType_None; + memset(ports[i].buffer,0,sizeof(ports[i].buffer)); + } + } + + s32 Connect(s32 address, s32 type) + { + //check the port address + int portnum = address&1; + if(portnum != 1 && portnum != 2) + return SHOCK_INVALID_ADDRESS; + portnum--; + + //check whats already there + if(ports[portnum].type == ePeripheralType_None && type == ePeripheralType_None) return SHOCK_OK; //NOP + if(ports[portnum].type != ePeripheralType_None && type != ePeripheralType_None) return SHOCK_NOCANDO; //cant re-connect something without disconnecting first + + //disconnecting: + if(type == ePeripheralType_None) { + ports[portnum].type = ePeripheralType_None; + memset(ports[portnum].buffer,0,sizeof(ports[portnum].buffer)); + FIO->SetInput(portnum, "none", ports[portnum].buffer); + return SHOCK_OK; + } + + //connecting: + const char* name = NULL; + switch(type) + { + case ePeripheralType_Pad: name = "gamepad"; break; + case ePeripheralType_DualShock: name = "dualshock"; break; + case ePeripheralType_DualAnalog: name = "dualanalog"; break; + default: + return SHOCK_ERROR; + } + ports[portnum].type = (ePeripheralType)type; + memset(ports[portnum].buffer,0,sizeof(ports[portnum].buffer)); + FIO->SetInput(portnum, name, ports[portnum].buffer); + + return SHOCK_OK; + } + + s32 SetPadInput(s32 address, u32 buttons, u8 left_x, u8 left_y, u8 right_x, u8 right_y) + { + //check the port address + int portnum = address&1; + if(portnum != 1 && portnum != 2) + return SHOCK_INVALID_ADDRESS; + portnum--; + + u8* buf = ports[portnum].buffer; + switch(ports[portnum].type) + { + case ePeripheralType_DualShock: + buf[0] = (buttons>>0)&0xFF; + buf[1] = (buttons>>8)&0xFF; + buf[2] = (buttons>>16)&0xFF; //this is only the analog mode button + buf[3] = left_x; + buf[4] = left_y; + buf[3] = right_x; + buf[4] = right_y; + break; + } + } + +} s_ShockPeripheralState; + +EW_EXPORT s32 shock_Peripheral_Connect(void* psx, s32 address, s32 type) +{ + return s_ShockPeripheralState.Connect(address,type); +} + +EW_EXPORT s32 shock_Peripheral_SetPadInput(void* psx, s32 address, u32 buttons, u8 left_x, u8 left_y, u8 right_x, u8 right_y) +{ + return s_ShockPeripheralState.SetPadInput(address, buttons, left_x, left_y, right_x, right_y); +} + static void MountCPUAddressSpace() { for(uint32 ma = 0x00000000; ma < 0x00800000; ma += 2048 * 1024) @@ -1350,7 +1442,7 @@ static bool s_FramebufferNormalized; static int s_FramebufferCurrent; static int s_FramebufferCurrentWidth; -EW_EXPORT s32 shock_Create(void** psx, eRegion region, void* firmware512k) +EW_EXPORT s32 shock_Create(void** psx, s32 region, void* firmware512k) { //NEW *psx = NULL; @@ -1413,6 +1505,7 @@ EW_EXPORT s32 shock_Create(void** psx, eRegion region, void* firmware512k) static bool emulate_memcard[8] = {0}; static bool emulate_multitap[2] = {0}; FIO = new FrontIO(emulate_memcard, emulate_multitap); + s_ShockPeripheralState.Initialize(); MountCPUAddressSpace(); @@ -2188,15 +2281,6 @@ static void CloseGame(void) Cleanup(); } - -static void SetInput(int port, const char *type, void *ptr) -{ - if(psf_loader) - FIO->SetInput(port, "none", NULL); - else - FIO->SetInput(port, type, ptr); -} - static int StateAction(StateMem *sm, int load, int data_only) { @@ -3080,4 +3164,4 @@ s32 ShockDiscRef::ReadLBA2048(s32 lba, void* dst2048) memcpy(dst2048,xasector.form1.data2048,2048); return sector.mode; -} \ No newline at end of file +} diff --git a/psx/octoshock/psx/psx.h b/psx/octoshock/psx/psx.h index 1a08371e51..8f1a9de946 100644 --- a/psx/octoshock/psx/psx.h +++ b/psx/octoshock/psx/psx.h @@ -131,6 +131,17 @@ enum eShockFramebufferFlags eShockFramebufferFlags_Normalize = 1 }; +enum ePeripheralType +{ + ePeripheralType_None = 0, //can be used to signify disconnection + + ePeripheralType_Pad = 1, //SCPH-1080 + ePeripheralType_DualShock = 2, //SCPH-1200 + ePeripheralType_DualAnalog = 3, //SCPH-1180 + + ePeripheralType_Multitap = 10, +}; + enum eShockSetting { REGION_AUTODETECT = 0, @@ -152,6 +163,7 @@ int shock_GetSetting(eShockSetting setting); #define SHOCK_OK 0 #define SHOCK_ERROR -1 #define SHOCK_NOCANDO -2 +#define SHOCK_INVALID_ADDRESS -3 struct ShockTOCTrack { @@ -230,11 +242,23 @@ EW_EXPORT s32 shock_AnalyzeDisc(ShockDiscRef* disc, ShockDiscInfo* info); //Creates the psx instance as a console of the specified region. //Additionally mounts the firmware from the provided buffer (the contents are copied) //TODO - receive a model number parameter instead -EW_EXPORT s32 shock_Create(void** psx, eRegion region, void* firmware512k); +EW_EXPORT s32 shock_Create(void** psx, s32 region, void* firmware512k); //Frees the psx instance created with shock_Create EW_EXPORT s32 shock_Destroy(void* psx); +//Attaches (or detaches) a peripheral at the given address. +//Send ePeripheralType_None to detach. +//Do not attach when something is already attached. +//You can detach when nothing is attached. +//Returns SHOCK_NOCANDO if something inappropriate is done. +//Presently this has only been validated as functioning correctly before the initial PowerOn, but we would like to use it other times. +EW_EXPORT s32 shock_Peripheral_Connect(void* psx, s32 address, s32 type); + +//Sets pad-type input (pad,dualshock,dualanalog) on the specified address; +//Read more about the input format (buttons, analog range) here: TBD +EW_EXPORT s32 shock_Peripheral_SetPadInput(void* psx, s32 address, u32 buttons, u8 left_x, u8 left_y, u8 right_x, u8 right_y); + //Sets the power to ON. Returns SHOCK_NOCANDO if already on. EW_EXPORT s32 shock_PowerOn(void* psx);