This brings in an implementation of some general matrix manipulation routines, not all of which are used at teh moment. Output the DCM on the UART at 50Hz for the host to display it usefully.
215 lines
4.6 KiB
C
215 lines
4.6 KiB
C
|
|
#include "wmp.h"
|
|
#include "i2c.h"
|
|
#include "uart.h"
|
|
#include "dcm.h"
|
|
|
|
#define WMP_ZERO_COUNT 100
|
|
|
|
unsigned char wmp_init_command[2] = {0xfe, 0x04};
|
|
|
|
i2c_result wmp_result;
|
|
unsigned int wmp_generation;
|
|
|
|
struct i2c_transaction wmp_init_transaction = {
|
|
(0x53 << 1) + 0, /* write */
|
|
2,
|
|
wmp_init_command,
|
|
&wmp_result,
|
|
NULL
|
|
};
|
|
|
|
unsigned char wmp_read_cal_command[1] = {0x20};
|
|
|
|
struct i2c_transaction wmp_read_cal_transaction2;
|
|
|
|
struct i2c_transaction wmp_read_cal_transaction = {
|
|
(0x53 << 1) + 0, /* write */
|
|
1,
|
|
wmp_read_cal_command,
|
|
&wmp_result,
|
|
&wmp_read_cal_transaction2
|
|
};
|
|
|
|
struct i2c_transaction wmp_read_cal_transaction2 = {
|
|
(0x53 << 1) + 1, /* read */
|
|
0x20,
|
|
wmp_calibration_data,
|
|
&wmp_result,
|
|
NULL
|
|
};
|
|
|
|
unsigned char wmp_sample_command[1] = {0x00};
|
|
|
|
unsigned char wmp_sample_data[6];
|
|
|
|
struct i2c_transaction wmp_sample_transaction2;
|
|
|
|
struct i2c_transaction wmp_sample_transaction = {
|
|
(0x52 << 1) + 0, /* write */
|
|
1,
|
|
wmp_sample_command,
|
|
&wmp_result,
|
|
&wmp_sample_transaction2
|
|
};
|
|
|
|
struct i2c_transaction wmp_sample_transaction2 = {
|
|
(0x52 << 1) + 1, /* read */
|
|
6,
|
|
wmp_sample_data,
|
|
&wmp_result,
|
|
NULL
|
|
};
|
|
|
|
|
|
bool wmp_init(void)
|
|
{
|
|
if (!i2c_start_transaction(&wmp_init_transaction))
|
|
return FALSE;
|
|
while (i2c_busy()) ;
|
|
return (wmp_result == I2C_SUCCESS);
|
|
}
|
|
|
|
unsigned char wmp_calibration_data[0x20];
|
|
|
|
bool wmp_read_calibration_data(void)
|
|
{
|
|
if (!i2c_start_transaction(&wmp_read_cal_transaction))
|
|
return FALSE;
|
|
while (i2c_busy());
|
|
return (wmp_result == I2C_SUCCESS);
|
|
}
|
|
|
|
unsigned int wmp_yaw;
|
|
unsigned int wmp_pitch;
|
|
unsigned int wmp_roll;
|
|
|
|
unsigned int wmp_yaw_zero;
|
|
unsigned int wmp_pitch_zero;
|
|
unsigned int wmp_roll_zero;
|
|
|
|
bool wmp_yaw_fast;
|
|
bool wmp_pitch_fast;
|
|
bool wmp_roll_fast;
|
|
|
|
bool wmp_update;
|
|
bool wmp_zero;
|
|
|
|
#define TWO_PI 6.28318531f
|
|
#define DEG_TO_RAD (TWO_PI/360.0f)
|
|
|
|
/* There's considerable debate about these values, and they may vary
|
|
* between different models of the Wii Motion Plus. It would be nice
|
|
* to be able to use the calibration data stored on the device itself
|
|
* but we don't know the format yet.
|
|
*/
|
|
#define SLOW_YAW_STEP (20 / DEG_TO_RAD)
|
|
#define SLOW_PITCH_STEP (20 / DEG_TO_RAD)
|
|
#define SLOW_ROLL_STEP (20 / DEG_TO_RAD)
|
|
#define FAST_YAW_STEP (4 / DEG_TO_RAD)
|
|
#define FAST_PITCH_STEP (4 / DEG_TO_RAD)
|
|
#define FAST_ROLL_STEP (4 / DEG_TO_RAD)
|
|
|
|
bool wmp_sample(void)
|
|
{
|
|
if (!i2c_start_transaction(&wmp_sample_transaction))
|
|
return FALSE;
|
|
|
|
while (i2c_busy());
|
|
|
|
if (wmp_result != I2C_SUCCESS)
|
|
return FALSE;
|
|
|
|
wmp_result = I2C_IN_PROGRESS;
|
|
|
|
wmp_yaw = ((wmp_sample_data[3]>>2)<<8) + wmp_sample_data[0];
|
|
wmp_pitch = ((wmp_sample_data[4]>>2)<<8) + wmp_sample_data[1];
|
|
wmp_roll = ((wmp_sample_data[5]>>2)<<8) + wmp_sample_data[2];
|
|
|
|
/* XXX We don't take into account the fast/slow mode flag here */
|
|
wmp_yaw_fast = !(wmp_sample_data[3] & 0x2);
|
|
wmp_pitch_fast = !(wmp_sample_data[3] & 0x1);
|
|
wmp_roll_fast = !(wmp_sample_data[4] & 0x2);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
bool wmp_start_sample(void)
|
|
{
|
|
return i2c_start_transaction(&wmp_sample_transaction);
|
|
}
|
|
|
|
void wmp_event_handler(void)
|
|
{
|
|
float yaw, pitch, roll;
|
|
|
|
if (wmp_result != I2C_SUCCESS)
|
|
return;
|
|
|
|
wmp_result = I2C_IN_PROGRESS;
|
|
|
|
wmp_yaw = ((wmp_sample_data[3]>>2)<<8) + wmp_sample_data[0];
|
|
wmp_pitch = ((wmp_sample_data[4]>>2)<<8) + wmp_sample_data[1];
|
|
wmp_roll = ((wmp_sample_data[5]>>2)<<8) + wmp_sample_data[2];
|
|
|
|
/* XXX We don't take into account the fast/slow mode flag here */
|
|
wmp_yaw_fast = !(wmp_sample_data[3] & 0x2);
|
|
wmp_pitch_fast = !(wmp_sample_data[3] & 0x1);
|
|
wmp_roll_fast = !(wmp_sample_data[4] & 0x2);
|
|
|
|
if (wmp_update) {
|
|
int tmp_yaw = wmp_yaw;
|
|
int tmp_pitch = wmp_pitch;
|
|
int tmp_roll = wmp_roll;
|
|
|
|
tmp_yaw -= wmp_yaw_zero;
|
|
tmp_pitch -= wmp_pitch_zero;
|
|
tmp_roll -= wmp_roll_zero;
|
|
|
|
if (wmp_yaw_fast)
|
|
yaw = ((float)tmp_yaw) / FAST_YAW_STEP;
|
|
else
|
|
yaw = ((float)tmp_yaw) / SLOW_YAW_STEP;
|
|
|
|
if (wmp_pitch_fast)
|
|
pitch = ((float)tmp_pitch) / FAST_PITCH_STEP;
|
|
else
|
|
pitch = ((float)tmp_pitch) / SLOW_PITCH_STEP;
|
|
|
|
if (wmp_roll_fast)
|
|
roll = ((float)tmp_roll) / FAST_ROLL_STEP;
|
|
else
|
|
roll = ((float)tmp_roll) / SLOW_ROLL_STEP;
|
|
|
|
dcm_update(roll, pitch, yaw);
|
|
|
|
wmp_generation++;
|
|
|
|
if ((wmp_generation % 2) == 0)
|
|
dcm_send_packet();
|
|
|
|
} else if (wmp_zero) {
|
|
wmp_yaw_zero += wmp_yaw;
|
|
wmp_pitch_zero += wmp_pitch;
|
|
wmp_roll_zero += wmp_roll;
|
|
wmp_generation++;
|
|
if (wmp_generation >= WMP_ZERO_COUNT) {
|
|
wmp_zero = FALSE;
|
|
wmp_update = TRUE;
|
|
wmp_generation = 0;
|
|
wmp_yaw_zero /= WMP_ZERO_COUNT;
|
|
wmp_pitch_zero /= WMP_ZERO_COUNT;
|
|
wmp_roll_zero /= WMP_ZERO_COUNT;
|
|
putstr("Zero finished\r\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
void wmp_start_zero(void)
|
|
{
|
|
wmp_zero = TRUE;
|
|
wmp_update = FALSE;
|
|
wmp_generation = 0;
|
|
putstr("Starting zero\r\n");
|
|
}
|