Gadgeteer Wrapper

Now that we have explained the concepts involved in adding a device driver to Gadgeteer, we can show some code. The following example is for a fictitious piece of hardware that has only one button.

Example A.1. ButtonDevice.h

  1 #ifndef _MY_BUTTON_DEVICE_H_
    #define _MY_BUTTON_DEVICE_H_
    
    #include <gadget/Devices/DriverConfig.h>
  5 
    #include <stdlib.h>
    
    #include <vpr/vpr.h>
    #include <vpr/Thread/Thread.h>
 10 #include <gadget/Type/Input.h>
    #include <gadget/Type/Digital.h>
    #include <gadget/Type/InputMixer.h>
    
    
 15 class ButtonDevice
       : public gadget::InputMixer<gadget::Input, gadget::Digital>
    {
    public:
       ButtonDevice()
 20       : mSampleThread(NULL)
          , mRunning(false)
       {
          /* Do nothing. */ ;
       }
 25 
       virtual ~ButtonDevice()
       {
          if ( mRunning )
          {
 30          this->stopSampling();
          }
       }
    
       virtual void updateData();
 35    virtual bool startSampling();
       virtual bool sample();
       virtual bool stopSampling();
    
       static std::string getElementType();
 40 
       /**
        * Invokes the global scope delete operator.  This is required for proper
        * releasing of memory in DLLs on Win32.
        */
 45    void operator delete(void* p)
       {
          ::operator delete(p);
       }
    
 50 protected:
       /**
        * Deletes this object.  This is an implementation of the pure virtual
        * gadget::Input::destroy() method.
        */
 55    virtual void destroy()
       {
          delete this;
       }
    
 60 private:
       static void   sampleFunction(void* classPointer);
       int           mDigitalData;
       vpr::Thread*  mSampleThread;
    
 65    bool          mRunning;
    
       // configuration data set by config()
       std::string   mPortName;
       int           mBaudRate;
 70 };
    
    #endif

Example A.2. ButtonDevice.cpp

  1 #include <gadget/Devices/DriverConfig.h>
    
    #include <vpr/vpr.h>
    #include <vpr/System.h>
  5 #include <gadget/InputManager.h>
    #include <gadget/Type/DeviceConstructor.h>
    
    #include "ButtonDevice.h"
    
 10 
    using namespace gadget;
    
    extern "C"
    {
 15 
    GADGET_DRIVER_EXPORT(void) initDevice(InputManager* inputMgr)
    {
       new DeviceConstructor<ButtonDevice>(inputMgr);
    }
 20 
    }
    
    /** Returns a string that matches this device's configuration element type. */
    std::string ButtonDevice::getElementType()
 25 {
       return std::string("MyButtonDevice");
    }
    
    //: When the system detects a configuration change for your driver, it will
 30 //  pass the new jccl::ConfigElement into this function.  See the documentation
    //  on config elements, for information on how to access them.
    bool ButtonDevice::config(jccl::ConfigElementPtr e)
    {
      if ( ! Digital::config(e))
 35   {
         return false;
      }
    
      mPort = e->getProperty<std::string>("port");
 40   mBaud = e->getProperty<int>("baud");
    
      return true;
    }
    
 45 void ButtonDevice::updateData()
    {
       if ( mRunning )
       {
          swapDigitalBuffers();
 50    }
    }
    
    /**
     * Spanws the sample thread, which calls MyButtonDevice::sample() repeatedly.
 55  */
    bool ButtonDevice::startSampling()
    {
       mRunning = true;
       mSampleThread = new vpr::Thread(threadedSampleFunction, (void*) this);
 60 
       if ( ! mSampleThread->valid() )
       {
          mRunning = false;
          return false; // thread creation failed
 65    }
       else
       {
          return true; // thread creation success
       }
 70 }
    
    /**
     * Records (or samples) the current data.  This is called repeatedly by the
     * sample thread created by startSampling().
 75  */
    bool ButtonDevice::sample()
    {
       bool status(false);
    
 80    if ( mRunning )
       {
          // Here you would add your code to sample the hardware for a button
          // press:
          std::vector<DigitalData> samples(1);
 85       samples[0] = 1;
          addDigitalSample(samples);
    
          // Successful sample.
          status = true;
 90    }
    
       return status;
    }
    
 95 /** Kills the sample thread. */
    bool ButtonDevice::stopSampling()
    {
       mRunning = false;
    
100    if (mSampleThread != NULL)
       {
          mSampleThread->kill(); // Not guaranteed to work on all platforms
          mSampleThread->join();
          delete mSampleThread;
105       mSampleThread = NULL;
       }
       return true;
    }
    
110 /**
     * Our sampling function that is executed by the spawned sample thread.
     * This function is declared as a static member of MyButtonDevice.  It simply
     * calls MyButtonDevice::sample() over and over.
     */
115 void ButtonDevice::threadedSampleFunction(void* classPointer)
    {
       ButtonDevice* this_ptr = static_cast<ButtonDevice*>( classPointer );
    
       // spin until someone kills "mSampleThread"
120    while ( this_ptr->mRunning )
       {
         this_ptr->sample();
         vpr::System::sleep(1); //specify some time here, so you don't waste CPU cycles
       }
125 }