nunchuck: C port; FTI; C++ wraps C

Some API changes were made as well, see docs/apichanges.md.

Signed-off-by: Jon Trulson <jtrulson@ics.com>
This commit is contained in:
Jon Trulson 2017-01-31 13:06:26 -07:00
parent 1bbb9386b7
commit 0749f130e1
15 changed files with 740 additions and 214 deletions

View File

@ -4,6 +4,14 @@ API Changes {#apichanges}
Here's a list of other API changes made to the library that break source/binary Here's a list of other API changes made to the library that break source/binary
compatibility between releases: compatibility between releases:
* **nunchuck** This driver no longer supports the init() function.
All initialization is now done in the C nunchuck_init() function,
or the C++ constructor. In addition, the *NUNCHUCK_I2C_ADDR*
define is no longer exposed, as it is not possible to use any other
I2C address than *0x52*. The readBytes() and writeByte() functions
are also no longer exposed, since aside from what the driver does
to initialize and read data, there are no other options available.
* **enc03r** This driver no longer supports the value() function. In * **enc03r** This driver no longer supports the value() function. In
addition, an update() function has been added. This function must be addition, an update() function has been added. This function must be
called prior to calling angularVelocity(). angularVelocity() no called prior to calling angularVelocity(). angularVelocity() no

View File

@ -43,37 +43,29 @@ int main(int argc, char **argv)
signal(SIGINT, sig_handler); signal(SIGINT, sig_handler);
//! [Interesting] //! [Interesting]
// Instantiate a nunchuck controller bus 0 // Instantiate a nunchuck controller bus 3
upm::NUNCHUCK *nunchuck = new upm::NUNCHUCK(0); upm::NUNCHUCK *nunchuck = new upm::NUNCHUCK(3);
// always do this first
cout << "Initializing... " << endl;
if (!nunchuck->init())
{
cerr << "nunchuck->init() failed." << endl;
return 0;
}
while (shouldRun) while (shouldRun)
{ {
nunchuck->update(); nunchuck->update();
cout << "stickX: " << nunchuck->stickX cout << "stickX: " << nunchuck->stickX
<< ", stickY: " << nunchuck->stickY << endl; << ", stickY: " << nunchuck->stickY << endl;
cout << "accelX: " << nunchuck->accelX cout << "accelX: " << nunchuck->accelX
<< ", accelY: " << nunchuck->accelY << ", accelY: " << nunchuck->accelY
<< ", accelZ: " << nunchuck->accelZ << endl; << ", accelZ: " << nunchuck->accelZ << endl;
cout << "button C: " cout << "button C: "
<< ((nunchuck->buttonC) ? "pressed" : "not pressed") << endl; << ((nunchuck->buttonC) ? "pressed" : "not pressed") << endl;
cout << "button Z: " cout << "button Z: "
<< ((nunchuck->buttonZ) ? "pressed" : "not pressed") << endl; << ((nunchuck->buttonZ) ? "pressed" : "not pressed") << endl;
cout << endl; cout << endl;
usleep(100000); usleep(100000);
} }
//! [Interesting] //! [Interesting]
delete nunchuck; delete nunchuck;
return 0; return 0;
} }

View File

@ -148,6 +148,7 @@ add_example (cjq4435)
add_example (hmc5883l) add_example (hmc5883l)
add_example (wfs) add_example (wfs)
add_example (enc03r) add_example (enc03r)
add_example (nunchuck)
# Custom examples # Custom examples
add_custom_example (nmea_gps_i2c-example-c nmea_gps_i2c.c nmea_gps) add_custom_example (nmea_gps_i2c-example-c nmea_gps_i2c.c nmea_gps)

84
examples/c/nunchuck.c Normal file
View File

@ -0,0 +1,84 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2015 Intel Corporation.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <upm_utilities.h>
#include "nunchuck.h"
bool shouldRun = true;
void sig_handler(int signo)
{
if (signo == SIGINT)
shouldRun = false;
}
int main(int argc, char **argv)
{
signal(SIGINT, sig_handler);
//! [Interesting]
// Instantiate a nunchuck controller bus 3
nunchuck_context sensor = nunchuck_init(3);
if (!sensor)
{
printf("%s: nunchuck_init() failed\n", __FUNCTION__);
return 1;
}
while (shouldRun)
{
if (nunchuck_update(sensor))
{
printf("%s: nunchuck_update() failed\n", __FUNCTION__);
nunchuck_close(sensor);
return 1;
}
int x, y, z;
nunchuck_get_stick(sensor, &x, &y);
printf("stickX: %d stickY: %d\n", x, y);
nunchuck_get_acceleration(sensor, &x, &y, &z);
printf("accelX: %d accelY: %d accelZ: %d\n", x, y, z);
bool bc, bz;
nunchuck_get_buttons(sensor, &bc, &bz);
printf("button C: %s\n",
((bc) ? "pressed" : "not pressed"));
printf("button Z: %s\n\n",
((bz) ? "pressed" : "not pressed"));
upm_delay_ms(100);
}
nunchuck_close(sensor);
//! [Interesting]
return 0;
}

View File

@ -24,38 +24,38 @@
public class NUNCHUCKSample { public class NUNCHUCKSample {
public static void main(String[] args) throws InterruptedException { public static void main(String[] args) throws InterruptedException {
// ! [Interesting] // ! [Interesting]
// Instantiate a nunchuck controller bus 0 // Instantiate a nunchuck controller bus 0
upm_nunchuck.NUNCHUCK nunchuck = new upm_nunchuck.NUNCHUCK(0); upm_nunchuck.NUNCHUCK nunchuck = new upm_nunchuck.NUNCHUCK(3);
// always do this first while (true)
System.out.println("Initializing... "); {
if (!nunchuck.init()) { nunchuck.update();
System.err.println("nunchuck->init() failed."); System.out.println("stickX: "
return; + nunchuck.getStickX()
} + ", stickY: "
+ nunchuck.getStickY());
System.out.println("accelX: "
+ nunchuck.getAccelX()
+ ", accelY: "
+ nunchuck.getAccelY()
+ ", accelZ: "
+ nunchuck.getAccelZ());
while (true) { if (nunchuck.getButtonC())
nunchuck.update(); System.out.println("Button C pressed");
System.out.println("stickX: " + nunchuck.getStickX() + ", stickY: " else
+ nunchuck.getStickY()); System.out.println("Button C not pressed");
System.out.println("accelX: " + nunchuck.getAccelX() + ", accelY: "
+ nunchuck.getAccelY() + ", accelZ: " + nunchuck.getAccelZ());
if (nunchuck.getButtonC()) if (nunchuck.getButtonZ())
System.out.println("Button C pressed"); System.out.println("Button Z pressed");
else else
System.out.println("Button C not pressed"); System.out.println("Button Z not pressed");
if (nunchuck.getButtonZ()) Thread.sleep(100);
System.out.println("Button Z pressed"); }
else // ! [Interesting]
System.out.println("Button Z not pressed"); }
Thread.sleep(1000); }
}
// ! [Interesting]
}
}

View File

@ -24,16 +24,8 @@
var nunchuck_lib = require('jsupm_nunchuck'); var nunchuck_lib = require('jsupm_nunchuck');
// Instantiate a nunchuck controller bus 0 // Instantiate a nunchuck controller bus 3
var nunchuck_obj = new nunchuck_lib.NUNCHUCK(0); var nunchuck_obj = new nunchuck_lib.NUNCHUCK(3);
// always do this first
console.log("Initializing... ");
if (!nunchuck_obj.init())
{
console.log("nunchuck->init() failed.");
process.exit(0);
}
setInterval(function() setInterval(function()
{ {

View File

@ -26,8 +26,8 @@ import time, sys, signal, atexit
from upm import pyupm_nunchuck as upmNunchuck from upm import pyupm_nunchuck as upmNunchuck
def main(): def main():
# Instantiate a nunchuck controller bus 0 on I2C # Instantiate a nunchuck controller bus 3 on I2C
myNunchuck = upmNunchuck.NUNCHUCK(0) myNunchuck = upmNunchuck.NUNCHUCK(3)
## Exit handlers ## ## Exit handlers ##
# This function stops python from printing a stacktrace when you hit control-C # This function stops python from printing a stacktrace when you hit control-C
@ -43,12 +43,6 @@ def main():
atexit.register(exitHandler) atexit.register(exitHandler)
signal.signal(signal.SIGINT, SIGINTHandler) signal.signal(signal.SIGINT, SIGINTHandler)
# always do this first
print("Initializing... ")
if (not myNunchuck.init()):
print("nunchuck->init() failed.")
sys.exit(0);
def buttonStateStr(buttonState): def buttonStateStr(buttonState):
return "pressed" if buttonState else "not pressed" return "pressed" if buttonState else "not pressed"

46
include/fti/upm_buttons.h Normal file
View File

@ -0,0 +1,46 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2017 Intel Corporation.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef UPM_BUTTONS_H_
#define UPM_BUTTONS_H_
#ifdef __cplusplus
extern "C" {
#endif
// Buttons function table
typedef struct _upm_buttons_ft {
// This function is used to query button state. The num_button
// specifies the total number of buttons present, and the values
// indicates each button's current value as an array of bools.
upm_result_t (*upm_buttons_get_num_buttons) (const void *dev,
unsigned int *num_buttons);
upm_result_t (*upm_buttons_get_values) (const void *dev,
bool *values);
} upm_buttons_ft;
#ifdef __cplusplus
}
#endif
#endif /* UPM_BUTTONS_H_ */

View File

@ -75,7 +75,8 @@ typedef enum {
UPM_STREAM, UPM_STREAM,
UPM_ORP, UPM_ORP,
UPM_BINARY, UPM_BINARY,
UPM_ROTARYENCODER UPM_ROTARYENCODER,
UPM_BUTTONS
} upm_sensor_t; } upm_sensor_t;
/* Supported IO protocols via MRAA */ /* Supported IO protocols via MRAA */
@ -127,6 +128,8 @@ typedef struct _upm_sensor_ft* (*func_get_upm_sensor_ft)(upm_sensor_t sensor_typ
#include <fti/upm_pressure.h> #include <fti/upm_pressure.h>
#include <fti/upm_compass.h> #include <fti/upm_compass.h>
#include <fti/upm_gyroscope.h> #include <fti/upm_gyroscope.h>
#include <fti/upm_buttons.h>
#include <fti/upm_joystick.h>
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -1,5 +1,9 @@
set (libname "nunchuck") upm_mixed_module_init (NAME nunchuck
set (libdescription "Wii nunchuck module") DESCRIPTION "I2C nunchuck driver"
set (module_src ${libname}.cxx) C_HDR nunchuck.h
set (module_hpp ${libname}.hpp) C_SRC nunchuck.c
upm_module_init() CPP_HDR nunchuck.hpp
CPP_SRC nunchuck.cxx
FTI_SRC nunchuck_fti.c
CPP_WRAPS_C
REQUIRES mraa)

206
src/nunchuck/nunchuck.c Normal file
View File

@ -0,0 +1,206 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2017 Intel Corporation.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include "nunchuck.h"
// This is not changeable
#define NUNCHUCK_I2C_ADDR 0x52
// static functions for r/w the device. No user-serviceable parts
// inside.
static upm_result_t nunchuck_write_byte(const nunchuck_context dev,
uint8_t reg, uint8_t byte)
{
assert(dev != NULL);
if (mraa_i2c_write_byte_data(dev->i2c, byte, reg))
{
printf("%s: mraa_i2c_write_byte_data() failed\n", __FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
return UPM_SUCCESS;
}
static int nunchuck_read_bytes(const nunchuck_context dev, uint8_t reg,
uint8_t *buffer, int len)
{
assert(dev != NULL);
if (!len || !buffer)
return 0;
if (mraa_i2c_write_byte(dev->i2c, reg))
{
printf("%s: mraa_i2c_write_byte() failed\n", __FUNCTION__);
return -1;
}
return mraa_i2c_read(dev->i2c, buffer, len);
}
// init
nunchuck_context nunchuck_init(int bus)
{
// make sure MRAA is initialized
int mraa_rv;
if ((mraa_rv = mraa_init()) != MRAA_SUCCESS)
{
printf("%s: mraa_init() failed (%d).\n", __FUNCTION__, mraa_rv);
return NULL;
}
nunchuck_context dev =
(nunchuck_context)malloc(sizeof(struct _nunchuck_context));
if (!dev)
return NULL;
memset((void *)dev, 0, sizeof(struct _nunchuck_context));
// setup our i2c link
if ( !(dev->i2c = mraa_i2c_init(bus)) )
{
printf("%s: mraa_i2c_init() failed\n", __FUNCTION__);
nunchuck_close(dev);
return NULL;
}
if (mraa_i2c_address(dev->i2c, NUNCHUCK_I2C_ADDR))
{
printf("%s: mraa_i2c_address() failed\n", __FUNCTION__);
nunchuck_close(dev);
return NULL;
}
// sleep for a second to let things settle
upm_delay(1);
// disable encryption
if (nunchuck_write_byte(dev, 0xf0, 0x55)
|| nunchuck_write_byte(dev, 0xfb, 0x00))
{
printf("%s: nunchuck_write_byte() failed\n", __FUNCTION__);
nunchuck_close(dev);
return NULL;
}
return dev;
}
void nunchuck_close(nunchuck_context dev)
{
assert(dev != NULL);
if (dev->i2c)
mraa_i2c_stop(dev->i2c);
free(dev);
}
upm_result_t nunchuck_update(const nunchuck_context dev)
{
assert(dev != NULL);
const int bufsize = 6;
uint8_t buf[bufsize];
int rv;
rv = nunchuck_read_bytes(dev, 0x00, buf, bufsize);
if (rv != bufsize)
{
printf("%s: nunchuck_read_bytes() failed. Expected %d, got %d.\n",
__FUNCTION__, bufsize, rv);
return UPM_ERROR_OPERATION_FAILED;
}
// analog stick X
dev->stickX = buf[0];
// analog stick Y
dev->stickY = buf[1];
// accelerometer X
dev->accelX = ( (buf[2] << 2) | ((buf[5] & 0x0c) >> 2) );
// accelerometer Y
dev->accelY = ( (buf[3] << 2) | ((buf[5] & 0x30) >> 4) );
// accelerometer Z
dev->accelZ = ( (buf[4] << 2) | ((buf[5] & 0xc0) >> 6) );
// buttonC
if (buf[5] & 0x02)
dev->buttonC = false;
else
dev->buttonC = true;
// buttonZ
if (buf[5] & 0x01)
dev->buttonZ = false;
else
dev->buttonZ = true;
return UPM_SUCCESS;
}
void nunchuck_get_stick(const nunchuck_context dev, int *x, int *y)
{
assert(dev != NULL);
if (x)
*x = dev->stickX;
if (y)
*y = dev->stickY;
}
void nunchuck_get_acceleration(const nunchuck_context dev,
int *x, int *y, int *z)
{
assert(dev != NULL);
if (x)
*x = dev->accelX;
if (y)
*y = dev->accelY;
if (z)
*z = dev->accelZ;
}
void nunchuck_get_buttons(const nunchuck_context dev, bool *c, bool *z)
{
assert(dev != NULL);
if (c)
*c = dev->buttonC;
if (z)
*z = dev->buttonZ;
}

View File

@ -1,6 +1,6 @@
/* /*
* Author: Jon Trulson <jtrulson@ics.com> * Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2015 Intel Corporation. * Copyright (c) 2015-2017 Intel Corporation.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -33,117 +33,27 @@ using namespace upm;
using namespace std; using namespace std;
NUNCHUCK::NUNCHUCK(int bus, uint8_t addr) NUNCHUCK::NUNCHUCK(int bus) :
m_nunchuck(nunchuck_init(bus))
{ {
stickX = 0; if (!m_nunchuck)
stickY = 0; throw std::runtime_error(string(__FUNCTION__)
accelX = 0; + ": nunchuck_init() failed");
accelY = 0;
accelZ = 0;
buttonC = false;
buttonZ = false;
// setup our i2c link
if ( !(m_i2c = mraa_i2c_init(bus)) )
{
throw std::invalid_argument(std::string(__FUNCTION__) +
": mraa_i2c_init() failed");
return;
}
mraa_result_t rv;
if ( (rv = mraa_i2c_address(m_i2c, addr)) != MRAA_SUCCESS )
{
throw std::invalid_argument(std::string(__FUNCTION__) +
": mraa_i2c_address() failed");
}
} }
NUNCHUCK::~NUNCHUCK() NUNCHUCK::~NUNCHUCK()
{ {
mraa_i2c_stop(m_i2c); nunchuck_close(m_nunchuck);
}
bool NUNCHUCK::writeByte(uint8_t reg, uint8_t byte)
{
mraa_result_t rv;
if ( (rv = mraa_i2c_write_byte_data(m_i2c, byte, reg)) != MRAA_SUCCESS )
{
throw std::runtime_error(std::string(__FUNCTION__) +
": mraa_i2c_write_byte_data() failed");
return false;
}
return true;
}
int NUNCHUCK::readBytes(uint8_t reg, uint8_t *buffer, int len)
{
if (!len || !buffer)
return 0;
mraa_i2c_address(m_i2c, NUNCHUCK_I2C_ADDR);
mraa_i2c_write_byte(m_i2c, reg);
return mraa_i2c_read(m_i2c, buffer, len);
}
bool NUNCHUCK::init()
{
usleep(1000000);
// disable encryption
if (!writeByte(0xf0, 0x55))
return false;
if (!writeByte(0xfb, 0x00))
return false;
return true;
} }
void NUNCHUCK::update() void NUNCHUCK::update()
{ {
const int bufsize = 6; if (nunchuck_update(m_nunchuck))
uint8_t buf[bufsize]; throw std::runtime_error(string(__FUNCTION__)
int rv; + ": nunchuck_update() failed");
rv = readBytes(0x00, buf, bufsize); nunchuck_get_stick(m_nunchuck, &stickX, &stickY);
nunchuck_get_acceleration(m_nunchuck, &accelX, &accelY, &accelZ);
if (rv != bufsize) nunchuck_get_buttons(m_nunchuck, &buttonC, &buttonZ);
{
throw std::runtime_error(std::string(__FUNCTION__) +
": readBytes() failed");
return;
}
// analog stick X
stickX = buf[0];
// analog stick Y
stickY = buf[1];
// accelerometer X
accelX = ( (buf[2] << 2) | ((buf[5] & 0x0c) >> 2) );
// accelerometer Y
accelY = ( (buf[3] << 2) | ((buf[5] & 0x30) >> 4) );
// accelerometer Z
accelZ = ( (buf[4] << 2) | ((buf[5] & 0xc0) >> 6) );
// buttonC
if (buf[5] & 0x02)
buttonC = false;
else
buttonC = true;
// buttonZ
if (buf[5] & 0x01)
buttonZ = false;
else
buttonZ = true;
} }

123
src/nunchuck/nunchuck.h Normal file
View File

@ -0,0 +1,123 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2017 Intel Corporation.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include <stdlib.h>
#include <stdio.h>
#include <upm.h>
#include <mraa/i2c.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file nunchuck.h
* @library nunchuck
* @brief C API for the nunchuck driver
*
* @include nunchuck.c
*/
/**
* Device context
*/
typedef struct _nunchuck_context {
mraa_i2c_context i2c;
// sticks - x, y
int stickX;
int stickY;
// accel
int accelX;
int accelY;
int accelZ;
// buttons
bool buttonC;
bool buttonZ;
} *nunchuck_context;
/**
* NUNCHUCK constructor
*
* @param bus I2C bus to use
* @return A Device context, or NULL on error
*/
nunchuck_context nunchuck_init(int bus);
/**
* Close the device and deallocate all resources.
*
* @param dev Device context
*/
void nunchuck_close(nunchuck_context dev);
/**
* Reads and updates the current state of the controller.
*
* @param dev Device context
* @return UPM result
*/
upm_result_t nunchuck_update(const nunchuck_context dev);
/**
* Returns the current analog stick X and Y positions.
* nunchuck_update() must have been called prior to calling this
* function.
*
* @param dev Device context
* @param x Pointer in which the X value will be stored
* @param y Pointer in which the Y value will be stored
*/
void nunchuck_get_stick(const nunchuck_context dev, int *x, int *y);
/**
* Returns the current accelerometer values. nunchuck_update()
* must have been called prior to calling this function.
*
* @param dev Device context
* @param x Pointer in which the X value will be stored
* @param y Pointer in which the Y value will be stored
* @param z Pointer in which the Z value will be stored
*/
void nunchuck_get_acceleration(const nunchuck_context dev,
int *x, int *y, int *z);
/**
* Returns the current button values values. nunchuck_update()
* must have been called prior to calling this function.
*
* @param dev Device context
* @param c Pointer in which the C button value will be stored
* @param z Pointer in which the Z button value will be stored
*/
void nunchuck_get_buttons(const nunchuck_context dev, bool *c, bool *z);
#ifdef __cplusplus
}
#endif

View File

@ -1,6 +1,6 @@
/* /*
* Author: Jon Trulson <jtrulson@ics.com> * Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2015 Intel Corporation. * Copyright (c) 2015-2017 Intel Corporation.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
@ -24,9 +24,8 @@
#pragma once #pragma once
#include <string> #include <string>
#include <mraa/i2c.h> #include "nunchuck.h"
#define NUNCHUCK_I2C_ADDR 0x52
namespace upm { namespace upm {
@ -48,17 +47,16 @@ namespace upm {
* @brief API for the Wii* Nunchuk controller * @brief API for the Wii* Nunchuk controller
* *
* UPM module for the Wii Nunchuk controller. This module was tested with * UPM module for the Wii Nunchuk controller. This module was tested with
* Wii Nunchuk connected to I2C via a Grove Wii Nunchuk adapter. * Wii Nunchuck connected to I2C via a Grove Wii Nunchuck adapter.
* *
* See http://wiibrew.org/wiki/Wiimote/Extension_Controllers and * See http://wiibrew.org/wiki/Wiimote/Extension_Controllers and
* http://wiibrew.org/wiki/Wiimote/Extension_Controllers/Nunchuck * http://wiibrew.org/wiki/Wiimote/Extension_Controllers/Nunchuck
* for more details on the controller and its protocol. * for more details on the controller and its protocol.
* *
* A warning for the Grove Wii Nunchuk adapter: it has 2 traces on one * A warning for the Grove Wii Nunchuk adapter: it has 2 traces on
* side, and 3 traces on the other. Do not match these up with the * one side, and 3 traces on the other. Do not match these up with
* Nunchuk connector's traces. The connector's 'Grove' * the Nunchuk connector's traces. The connector's 'groove' should
* should be on the same side as the Grove interface socket on the * be on the same side as the Grove interface socket on the adapter.
* adapter.
* *
* @image html nunchuck.jpg * @image html nunchuck.jpg
* @snippet nunchuck.cxx Interesting * @snippet nunchuck.cxx Interesting
@ -71,39 +69,12 @@ namespace upm {
* @param bus I2C bus to use * @param bus I2C bus to use
* @param addr I2C address to use * @param addr I2C address to use
*/ */
NUNCHUCK(int bus, uint8_t addr=NUNCHUCK_I2C_ADDR); NUNCHUCK(int bus);
/** /**
* NUNCHUCK destructor * NUNCHUCK destructor
*/ */
~NUNCHUCK(); virtual ~NUNCHUCK();
/**
* Writes value(s) into registers
*
* @param reg Register location to start writing into
* @param byte Byte to write
* @return True if successful
*/
bool writeByte(uint8_t reg, uint8_t byte);
/**
* Reads value(s) from registers
*
* @param reg Register location to start reading from
* @param buffer Buffer for data storage
* @param len Number of bytes to read
* @return Number of bytes read
*/
int readBytes(uint8_t reg, uint8_t *buffer, int len);
/**
* Initializes the controller. Here, we disable encryption after
* delaying for a time to ensure the controller is ready.
*
* @return True if initialization is successful
*/
bool init();
/** /**
* Reads and updates the current state of the controller. * Reads and updates the current state of the controller.
@ -153,8 +124,10 @@ namespace upm {
*/ */
bool buttonZ; bool buttonZ;
protected:
nunchuck_context m_nunchuck;
private: private:
mraa_i2c_context m_i2c;
}; };
} }

190
src/nunchuck/nunchuck_fti.c Normal file
View File

@ -0,0 +1,190 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* Copyright (c) 2017 Intel Corporation.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "nunchuck.h"
#include "upm_fti.h"
/**
* This file implements the Function Table Interface (FTI) for this sensor
*/
const char upm_nunchuck_name[] = "NUNCHUCK";
const char upm_nunchuck_description[] = "Nunchuck controller";
const upm_protocol_t upm_nunchuck_protocol[] = {UPM_I2C};
const upm_sensor_t upm_nunchuck_category[] =
{ UPM_ACCELEROMETER, UPM_JOYSTICK, UPM_BUTTONS};
// forward declarations
const void* upm_nunchuck_get_ft(upm_sensor_t sensor_type);
void* upm_nunchuck_init_name();
void upm_nunchuck_close(void *dev);
upm_result_t upm_nunchuck_get_accel_values(void *dev, float *value, upm_acceleration_u unit);
upm_result_t upm_nunchuck_get_joystick_value_x(const void *dev, float *value);
upm_result_t upm_nunchuck_get_joystick_value_y(const void *dev, float *value);
upm_result_t upm_nunchuck_get_num_buttons(const void *dev,
unsigned int *num_buttons);
upm_result_t upm_nunchuck_get_button_values(const void *dev,
bool *values);
const upm_sensor_descriptor_t upm_nunchuck_get_descriptor()
{
upm_sensor_descriptor_t usd;
usd.name = upm_nunchuck_name;
usd.description = upm_nunchuck_description;
usd.protocol_size = 1;
usd.protocol = upm_nunchuck_protocol;
usd.category_size = 3;
usd.category = upm_nunchuck_category;
return usd;
}
static const upm_sensor_ft ft =
{
.upm_sensor_init_name = upm_nunchuck_init_name,
.upm_sensor_close = upm_nunchuck_close,
};
static const upm_acceleration_ft aft =
{
.upm_acceleration_get_value = upm_nunchuck_get_accel_values
};
static const upm_joystick_ft jft =
{
.upm_joystick_get_value_x = upm_nunchuck_get_joystick_value_x,
.upm_joystick_get_value_y = upm_nunchuck_get_joystick_value_y
};
static const upm_buttons_ft bft =
{
.upm_buttons_get_num_buttons = upm_nunchuck_get_num_buttons,
.upm_buttons_get_values = upm_nunchuck_get_button_values
};
const void* upm_nunchuck_get_ft(upm_sensor_t sensor_type)
{
switch(sensor_type)
{
case UPM_SENSOR:
return &ft;
case UPM_ACCELEROMETER:
return &aft;
case UPM_JOYSTICK:
return &jft;
case UPM_BUTTONS:
return &bft;
default:
return NULL;
}
}
void* upm_nunchuck_init_name()
{
return NULL;
}
void upm_nunchuck_close(void *dev)
{
nunchuck_close((nunchuck_context)dev);
}
upm_result_t upm_nunchuck_get_accel_values(void *dev,
float *value,
upm_acceleration_u unit)
{
if (nunchuck_update((nunchuck_context)dev))
return UPM_ERROR_OPERATION_FAILED;
int x, y, z;
nunchuck_get_acceleration((nunchuck_context)dev, &x, &y, &z);
value[0] = (float)x;
value[1] = (float)y;
value[2] = (float)z;
return UPM_SUCCESS;
}
upm_result_t upm_nunchuck_get_joystick_value_x(const void *dev, float *value)
{
// This is bad - separating getting X and Y stick values... You
// can't be sure when updating for one axis whether the other
// changed... Should be fixed by having a single function return
// both values from the same sampletime. Same goes for the rest
// of the values reported.
if (nunchuck_update((nunchuck_context)dev))
return UPM_ERROR_OPERATION_FAILED;
int x;
nunchuck_get_stick((nunchuck_context)dev, &x, NULL);
*value = (float)x;
return UPM_SUCCESS;
}
upm_result_t upm_nunchuck_get_joystick_value_y(const void *dev, float *value)
{
// This is bad - separating getting X and Y stick values... You
// can't be sure when updating for one axis whether the other
// changed... Should be fixed by having a single function return
// both values from the same sampletime. Same goes for the rest
// of the values reported.
if (nunchuck_update((nunchuck_context)dev))
return UPM_ERROR_OPERATION_FAILED;
int y;
nunchuck_get_stick((nunchuck_context)dev, NULL, &y);
*value = (float)y;
return UPM_SUCCESS;
}
upm_result_t upm_nunchuck_get_num_buttons(const void *dev,
unsigned int *num_buttons)
{
// always 2 buttons (C and Z)
*num_buttons = 2;
return UPM_SUCCESS;
}
upm_result_t upm_nunchuck_get_button_values(const void *dev,
bool *values)
{
if (nunchuck_update((nunchuck_context)dev))
return UPM_ERROR_OPERATION_FAILED;
bool bc, bz;
nunchuck_get_buttons((nunchuck_context)dev, &bc, &bz);
// hope they passed a bool[2]....
values[0] = bc;
values[1] = bz;
return UPM_SUCCESS;
}