DOSBox-X
|
00001 /* 00002 * Copyright (C) 2002-2020 The DOSBox Team 00003 * 00004 * This program is free software; you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation; either version 2 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License along 00015 * with this program; if not, write to the Free Software Foundation, Inc., 00016 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 */ 00018 00019 00020 #include <string.h> 00021 #include "dosbox.h" 00022 #include "inout.h" 00023 #include "setup.h" 00024 #include "joystick.h" 00025 #include "pic.h" 00026 #include "support.h" 00027 #include "control.h" 00028 00029 #define RANGE 64 00030 #define TIMEOUT 10 00031 00032 #define OHMS 120000/2 00033 #define JOY_S_CONSTANT 0.0000242 00034 #define S_PER_OHM 0.000000011 00035 00036 struct JoyStick { 00037 bool enabled; 00038 float xpos,ypos; 00039 double xtick,ytick; 00040 Bitu xcount,ycount; 00041 bool button[2]; 00042 }; 00043 00044 JoystickType joytype; 00045 static JoyStick stick[2]; 00046 00047 static Bit32u last_write = 0; 00048 static bool write_active = false; 00049 static bool swap34 = false; 00050 bool button_wrapping_enabled = true; 00051 00052 extern bool autofire; //sdl_mapper.cpp 00053 extern int joy1axes[]; //sdl_mapper.cpp 00054 extern int joy2axes[]; //sdl_mapper.cpp 00055 00056 static Bitu read_p201(Bitu port,Bitu iolen) { 00057 (void)iolen;//UNUSED 00058 (void)port;//UNUSED 00059 /* Reset Joystick to 0 after TIMEOUT ms */ 00060 if(write_active && ((PIC_Ticks - last_write) > TIMEOUT)) { 00061 write_active = false; 00062 stick[0].xcount = 0; 00063 stick[1].xcount = 0; 00064 stick[0].ycount = 0; 00065 stick[1].ycount = 0; 00066 // LOG_MSG("reset by time %d %d",PIC_Ticks,last_write); 00067 } 00068 00078 Bit8u ret=0xff; 00079 if (stick[0].enabled) { 00080 if (stick[0].xcount) stick[0].xcount--; else ret&=~1; 00081 if (stick[0].ycount) stick[0].ycount--; else ret&=~2; 00082 if (stick[0].button[0]) ret&=~16; 00083 if (stick[0].button[1]) ret&=~32; 00084 } 00085 if (stick[1].enabled) { 00086 if (stick[1].xcount) stick[1].xcount--; else ret&=~4; 00087 if (stick[1].ycount) stick[1].ycount--; else ret&=~8; 00088 if (stick[1].button[0]) ret&=~64; 00089 if (stick[1].button[1]) ret&=~128; 00090 } 00091 return ret; 00092 } 00093 00094 static Bitu read_p201_timed(Bitu port,Bitu iolen) { 00095 (void)port;//UNUSED 00096 (void)iolen;//UNUSED 00097 Bit8u ret=0xff; 00098 double currentTick = PIC_FullIndex(); 00099 if( stick[0].enabled ){ 00100 if( stick[0].xtick < currentTick ) ret &=~1; 00101 if( stick[0].ytick < currentTick ) ret &=~2; 00102 } 00103 if( stick[1].enabled ){ 00104 if( stick[1].xtick < currentTick ) ret &=~4; 00105 if( stick[1].ytick < currentTick ) ret &=~8; 00106 } 00107 00108 if (stick[0].enabled) { 00109 if (stick[0].button[0]) ret&=~16; 00110 if (stick[0].button[1]) ret&=~32; 00111 } 00112 if (stick[1].enabled) { 00113 if (stick[1].button[0]) ret&=~64; 00114 if (stick[1].button[1]) ret&=~128; 00115 } 00116 return ret; 00117 } 00118 00119 static void write_p201(Bitu port,Bitu val,Bitu iolen) { 00120 (void)val;//UNUSED 00121 (void)port;//UNUSED 00122 (void)iolen;//UNUSED 00123 /* Store writetime index */ 00124 write_active = true; 00125 last_write = (Bit32u)PIC_Ticks; 00126 if (stick[0].enabled) { 00127 stick[0].xcount=(Bitu)((stick[0].xpos*RANGE)+RANGE); 00128 stick[0].ycount=(Bitu)((stick[0].ypos*RANGE)+RANGE); 00129 } 00130 if (stick[1].enabled) { 00131 stick[1].xcount=(Bitu)(((swap34? stick[1].ypos : stick[1].xpos)*RANGE)+RANGE); 00132 stick[1].ycount=(Bitu)(((swap34? stick[1].xpos : stick[1].ypos)*RANGE)+RANGE); 00133 } 00134 00135 } 00136 static void write_p201_timed(Bitu port,Bitu val,Bitu iolen) { 00137 (void)val;//UNUSED 00138 (void)port;//UNUSED 00139 (void)iolen;//UNUSED 00140 // Store writetime index 00141 // Axes take time = 24.2 microseconds + ( 0.011 microsecons/ohm * resistance ) 00142 // to reset to 0 00143 // Precalculate the time at which each axis hits 0 here 00144 double currentTick = PIC_FullIndex(); 00145 if (stick[0].enabled) { 00146 stick[0].xtick = currentTick + 1000.0*( JOY_S_CONSTANT + S_PER_OHM * 00147 (double)((stick[0].xpos+1.0)* OHMS) ); 00148 stick[0].ytick = currentTick + 1000.0*( JOY_S_CONSTANT + S_PER_OHM * 00149 (double)((stick[0].ypos+1.0)* OHMS) ); 00150 } 00151 if (stick[1].enabled) { 00152 stick[1].xtick = currentTick + 1000.0*( JOY_S_CONSTANT + S_PER_OHM * 00153 (double)((swap34? stick[1].ypos : stick[1].xpos)+1.0) * OHMS); 00154 stick[1].ytick = currentTick + 1000.0*( JOY_S_CONSTANT + S_PER_OHM * 00155 (double)((swap34? stick[1].xpos : stick[1].ypos)+1.0) * OHMS); 00156 } 00157 } 00158 00159 void JOYSTICK_Enable(Bitu which,bool enabled) { 00160 LOG(LOG_MISC,LOG_DEBUG)("JOYSTICK: Stick %u enable=%u",(int)which,enabled?1:0); 00161 if (which<2) stick[which].enabled=enabled; 00162 } 00163 00164 void JOYSTICK_Button(Bitu which,Bitu num,bool pressed) { 00165 if ((which<2) && (num<2)) stick[which].button[num]=pressed; 00166 } 00167 00168 void JOYSTICK_Move_X(Bitu which,float x) { 00169 if (which<2) { 00170 stick[which].xpos=x; 00171 } 00172 } 00173 00174 void JOYSTICK_Move_Y(Bitu which,float y) { 00175 if (which<2) { 00176 stick[which].ypos=y; 00177 } 00178 } 00179 00180 bool JOYSTICK_IsEnabled(Bitu which) { 00181 if (which<2) return stick[which].enabled; 00182 return false; 00183 } 00184 00185 bool JOYSTICK_GetButton(Bitu which, Bitu num) { 00186 if ((which<2) && (num<2)) return stick[which].button[num]; 00187 return false; 00188 } 00189 00190 float JOYSTICK_GetMove_X(Bitu which) { 00191 if (which<2) return stick[which].xpos; 00192 return 0.0f; 00193 } 00194 00195 float JOYSTICK_GetMove_Y(Bitu which) { 00196 if (which<2) return stick[which].ypos; 00197 return 0.0f; 00198 } 00199 00200 class JOYSTICK:public Module_base{ 00201 private: 00202 IO_ReadHandleObject ReadHandler; 00203 IO_WriteHandleObject WriteHandler; 00204 public: 00205 JOYSTICK(Section* configuration):Module_base(configuration){ 00206 Section_prop * section=static_cast<Section_prop *>(configuration); 00207 00208 bool timed = section->Get_bool("timed"); 00209 if(timed) { 00210 ReadHandler.Install(0x201,read_p201_timed,IO_MB); 00211 WriteHandler.Install(0x201,write_p201_timed,IO_MB); 00212 } else { 00213 ReadHandler.Install(0x201,read_p201,IO_MB); 00214 WriteHandler.Install(0x201,write_p201,IO_MB); 00215 } 00216 } 00217 }; 00218 00219 static JOYSTICK* test = NULL; 00220 00221 void JOYSTICK_Destroy(Section* sec) { 00222 (void)sec;//UNUSED 00223 if (test != NULL) { 00224 delete test; 00225 test = NULL; 00226 } 00227 } 00228 00229 void JOYSTICK_OnPowerOn(Section* sec) { 00230 (void)sec;//UNUSED 00231 if (test == NULL) { 00232 LOG(LOG_MISC,LOG_DEBUG)("Allocating joystick emulation"); 00233 test = new JOYSTICK(control->GetSection("joystick")); 00234 } 00235 } 00236 00237 void JOYSTICK_Init() { 00238 LOG(LOG_MISC,LOG_DEBUG)("Initializing joystick emulation"); 00239 00240 /* NTS: Joystick emulation does not work if we init joystick type AFTER mapper init. 00241 * We cannot wait for poweron/reset signal for determination of joystick type. 00242 * But, I/O port setup can happen later. */ 00243 { 00244 Section_prop * section=static_cast<Section_prop *>(control->GetSection("joystick")); 00245 00246 const char * type=section->Get_string("joysticktype"); 00247 if (!strcasecmp(type,"none")) joytype = JOY_NONE; 00248 else if (!strcasecmp(type,"false")) joytype = JOY_NONE; 00249 else if (!strcasecmp(type,"auto")) joytype = JOY_AUTO; 00250 else if (!strcasecmp(type,"2axis")) joytype = JOY_2AXIS; 00251 else if (!strcasecmp(type,"4axis")) joytype = JOY_4AXIS; 00252 else if (!strcasecmp(type,"4axis_2")) joytype = JOY_4AXIS_2; 00253 else if (!strcasecmp(type,"fcs")) joytype = JOY_FCS; 00254 else if (!strcasecmp(type,"ch")) joytype = JOY_CH; 00255 else joytype = JOY_AUTO; 00256 00257 autofire = section->Get_bool("autofire"); 00258 swap34 = section->Get_bool("swap34"); 00259 button_wrapping_enabled = section->Get_bool("buttonwrap"); 00260 stick[0].enabled = false; 00261 stick[1].enabled = false; 00262 stick[0].xtick = stick[0].ytick = stick[1].xtick = 00263 stick[1].ytick = PIC_FullIndex(); 00264 00265 // retrieves axes mapping 00266 auto joysticks = 2; 00267 auto axes = 8; 00268 for (auto i = 0; i < joysticks; i++) 00269 { 00270 for (auto j = 0; j < axes; j++) 00271 { 00272 auto propname = "joy" + std::to_string(i + 1) + "axis" + std::to_string(j); 00273 auto axis = section->Get_int(propname); 00274 if (i == 0) 00275 { 00276 joy1axes[j] = axis; 00277 } 00278 else 00279 { 00280 joy2axes[j] = axis; 00281 } 00282 } 00283 } 00284 } 00285 00286 AddExitFunction(AddExitFunctionFuncPair(JOYSTICK_Destroy),true); 00287 00288 if (!IS_PC98_ARCH) 00289 AddVMEventFunction(VM_EVENT_POWERON,AddVMEventFunctionFuncPair(JOYSTICK_OnPowerOn)); 00290 } 00291 00292 //save state support 00293 namespace 00294 { 00295 class SerializeStick : public SerializeGlobalPOD 00296 { 00297 public: 00298 SerializeStick() : SerializeGlobalPOD("Joystick") 00299 { 00300 registerPOD(joytype); 00301 registerPOD(stick); 00302 registerPOD(last_write); 00303 registerPOD(write_active); 00304 registerPOD(swap34); 00305 registerPOD(button_wrapping_enabled); 00306 registerPOD(autofire); 00307 } 00308 } dummy; 00309 }