test-manager.cpp

Go to the documentation of this file.
00001 /*
00002  * test-manager.cpp
00003  *
00004  * Copyright (C) 2010  Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  * Simple test of the gamepad::Manager object.
00008  */
00009 
00010 // includes --------------------------------------------------------------------
00011 #include <iostream>
00012 #include <signal.h>
00013 
00014 #include "gamepad/manager.h"
00015 #include "perf/perf.h"
00016 #include "threadsafe/threadsafe.h"
00017 
00018 
00019 // map from source device unique ID --> gamepad
00020 //  (limitation here: only support 1 gamepad per source device!)
00021 typedef std::map<std::string, smart_ptr<gamepad::Gamepad> > gamepad_map_t;
00022 
00023 static bool s_keepLooping               = true;
00024 
00025 
00026 ////////////////////////////////////////////////////////////////////////////////
00027 //
00028 //      static methods
00029 //
00030 ////////////////////////////////////////////////////////////////////////////////
00031 
00032 static void
00033 handleSignal
00034 (
00035 IN int sig
00036 )
00037 {
00038         s_keepLooping = false;
00039 }
00040 
00041 
00042 
00043 static smart_ptr<gamepad::Gamepad>
00044 createDefaultGamepad
00045 (
00046 IN gamepad::Manager * mgr,
00047 IN smart_ptr<gamepad::SourceDevice>& device
00048 )
00049 {
00050         perf::Timer timer("createDefaultGamepad");
00051         ASSERT(mgr, "null");
00052         ASSERT(device, "null");
00053 
00054         DPRINTF("Looking for a default gamepad mapping for device: '%s'",
00055             device->getPublicName());
00056 
00057         VecString mapNames;
00058         gamepad::getRecommendedMappings(mgr, device, mapNames);
00059         DPRINTF("  Found %d recommended mappings", (int) mapNames.size());
00060         if (!mapNames.size()) {
00061                 DPRINTF("  Source device not recognized!  Skipping...");
00062                 return NULL;
00063         }
00064 
00065         const char * name = mapNames[0].c_str();
00066         ASSERT(name, "null");
00067         DPRINTF("  Using the first recommended mapping: %s", name);
00068 
00069         smart_ptr<gamepad::Map> mapping = mgr->getMapping(name);
00070         if (!mapping) {
00071                 DPRINTF("  Mapping not found!  Skipping...");
00072                 return NULL;
00073         }
00074 
00075         DPRINTF("  Found mapping: %s", mapping->getName());
00076 
00077         // okay, create gamepad
00078         smart_ptr<gamepad::Gamepad> gpad;
00079         gamepad::Manager::eResult result =
00080             mgr->createGamepad(device, mapping, gpad);
00081         if (gamepad::Manager::eResult_Success != result) {
00082                 DPRINTF("  Gamepad create attempt failed!");
00083                 switch (result) {
00084                 case gamepad::Manager::eResult_BadSource:
00085                         DPRINTF("  Source device is bad/gone.");
00086                         break;
00087                 case gamepad::Manager::eResult_BadMap:
00088                         DPRINTF("  Mapping is bad");
00089                         break;
00090                 default:
00091                         DPRINTF("  Unknown reason: %d", result);
00092                 }
00093                 DPRINTF("  Skipping...");
00094                 return NULL;
00095         }
00096         ASSERT_THROW(gpad, "failed to create gamepad object");
00097         return gpad;
00098 }
00099 
00100 
00101 
00102 static void
00103 printButtons
00104 (
00105 IN gamepad::buttons_t buttons,
00106 IN const gamepad::Type * type
00107 )
00108 {
00109         ASSERT(type, "null");
00110 
00111         // this is very slow!  Fine for a demo, but for real programs you'll
00112         // want to precompute most of these bit masks so you can use quick bit
00113         // tests rather than loops.
00114         char buffer[128];
00115 
00116         std::string output;
00117         int nMax = type->getInputCount(gamepad::eInput_Button);
00118         int bitmask = 1;
00119         for (int i = 0; i < nMax; ++i, bitmask *= 2) {
00120                 if (buttons & bitmask) {
00121                         // button i is pressed!  What is its name?
00122                         const char * name =
00123                             type->getLogicalName(gamepad::eInput_Button, i);
00124 
00125                         sprintf(buffer, " %s", name);
00126                         output += buffer;
00127                 }
00128         }
00129         DPRINTF("  buttons: %s", output.c_str());
00130 }
00131 
00132 
00133 
00134 static void
00135 doTest
00136 (
00137 IN const char * dataDir
00138 )
00139 {
00140         ASSERT(dataDir, "null");
00141 
00142         // create nstream::Folder for data directory
00143         smart_ptr<nstream::Manager> fsMgr =
00144             nstream::getFilesystemManager(dataDir);
00145         ASSERT_THROW(fsMgr,
00146             "Failed to open filesystem manager for data directory: " <<
00147             dataDir);
00148         smart_ptr<nstream::Folder> root = fsMgr->getRoot();
00149         ASSERT(root, "null");
00150         smart_ptr<gamepad::Manager> mgr = gamepad::Manager::create(root);
00151         ASSERT_THROW(mgr, "failed to create gamepad manager?");
00152 
00153         int nSDevs = mgr->getSourceDeviceCount();
00154         DPRINTF("Found %d source devices", nSDevs);
00155 
00156         mgr->rediscover();
00157         nSDevs = mgr->getSourceDeviceCount();
00158         DPRINTF("Found %d source devices", nSDevs);
00159         ASSERT_THROW(nSDevs > 0, "No source devices!");
00160 
00161         int nSDevs2 = mgr->getSourceDeviceCount();
00162         DPRINTF("Found %d source devices (again)", nSDevs2);
00163         ASSERT_THROW(nSDevs == nSDevs2, "found different number of devices?");
00164 
00165         smart_ptr<gamepad::SourceDevice> device = mgr->getSourceDevice(0);
00166         ASSERT_THROW(device, "failed to acquire first device");
00167 
00168         device = mgr->getSourceDevice(nSDevs - 1);
00169         ASSERT_THROW(device, "failed to acquire last device");
00170 
00171         int nTypes = mgr->getTypeCount();
00172         DPRINTF("Found %d types", nTypes);
00173         for (int i = 0; i < nTypes; ++i) {
00174                 smart_ptr<gamepad::Type> type = mgr->getType(i);
00175                 ASSERT_THROW(type, "failed to acquire type " << i);
00176         }
00177 
00178         int nMaps = mgr->getMappingCount();
00179         DPRINTF("Found %d mappings", nMaps);
00180 
00181         for (int i = 0; i < nMaps; ++i) {
00182                 smart_ptr<gamepad::Map> map = mgr->getMapping(i);
00183                 ASSERT_THROW(map, "Failed to acquire mapping " << i);
00184         }
00185 
00186         // now loop and keep looking for gamepads/devices
00187         // NOTE: this isn't a perfect example!  In an attempt to avoid
00188         //   additional UI concerns, I haven't supported multiple gampepads
00189         //   per source device.  In the real world, you'll want to do that.
00190         //   There are a lot of USB devices that support multiple gamepads.
00191         const int desiredHz = 100;
00192         long msSleep = 1000 / desiredHz;
00193         DPRINTF("Want sampling at %d Hz, so polling every %d ms",
00194             desiredHz, (int) msSleep);
00195 
00196         // how often do we poll for new devices?
00197         const int deviceHz = 2;
00198         const int checkCounter = desiredHz / deviceHz;
00199         DPRINTF("Will look for new source devices every %d iterations",
00200             checkCounter);
00201         int counter = 0;
00202 
00203         // now loop
00204         gamepad_map_t gamepads;
00205         while (s_keepLooping) {
00206                 sleepMilliseconds(msSleep);
00207 
00208                 ++counter;
00209                 if (!(counter % checkCounter)) {
00210                         mgr->rediscover();
00211                         int newCount = mgr->getSourceDeviceCount();
00212                         if (newCount != nSDevs) {
00213                                 DPRINTF("Device count: %d", newCount);
00214                         }
00215                         nSDevs = newCount;
00216 
00217                         // loop through all devices and see if we already have a
00218                         //      gamepad.
00219                         VecString badIds;
00220                         for (int i = 0; i < nSDevs; ++i) {
00221                                 smart_ptr<gamepad::SourceDevice> device =
00222                                     mgr->getSourceDevice(i);
00223                                 ASSERT_THROW(device, "null");
00224                                 const char * id = device->getUniqueId();
00225 
00226                                 // is this device gone?
00227                                 if (gamepad::eDevice_Detached == device->getState()) {
00228                                         badIds.push_back(id);
00229                                         continue;
00230                                 }
00231 
00232                                 // not gone.  Do we already know about it?
00233                                 if (gamepads.end() != gamepads.find(id)) {
00234                                         continue;       // already have this
00235                                 }
00236 
00237                                 // need to create gamepad for this source
00238                                 // device!
00239                                 smart_ptr<gamepad::Gamepad> gpad =
00240                                     createDefaultGamepad(mgr, device);
00241                                 // ASSERT(gpad) -- can be null!
00242                                 gamepads[id] = gpad;
00243                         }
00244 
00245                         // nuke any detached devices
00246                         for (VecString::iterator i = badIds.begin();
00247                              i != badIds.end(); ++i) {
00248                                 gamepad_map_t::iterator bad =
00249                                     gamepads.find(*i);
00250                                 ASSERT(gamepads.end() != bad,
00251                                     "bad device not in gamepad map");
00252                                 gamepads.erase(bad);
00253                         }
00254 
00255                         //DPRINTF("Have %d gamepads", gamepads.size());
00256                 }
00257 
00258                 mgr->update();
00259 
00260                 // loop through all gamepad objects
00261                 for (gamepad_map_t::iterator i = gamepads.begin();
00262                      i != gamepads.end(); ++i) {
00263                         gamepad::Gamepad * gpad = i->second;
00264                         if (!gpad)
00265                                 continue;       // no gamepad for device
00266 
00267                         const gamepad::Type * type = gpad->getType();
00268                         ASSERT(type, "null type");
00269 
00270                         gamepad::buttons_t buttons = gpad->getButtons();
00271                         if (buttons) {
00272                                 printButtons(buttons, gpad->getType());
00273                         }
00274                 }
00275         }
00276         DPRINTF("---- Stopping due to signal ----");
00277 }
00278 
00279 
00280 
00281 ////////////////////////////////////////////////////////////////////////////////
00282 //
00283 //      entry point
00284 //
00285 ////////////////////////////////////////////////////////////////////////////////
00286 
00287 int
00288 main
00289 (
00290 IN int argc,
00291 IN const char * argv[]
00292 )
00293 {
00294         int result = 0;
00295 
00296         ASSERT(2 == argc, "Usage: gamepad-test-manager <data-directory>");
00297         const char * dataDir = argv[1];
00298         DPRINTF("Using data directory: '%s'", dataDir);
00299 
00300 #ifndef WIN32
00301         struct sigaction sigact;
00302         sigact.sa_handler = handleSignal;
00303         sigact.sa_flags = 0;
00304         sigemptyset(&sigact.sa_mask);
00305         sigaction(SIGINT, &sigact, NULL);
00306         sigaction(SIGHUP, &sigact, NULL);
00307 #endif  // WIN32
00308 
00309         try {
00310                 perf::Timer timer("overall timer");
00311 
00312                 doTest(dataDir);
00313 
00314         } catch (std::exception& e) {
00315                 DPRINTF("Exception: %s", e.what());
00316                 result = 1;
00317         }
00318 
00319         perf::dumpTimingSummary(std::cerr);
00320 
00321         return result;
00322 }
00323