source-device.cpp

Go to the documentation of this file.
00001 /*
00002  * source-device.cpp
00003  *
00004  * Copyright (C) 2009  Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *     * Redistributions of source code must retain the above copyright
00011  *       notice, this list of conditions and the following disclaimer.
00012  *     * Redistributions in binary form must reproduce the above copyright
00013  *       notice, this list of conditions and the following disclaimer in the
00014  *       documentation and/or other materials provided with the distribution.
00015  *     * Neither the name of the <organization> nor the
00016  *       names of its contributors may be used to endorse or promote products
00017  *       derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY
00020  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022  * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY
00023  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00024  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00026  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  *
00030  *
00031  * See source-device.h
00032  */
00033 
00034 // includes --------------------------------------------------------------------
00035 #include "source-device.h"              // always include our own header first
00036 
00037 namespace gamepad {
00038 
00039 
00040 /// interface destructors
00041 SourceDevice::~SourceDevice(void) throw() { }
00042 SourceDeviceFactory::~SourceDeviceFactory(void) throw() { }
00043 
00044 
00045 
00046 ////////////////////////////////////////////////////////////////////////////////
00047 //
00048 //      static helper methods
00049 //
00050 ////////////////////////////////////////////////////////////////////////////////
00051 
00052 ////////////////////////////////////////////////////////////////////////////////
00053 //
00054 //      public API
00055 //
00056 ////////////////////////////////////////////////////////////////////////////////
00057 
00058 byte_t
00059 updateButton
00060 (
00061 IN byte_t oldButton,
00062 IN bool isButtonDown
00063 )
00064 throw()
00065 {
00066         if (isButtonDown) {
00067                 // button is down now.  Was it down before?
00068                 if (eButtonDown & oldButton) {
00069                         // button was already down!  no change...
00070                 } else {
00071                         // need to set "was pushed" and "is down" bits
00072                         oldButton |= eButtonWasPushed;          
00073                         oldButton |= eButtonDown;
00074                 }
00075         } else {
00076                 // button is up now.  Was it down before?
00077                 if (eButtonDown & oldButton) {
00078                         // DPRINTF("old:0x%02x", oldButton);
00079 
00080                         // button was recorded as down before
00081                         // need to clear "is down" bit
00082                         oldButton &= ~eButtonDown;
00083 
00084                         // set "was released" bit
00085                         oldButton |= eButtonWasReleased;
00086                 } else {
00087                         // button was already up!  no change
00088                 }
00089         }
00090 
00091         return oldButton;
00092 }
00093 
00094 
00095 
00096 void
00097 snapshotState
00098 (
00099 IN SourceDevice * device,
00100 OUT device_state_t& state
00101 )
00102 {
00103         ASSERT(device, "null");
00104         state.clear();
00105 
00106         // loop through all pots and set their values
00107         state.nPots = device->getNumPots();
00108         ASSERT_THROW(state.nPots <= device_state_t::eMaxPots,
00109             "Source device has too many potentiometers: " << state.nPots);
00110         for (int i = 0; i < state.nPots; ++i) {
00111                 state.pot[i] = device->getPotValue(i);
00112         }
00113 
00114         // loop through all buttons and set their values
00115         state.nButtons = device->getNumButtons();
00116         ASSERT_THROW(state.nButtons <= device_state_t::eMaxButtons,
00117             "Source device has too many buttons: " << state.nButtons);
00118         for (int i = 0; i < state.nButtons; ++i) {
00119                 state.button[i] = device->getButtonValue(i);
00120         }
00121 }
00122 
00123 
00124 
00125 int
00126 buttonDown
00127 (
00128 IN const device_state_t& s
00129 )
00130 {
00131         int retval = -1;
00132         for (int i = 0; i < s.nButtons; ++i) {
00133                 if (s.button[i] & eButtonDown) {
00134                         // button is down
00135                         if (retval > -1) {
00136                                 // multiple buttons are down
00137                                 return -1;
00138                         }
00139                         retval = i;
00140                 }
00141         }
00142         return retval;
00143 }
00144 
00145 
00146 
00147 int
00148 buttonChanged
00149 (
00150 IN const device_state_t& s0,
00151 IN const device_state_t& s1
00152 )
00153 {
00154         ASSERT_THROW(s0.nButtons == s1.nButtons,
00155             "State snapshots don't match button count?");
00156 
00157         int retval = -1;        // nothing changed
00158         for (int i = 0; i < s0.nButtons; ++i) {
00159                 if (s0.button[i] != s1.button[i]) {
00160                         // changed!
00161                         if (retval > -1) {
00162                                 // another button also changed
00163                                 DPRINTF("multiple button state changes");
00164                                 return -1;
00165                         }
00166                         retval = i;
00167                 }
00168         }
00169 
00170         return retval;
00171 }
00172 
00173 
00174 
00175 int
00176 buttonReleased
00177 (
00178 IN const device_state_t& s
00179 )
00180 {
00181         int retval = -1;
00182         for (int i = 0; i < s.nButtons; ++i) {
00183                 if (eButtonWasReleased & s.button[i]) {
00184                         if (retval > -1) {
00185                                 // another button was also released!
00186                                 DPRINTF("multiple button releases");
00187                                 return -1;
00188                         }
00189                         retval = i;
00190                 }
00191         }
00192 
00193         return retval;
00194 }
00195 
00196 
00197 
00198 bool
00199 potsCalibrated
00200 (
00201 IN const device_state_t& s0,
00202 IN const device_state_t& s1
00203 )
00204 {
00205         ASSERT_THROW(s0.nPots == s1.nPots,
00206             "State snapshots have different potentiometer counts?  " <<
00207             s0.nPots << " vs. " << s1.nPots);
00208 
00209         for (int i = 0; i < s0.nPots; ++i) {
00210                 const pot_value_t& p0 = s0.pot[i];
00211                 const pot_value_t& p1 = s1.pot[i];
00212 
00213                 if (p0.minSeen == p0.maxSeen ||
00214                     p0.minSeen != p1.minSeen ||
00215                     p0.maxSeen != p1.maxSeen) {
00216                         DPRINTF("Still calibrating potentiometers (%d)", i);
00217                         DPRINTF("  p0.min=%d   p0.max=%d", p0.minSeen, p0.maxSeen);
00218                         DPRINTF("  p1.min=%d   p1.max=%d", p1.minSeen, p1.maxSeen);
00219                         return false;
00220                 }
00221         }
00222 
00223         return true;
00224 }
00225 
00226 
00227 
00228 int
00229 maxPotValue
00230 (
00231 IN const device_state_t& state,
00232 IN float threshold
00233 )
00234 {
00235         ASSERT(threshold >= 0.0 && threshold <= 1.0,
00236             "Bad threshold: %f", threshold);
00237 
00238         int retval = -1;
00239         float max = threshold;
00240         
00241         for (int i = 0; i < state.nPots; ++i) {
00242                 const pot_value_t& p0 = state.pot[i];
00243 
00244                 if (p0.minSeen == p0.maxSeen) {
00245                         // skip this pot
00246                         continue;
00247                 }
00248 
00249                 float val = (p0.value - p0.minSeen) / (p0.maxSeen - p0.minSeen);
00250 
00251                 if (val > max) {
00252                         retval = i;
00253                         max = val;
00254                 }
00255         }
00256 
00257         return retval;
00258 }
00259 
00260 
00261 
00262 int
00263 maxPotChanged
00264 (
00265 IN const device_state_t& s0,    // old state
00266 IN const device_state_t& s1     // new state
00267 )
00268 {
00269         ASSERT_THROW(s0.nPots == s1.nPots,
00270             "State snapshots have different potentiometer counts?  " <<
00271             s0.nPots << " vs. " << s1.nPots);
00272 
00273         int retval = -1;
00274         float delta = 0.4;      // pots should change by 40% or more
00275 
00276         for (int i = 0; i < s0.nPots; ++i) {
00277                 const pot_value_t& p0 = s0.pot[i];
00278                 const pot_value_t& p1 = s1.pot[i];
00279 
00280                 if (!p0.isValid() || !p1.isValid() ||
00281                     p0.minSeen != p1.minSeen ||
00282                     p0.maxSeen != p1.maxSeen) {
00283                         // skip this pot
00284                         DPRINTF("Skipping non-calibrated [%d]...\n", i);
00285                         continue;
00286                 }
00287 
00288                 float dv = (1.0 * (p1.value - p0.value)) / (p1.maxSeen - p1.minSeen);
00289                 if (dv < 0) {
00290                         dv = -dv;
00291                 }
00292                 DPRINTF("  pot[%d]: dv=%f  (min=%d, max=%d, v0=%d, v1=%d)",
00293                     i, dv, p1.minSeen, p1.maxSeen, p0.value, p1.value);
00294                 if (dv > delta) {
00295                         delta = dv;
00296                         retval = i;
00297                 }
00298         }
00299 
00300         return retval;
00301 }
00302 
00303 
00304 
00305 };      // gamepad namespace
00306