DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator
src/hardware/joystick.cpp
00001 /*
00002  *  Copyright (C) 2002-2015  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
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 
00054 static Bitu read_p201(Bitu port,Bitu iolen) {
00055     (void)iolen;//UNUSED
00056     (void)port;//UNUSED
00057         /* Reset Joystick to 0 after TIMEOUT ms */
00058         if(write_active && ((PIC_Ticks - last_write) > TIMEOUT)) {
00059                 write_active = false;
00060                 stick[0].xcount = 0;
00061                 stick[1].xcount = 0;
00062                 stick[0].ycount = 0;
00063                 stick[1].ycount = 0;
00064 //              LOG_MSG("reset by time %d %d",PIC_Ticks,last_write);
00065         }
00066 
00076         Bit8u ret=0xff;
00077         if (stick[0].enabled) {
00078                 if (stick[0].xcount) stick[0].xcount--; else ret&=~1;
00079                 if (stick[0].ycount) stick[0].ycount--; else ret&=~2;
00080                 if (stick[0].button[0]) ret&=~16;
00081                 if (stick[0].button[1]) ret&=~32;
00082         }
00083         if (stick[1].enabled) {
00084                 if (stick[1].xcount) stick[1].xcount--; else ret&=~4;
00085                 if (stick[1].ycount) stick[1].ycount--; else ret&=~8;
00086                 if (stick[1].button[0]) ret&=~64;
00087                 if (stick[1].button[1]) ret&=~128;
00088         }
00089         return ret;
00090 }
00091 
00092 static Bitu read_p201_timed(Bitu port,Bitu iolen) {
00093     (void)port;//UNUSED
00094     (void)iolen;//UNUSED
00095         Bit8u ret=0xff;
00096         double currentTick = PIC_FullIndex();
00097         if( stick[0].enabled ){
00098                 if( stick[0].xtick < currentTick ) ret &=~1;
00099                 if( stick[0].ytick < currentTick ) ret &=~2;
00100         }
00101         if( stick[1].enabled ){
00102                 if( stick[1].xtick < currentTick ) ret &=~4;
00103                 if( stick[1].ytick < currentTick ) ret &=~8;
00104         }
00105 
00106         if (stick[0].enabled) {
00107                 if (stick[0].button[0]) ret&=~16;
00108                 if (stick[0].button[1]) ret&=~32;
00109         }
00110         if (stick[1].enabled) {
00111                 if (stick[1].button[0]) ret&=~64;
00112                 if (stick[1].button[1]) ret&=~128;
00113         }
00114         return ret;
00115 }
00116 
00117 static void write_p201(Bitu port,Bitu val,Bitu iolen) {
00118     (void)val;//UNUSED
00119     (void)port;//UNUSED
00120     (void)iolen;//UNUSED
00121         /* Store writetime index */
00122         write_active = true;
00123         last_write = PIC_Ticks;
00124         if (stick[0].enabled) {
00125                 stick[0].xcount=(Bitu)((stick[0].xpos*RANGE)+RANGE);
00126                 stick[0].ycount=(Bitu)((stick[0].ypos*RANGE)+RANGE);
00127         }
00128         if (stick[1].enabled) {
00129                 stick[1].xcount=(Bitu)(((swap34? stick[1].ypos : stick[1].xpos)*RANGE)+RANGE);
00130                 stick[1].ycount=(Bitu)(((swap34? stick[1].xpos : stick[1].ypos)*RANGE)+RANGE);
00131         }
00132 
00133 }
00134 static void write_p201_timed(Bitu port,Bitu val,Bitu iolen) {
00135     (void)val;//UNUSED
00136     (void)port;//UNUSED
00137     (void)iolen;//UNUSED
00138         // Store writetime index
00139         // Axes take time = 24.2 microseconds + ( 0.011 microsecons/ohm * resistance )
00140         // to reset to 0
00141         // Precalculate the time at which each axis hits 0 here
00142         double currentTick = PIC_FullIndex();
00143         if (stick[0].enabled) {
00144                 stick[0].xtick = currentTick + 1000.0*( JOY_S_CONSTANT + S_PER_OHM *
00145                                  (double)(((stick[0].xpos+1.0)* OHMS)) );
00146                 stick[0].ytick = currentTick + 1000.0*( JOY_S_CONSTANT + S_PER_OHM *
00147                                  (double)(((stick[0].ypos+1.0)* OHMS)) );
00148         }
00149         if (stick[1].enabled) {
00150                 stick[1].xtick = currentTick + 1000.0*( JOY_S_CONSTANT + S_PER_OHM *
00151                                  (double)((swap34? stick[1].ypos : stick[1].xpos)+1.0) * OHMS);
00152                 stick[1].ytick = currentTick + 1000.0*( JOY_S_CONSTANT + S_PER_OHM *
00153                                  (double)((swap34? stick[1].xpos : stick[1].ypos)+1.0) * OHMS);
00154         }
00155 }
00156 
00157 void JOYSTICK_Enable(Bitu which,bool enabled) {
00158         LOG(LOG_MISC,LOG_DEBUG)("JOYSTICK: Stick %u enable=%u",(int)which,enabled?1:0);
00159         if (which<2) stick[which].enabled=enabled;
00160 }
00161 
00162 void JOYSTICK_Button(Bitu which,Bitu num,bool pressed) {
00163         if ((which<2) && (num<2)) stick[which].button[num]=pressed;
00164 }
00165 
00166 void JOYSTICK_Move_X(Bitu which,float x) {
00167         if (which<2) {
00168                 stick[which].xpos=x;
00169         }
00170 }
00171 
00172 void JOYSTICK_Move_Y(Bitu which,float y) {
00173         if (which<2) {
00174                 stick[which].ypos=y;
00175         }
00176 }
00177 
00178 bool JOYSTICK_IsEnabled(Bitu which) {
00179         if (which<2) return stick[which].enabled;
00180         return false;
00181 }
00182 
00183 bool JOYSTICK_GetButton(Bitu which, Bitu num) {
00184         if ((which<2) && (num<2)) return stick[which].button[num];
00185         return false;
00186 }
00187 
00188 float JOYSTICK_GetMove_X(Bitu which) {
00189         if (which<2) return stick[which].xpos;
00190         return 0.0f;
00191 }
00192 
00193 float JOYSTICK_GetMove_Y(Bitu which) {
00194         if (which<2) return stick[which].ypos;
00195         return 0.0f;
00196 }
00197 
00198 class JOYSTICK:public Module_base{
00199 private:
00200         IO_ReadHandleObject ReadHandler;
00201         IO_WriteHandleObject WriteHandler;
00202 public:
00203         JOYSTICK(Section* configuration):Module_base(configuration){
00204                 Section_prop * section=static_cast<Section_prop *>(configuration);
00205 
00206                 bool timed = section->Get_bool("timed");
00207                 if(timed) {
00208                         ReadHandler.Install(0x201,read_p201_timed,IO_MB);
00209                         WriteHandler.Install(0x201,write_p201_timed,IO_MB);
00210                 } else {
00211                         ReadHandler.Install(0x201,read_p201,IO_MB);
00212                         WriteHandler.Install(0x201,write_p201,IO_MB);
00213                 }
00214         }
00215 };
00216 
00217 static JOYSTICK* test = NULL;
00218 
00219 void JOYSTICK_Destroy(Section* sec) {
00220     (void)sec;//UNUSED
00221     if (test != NULL) {
00222         delete test;
00223         test = NULL;
00224     }
00225 }
00226 
00227 void JOYSTICK_OnPowerOn(Section* sec) {
00228     (void)sec;//UNUSED
00229     if (test == NULL) {
00230         LOG(LOG_MISC,LOG_DEBUG)("Allocating joystick emulation");
00231         test = new JOYSTICK(control->GetSection("joystick"));
00232     }
00233 }
00234 
00235 void JOYSTICK_Init() {
00236         LOG(LOG_MISC,LOG_DEBUG)("Initializing joystick emulation");
00237 
00238         /* NTS: Joystick emulation does not work if we init joystick type AFTER mapper init.
00239          *      We cannot wait for poweron/reset signal for determination of joystick type.
00240          *      But, I/O port setup can happen later. */
00241         {
00242                 Section_prop * section=static_cast<Section_prop *>(control->GetSection("joystick"));
00243 
00244                 const char * type=section->Get_string("joysticktype");
00245                 if (!strcasecmp(type,"none"))       joytype = JOY_NONE;
00246                 else if (!strcasecmp(type,"false")) joytype = JOY_NONE;
00247                 else if (!strcasecmp(type,"auto"))  joytype = JOY_AUTO;
00248                 else if (!strcasecmp(type,"2axis")) joytype = JOY_2AXIS;
00249                 else if (!strcasecmp(type,"4axis")) joytype = JOY_4AXIS;
00250                 else if (!strcasecmp(type,"4axis_2")) joytype = JOY_4AXIS_2;
00251                 else if (!strcasecmp(type,"fcs"))   joytype = JOY_FCS;
00252                 else if (!strcasecmp(type,"ch"))    joytype = JOY_CH;
00253                 else joytype = JOY_AUTO;
00254 
00255                 autofire = section->Get_bool("autofire");
00256                 swap34 = section->Get_bool("swap34");
00257                 button_wrapping_enabled = section->Get_bool("buttonwrap");
00258                 stick[0].enabled = false;
00259                 stick[1].enabled = false;
00260                 stick[0].xtick = stick[0].ytick = stick[1].xtick =
00261                                  stick[1].ytick = PIC_FullIndex();
00262         }
00263 
00264         AddExitFunction(AddExitFunctionFuncPair(JOYSTICK_Destroy),true);
00265 
00266     if (!IS_PC98_ARCH)
00267         AddVMEventFunction(VM_EVENT_POWERON,AddVMEventFunctionFuncPair(JOYSTICK_OnPowerOn));
00268 }
00269