828 lines
22 KiB
C
828 lines
22 KiB
C
/*
|
|
* Copyright (c) 2015 Yamaha Corporation
|
|
*
|
|
* This software is provided 'as-is', without any express or implied
|
|
* warranty. In no event will the authors be held liable for any damages
|
|
* arising from the use of this software.
|
|
*
|
|
* Permission is granted to anyone to use this software for any purpose,
|
|
* including commercial applications, and to alter it and redistribute it
|
|
* freely, subject to the following restrictions:
|
|
*
|
|
* 1. The origin of this software must not be misrepresented; you must not
|
|
* claim that you wrote the original software. If you use this software
|
|
* in a product, an acknowledgment in the product documentation would be
|
|
* appreciated but is not required.
|
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
|
* misrepresented as being the original software.
|
|
* 3. This notice may not be removed or altered from any source distribution.
|
|
*/
|
|
|
|
#include "yas.h"
|
|
|
|
#if YAS_MAG_DRIVER == YAS_MAG_DRIVER_YAS539
|
|
|
|
#define YAS539_REG_DIDR (0x80)
|
|
#define YAS539_REG_CMDR (0x81)
|
|
#define YAS539_REG_RCOILR (0x82)
|
|
#define YAS539_REG_INTRVLR (0x83)
|
|
#define YAS539_REG_RCAUTOR (0x85)
|
|
#define YAS539_REG_AVRR (0x87)
|
|
#define YAS539_REG_SRSTR (0x90)
|
|
#define YAS539_REG_ADCCALR (0x91)
|
|
#define YAS539_REG_TRMR (0x9f)
|
|
#define YAS539_REG_RCDRVR (0xa0)
|
|
#define YAS539_REG_RCCURR (0xaa)
|
|
#define YAS539_REG_DATAR (0xb0)
|
|
#define YAS539_REG_CALR (0xc0)
|
|
|
|
#define YAS539_DATA_UNDERFLOW (0)
|
|
#define YAS539_DATA_OVERFLOW (32767)
|
|
#define YAS539_DEVICE_ID (0x08) /* YAS539 (MS-3S) */
|
|
|
|
#define YAS_X_OVERFLOW (0x01)
|
|
#define YAS_X_UNDERFLOW (0x02)
|
|
#define YAS_Y1_OVERFLOW (0x04)
|
|
#define YAS_Y1_UNDERFLOW (0x08)
|
|
#define YAS_Y2_OVERFLOW (0x10)
|
|
#define YAS_Y2_UNDERFLOW (0x20)
|
|
#define YAS_OVERFLOW (YAS_X_OVERFLOW|YAS_Y1_OVERFLOW|YAS_Y2_OVERFLOW)
|
|
#define YAS_UNDERFLOW (YAS_X_UNDERFLOW|YAS_Y1_UNDERFLOW|YAS_Y2_UNDERFLOW)
|
|
|
|
#define YAS539_MAG_STATE_NORMAL (0)
|
|
#define YAS539_MAG_STATE_INIT_COIL (1)
|
|
#define YAS539_MAG_INITCOIL_TIMEOUT (1000) /* msec */
|
|
#define YAS539_MAG_POWER_ON_RESET_TIME (4000) /* usec */
|
|
#define YAS539_MAG_SOFT_RESET_TIME (150) /* usec */
|
|
#define YAS539_MAG_NOTRANS_POSITION (3)
|
|
|
|
#define YAS539_MAG_AVERAGE_16 (0)
|
|
#define YAS539_MAG_AVERAGE_64 (1)
|
|
#define YAS539_MAG_AVERAGE_128 (2)
|
|
#define YAS539_MAG_AVERAGE_256 (3)
|
|
|
|
#define YAS539_MAG_RCOIL_TIME0 (65)
|
|
#define YAS539_MAG_RCOIL_TIME3 (550)
|
|
#define YAS539_MAG_RCOIL_RETRY (2)
|
|
#define YAS539_MAG_TEST_TIME (5000) /* usec */
|
|
|
|
#define set_vector(to, from) \
|
|
{int _l; for (_l = 0; _l < 3; _l++) (to)[_l] = (from)[_l]; }
|
|
|
|
struct yas_cdriver {
|
|
int initialized;
|
|
struct yas_driver_callback cbk;
|
|
int measure_state;
|
|
int invalid_data;
|
|
uint32_t invalid_data_time;
|
|
int position;
|
|
int32_t delay;
|
|
int enable;
|
|
uint8_t dev_id;
|
|
const int8_t *transform;
|
|
int average;
|
|
uint32_t current_time;
|
|
uint16_t last_raw[4];
|
|
uint16_t last_after_rcoil[3];
|
|
int16_t overflow[3], underflow[3];
|
|
struct yas_matrix static_matrix;
|
|
int noise_rcoil_flag;
|
|
int flowflag;
|
|
};
|
|
|
|
static const struct yas_matrix no_conversion
|
|
= { {10000, 0, 0, 0, 10000, 0, 0, 0, 10000} };
|
|
static const int measure_time_worst[] = {682, 1210, 2387, 4752};
|
|
|
|
static const int8_t YAS539_TRANSFORMATION[][9] = {
|
|
{ 0, 1, 0, -1, 0, 0, 0, 0, 1 },
|
|
{-1, 0, 0, 0, -1, 0, 0, 0, 1 },
|
|
{ 0, -1, 0, 1, 0, 0, 0, 0, 1 },
|
|
{ 1, 0, 0, 0, 1, 0, 0, 0, 1 },
|
|
{ 0, -1, 0, -1, 0, 0, 0, 0, -1 },
|
|
{ 1, 0, 0, 0, -1, 0, 0, 0, -1 },
|
|
{ 0, 1, 0, 1, 0, 0, 0, 0, -1 },
|
|
{-1, 0, 0, 0, 1, 0, 0, 0, -1 },
|
|
};
|
|
static struct yas_cdriver driver;
|
|
|
|
static int yas_set_enable_wrap(int enable, int rcoil);
|
|
static int yas_set_enable(int enable);
|
|
static int single_read(int *busy, uint16_t *t, uint16_t *xy1y2, int *ouflow);
|
|
|
|
static int yas_open(void)
|
|
{
|
|
if (driver.cbk.device_open(YAS_TYPE_MAG) < 0)
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
driver.cbk.usleep(YAS539_MAG_POWER_ON_RESET_TIME);
|
|
return YAS_NO_ERROR;
|
|
}
|
|
#define yas_read(a, b, c) \
|
|
(driver.cbk.device_read(YAS_TYPE_MAG, (a), (b), (c)))
|
|
static int yas_single_write(uint8_t addr, uint8_t data)
|
|
{
|
|
return driver.cbk.device_write(YAS_TYPE_MAG, addr, &data, 1);
|
|
}
|
|
|
|
static void apply_matrix(struct yas_vector *xyz, struct yas_matrix *m)
|
|
{
|
|
int32_t tmp[3];
|
|
int i;
|
|
if (m == NULL)
|
|
return;
|
|
for (i = 0; i < 3; i++)
|
|
tmp[i] = ((m->m[i*3]/10) * (xyz->v[0]/10)
|
|
+ (m->m[i*3+1]/10) * (xyz->v[1]/10)
|
|
+ (m->m[i*3+2]/10) * (xyz->v[2]/10)) / 100;
|
|
for (i = 0; i < 3; i++)
|
|
xyz->v[i] = tmp[i];
|
|
}
|
|
|
|
static uint32_t curtime(void)
|
|
{
|
|
if (driver.cbk.current_time)
|
|
return driver.cbk.current_time();
|
|
else
|
|
return driver.current_time;
|
|
}
|
|
|
|
static int invalid_magnetic_field(uint16_t *cur, uint16_t *last)
|
|
{
|
|
int16_t invalid_thresh[] = {2000, 2000, 2000};
|
|
int i;
|
|
for (i = 0; i < 3; i++)
|
|
if (invalid_thresh[i] <= ABS(cur[i] - last[i]))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
static int start_yas539(int tcsen, int cont)
|
|
{
|
|
uint8_t data = 0x81;
|
|
data = (uint8_t)(data | (cont<<5));
|
|
data = (uint8_t)(data | (tcsen<<6));
|
|
if (yas_single_write(YAS539_REG_CMDR, data) < 0)
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
return YAS_NO_ERROR;
|
|
}
|
|
|
|
static int cont_start_yas539(void)
|
|
{
|
|
if (start_yas539(0, 1) < 0)
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
/* wait for the first measurement */
|
|
driver.cbk.usleep(measure_time_worst[driver.average]);
|
|
return YAS_NO_ERROR;
|
|
}
|
|
|
|
static void sensitivity_correction(uint16_t *xy1y2, uint16_t t)
|
|
{
|
|
int32_t h[3];
|
|
int i;
|
|
for (i = 0; i < 3; i++) {
|
|
h[i] = (int32_t) xy1y2[i] - 16384;
|
|
h[i] = 100000 * h[i] / (100000 - 11 * (t - 8170));
|
|
xy1y2[i] = CLIP(h[i], -16384, 16383) + 16384;
|
|
}
|
|
}
|
|
|
|
static int read_yas539(int *busy, uint16_t *t, uint16_t *xy1y2, int *ouflow)
|
|
{
|
|
uint8_t data[8];
|
|
int i;
|
|
if (yas_read(YAS539_REG_DATAR, data, 8) < 0)
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
*t = (data[0]<<8) | data[1];
|
|
*busy = data[2]>>7;
|
|
xy1y2[0] = (uint16_t)(((data[2]&0x7f)<<8) | data[3]);
|
|
xy1y2[1] = (uint16_t)(((data[4]&0x7f)<<8) | data[5]);
|
|
xy1y2[2] = (uint16_t)(((data[6]&0x7f)<<8) | data[7]);
|
|
*ouflow = 0;
|
|
for (i = 0; i < 3; i++) {
|
|
if (driver.overflow[i] <= xy1y2[i])
|
|
*ouflow |= (1<<(i*2));
|
|
if (xy1y2[i] <= driver.underflow[i])
|
|
*ouflow |= (1<<(i*2+1));
|
|
driver.last_raw[i] = xy1y2[i];
|
|
}
|
|
driver.last_raw[i] = *t;
|
|
return YAS_NO_ERROR;
|
|
}
|
|
|
|
static int update_intrvlr(int32_t delay)
|
|
{
|
|
int ds = (delay * 1000 - measure_time_worst[driver.average]) / 1000;
|
|
int l, h;
|
|
if (ds < 1)
|
|
ds = 1;
|
|
for (l = 0; l < 7; l++) {
|
|
if (16 * (1<<l) < ds)
|
|
continue;
|
|
else
|
|
break;
|
|
}
|
|
for (h = 15; 0 < h; h--) {
|
|
if (ds < (h+1) * (1<<l))
|
|
continue;
|
|
else
|
|
break;
|
|
}
|
|
if (yas_single_write(YAS539_REG_INTRVLR, (h<<3) | l) < 0)
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
return YAS_NO_ERROR;
|
|
}
|
|
|
|
static int update_avrr(int average)
|
|
{
|
|
static const uint8_t avrr[] = {0x05, 0x2d, 0x2e, 0x2f};
|
|
if (yas_single_write(YAS539_REG_AVRR, avrr[average]) < 0)
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
return YAS_NO_ERROR;
|
|
}
|
|
|
|
static int rcoil(int mode, int rnum)
|
|
{
|
|
if (yas_single_write(YAS539_REG_RCDRVR, mode == 0 ? 0x00 : 0x01) < 0)
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
if (yas_single_write(YAS539_REG_RCOILR, 0x0a | ((rnum&0x3)<<6)) < 0)
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
if (rnum == 0)
|
|
driver.cbk.usleep(YAS539_MAG_RCOIL_TIME0);
|
|
else
|
|
driver.cbk.usleep(YAS539_MAG_RCOIL_TIME3);
|
|
return YAS_NO_ERROR;
|
|
}
|
|
|
|
static int rcoil_and_record_data(int flowflag, uint16_t *xy1y2, int *ouflow)
|
|
{
|
|
uint16_t t;
|
|
int rt, busy;
|
|
|
|
if (flowflag) {
|
|
if (rcoil(0, 0) < 0)
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
if (rcoil(1, 3) < 0)
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
} else {
|
|
if (rcoil(1, 0) < 0)
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
}
|
|
rt = single_read(&busy, &t, xy1y2, ouflow);
|
|
if (rt < 0)
|
|
return rt;
|
|
if (busy)
|
|
return YAS_ERROR_BUSY;
|
|
sensitivity_correction(xy1y2, t);
|
|
set_vector(driver.last_after_rcoil, xy1y2);
|
|
return YAS_NO_ERROR;
|
|
}
|
|
|
|
static int enable_rcoil(void)
|
|
{
|
|
uint16_t xy1y2[3], xy1y2_after[3], t;
|
|
int rt, busy, overflow;
|
|
|
|
rt = single_read(&busy, &t, xy1y2, &overflow);
|
|
if (rt < 0)
|
|
return rt;
|
|
if (busy)
|
|
return YAS_ERROR_BUSY;
|
|
sensitivity_correction(xy1y2, t);
|
|
if (!overflow) {
|
|
rt = rcoil_and_record_data(0, xy1y2_after, &overflow);
|
|
if (rt < 0)
|
|
return rt;
|
|
if (!overflow && !invalid_magnetic_field(xy1y2, xy1y2_after))
|
|
return 1;
|
|
}
|
|
rt = rcoil_and_record_data(1, xy1y2, &overflow);
|
|
if (rt < 0)
|
|
return rt;
|
|
if (overflow)
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
static int reset_yas539(void)
|
|
{
|
|
if (yas_single_write(YAS539_REG_SRSTR, 0x80) < 0)
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
driver.cbk.usleep(YAS539_MAG_SOFT_RESET_TIME);
|
|
if (yas_single_write(YAS539_REG_ADCCALR, 0x03) < 0)
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
if (yas_single_write(YAS539_REG_ADCCALR+1, 0xe0) < 0)
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
if (yas_single_write(YAS539_REG_TRMR, 0xff) < 0)
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
if (yas_single_write(YAS539_REG_RCAUTOR, 0x8a) < 0)
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
if (yas_single_write(YAS539_REG_RCCURR, 0x03) < 0)
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
if (update_intrvlr(driver.delay) < 0)
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
if (update_avrr(driver.average) < 0)
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
return YAS_NO_ERROR;
|
|
}
|
|
|
|
static int single_read(int *busy, uint16_t *t, uint16_t *xy1y2, int *ouflow)
|
|
{
|
|
if (start_yas539(0, 0) < 0)
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
driver.cbk.usleep(measure_time_worst[driver.average]);
|
|
if (read_yas539(busy, t, xy1y2, ouflow) < 0)
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
return YAS_NO_ERROR;
|
|
}
|
|
|
|
static void xy1y2_to_xyz(uint16_t *xy1y2, int32_t *xyz)
|
|
{
|
|
xyz[0] = ((int32_t)xy1y2[0] - 16384) * 150;
|
|
xyz[1] = ((int32_t)xy1y2[1] - xy1y2[2]) * 866 / 10;
|
|
xyz[2] = ((int32_t)-xy1y2[1] - xy1y2[2] + 32768) * 150;
|
|
}
|
|
|
|
static int sensitivity_measuremnet(uint16_t *xy1y2)
|
|
{
|
|
uint16_t t;
|
|
int rt, busy, ouflow;
|
|
rt = start_yas539(1, 0);
|
|
if (rt < 0)
|
|
return rt;
|
|
driver.cbk.usleep(YAS539_MAG_TEST_TIME);
|
|
rt = read_yas539(&busy, &t, xy1y2, &ouflow);
|
|
if (rt < 0)
|
|
return rt;
|
|
if (busy)
|
|
return YAS_ERROR_BUSY;
|
|
return YAS_NO_ERROR;
|
|
}
|
|
|
|
static int yas_get_position(void)
|
|
{
|
|
if (!driver.initialized)
|
|
return YAS_ERROR_INITIALIZE;
|
|
return driver.position;
|
|
}
|
|
|
|
static int yas_set_position(int position)
|
|
{
|
|
if (!driver.initialized)
|
|
return YAS_ERROR_INITIALIZE;
|
|
if (position < 0 || 7 < position)
|
|
return YAS_ERROR_ARG;
|
|
if (position == YAS539_MAG_NOTRANS_POSITION)
|
|
driver.transform = NULL;
|
|
else
|
|
driver.transform = YAS539_TRANSFORMATION[position];
|
|
driver.position = position;
|
|
return YAS_NO_ERROR;
|
|
}
|
|
|
|
static int yas_measure(struct yas_data *data, int num, int *ouflow)
|
|
{
|
|
int32_t xyz_tmp[3];
|
|
int i, busy, rt;
|
|
uint16_t xy1y2[3], t;
|
|
uint32_t tm;
|
|
*ouflow = 0;
|
|
if (!driver.initialized)
|
|
return YAS_ERROR_INITIALIZE;
|
|
if (data == NULL || num < 0)
|
|
return YAS_ERROR_ARG;
|
|
if (driver.cbk.current_time == NULL)
|
|
driver.current_time += (uint32_t)driver.delay;
|
|
if (num == 0)
|
|
return 0;
|
|
if (!driver.enable)
|
|
return 0;
|
|
if (driver.measure_state == YAS539_MAG_STATE_INIT_COIL) {
|
|
tm = curtime();
|
|
if (YAS539_MAG_INITCOIL_TIMEOUT
|
|
<= tm - driver.invalid_data_time) {
|
|
driver.invalid_data_time = tm;
|
|
/* stop the continuous measurement */
|
|
if (yas_single_write(YAS539_REG_CMDR, 0x00) < 0)
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
rt = rcoil_and_record_data(driver.flowflag, xy1y2,
|
|
ouflow);
|
|
if (rt < 0)
|
|
return rt;
|
|
if (!*ouflow) {
|
|
driver.flowflag = 0;
|
|
driver.invalid_data = 0;
|
|
driver.measure_state = YAS539_MAG_STATE_NORMAL;
|
|
}
|
|
if (cont_start_yas539() < 0)
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
}
|
|
}
|
|
if (read_yas539(&busy, &t, xy1y2, ouflow) < 0)
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
sensitivity_correction(xy1y2, t);
|
|
xy1y2_to_xyz(xy1y2, data->xyz.v);
|
|
if (driver.transform != NULL) {
|
|
for (i = 0; i < 3; i++) {
|
|
xyz_tmp[i] = driver.transform[i*3] * data->xyz.v[0]
|
|
+ driver.transform[i*3+1] * data->xyz.v[1]
|
|
+ driver.transform[i*3+2] * data->xyz.v[2];
|
|
}
|
|
set_vector(data->xyz.v, xyz_tmp);
|
|
}
|
|
apply_matrix(&data->xyz, &driver.static_matrix);
|
|
for (i = 0; i < 3; i++) {
|
|
data->xyz.v[i] -= data->xyz.v[i] % 10;
|
|
if (*ouflow & (1<<(i*2)))
|
|
data->xyz.v[i] += 1; /* set overflow */
|
|
if (*ouflow & (1<<(i*2+1)))
|
|
data->xyz.v[i] += 2; /* set underflow */
|
|
}
|
|
tm = curtime();
|
|
data->type = YAS_TYPE_MAG;
|
|
if (driver.cbk.current_time)
|
|
data->timestamp = tm;
|
|
else
|
|
data->timestamp = 0;
|
|
data->accuracy = 0;
|
|
if (busy)
|
|
return YAS_ERROR_BUSY;
|
|
if (*ouflow || invalid_magnetic_field(xy1y2, driver.last_after_rcoil)) {
|
|
if (!driver.invalid_data) {
|
|
driver.invalid_data_time = tm;
|
|
driver.invalid_data = 1;
|
|
}
|
|
if (*ouflow)
|
|
driver.flowflag = 1;
|
|
driver.measure_state = YAS539_MAG_STATE_INIT_COIL;
|
|
for (i = 0; i < 3; i++) {
|
|
if (!*ouflow)
|
|
data->xyz.v[i] += 3;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int yas_measure_wrap(struct yas_data *data, int num)
|
|
{
|
|
int ouflow;
|
|
return yas_measure(data, num, &ouflow);
|
|
}
|
|
|
|
static int yas_get_delay(void)
|
|
{
|
|
if (!driver.initialized)
|
|
return YAS_ERROR_INITIALIZE;
|
|
return driver.delay;
|
|
}
|
|
|
|
static int yas_set_delay(int delay)
|
|
{
|
|
if (!driver.initialized)
|
|
return YAS_ERROR_INITIALIZE;
|
|
if (delay < 0)
|
|
return YAS_ERROR_ARG;
|
|
driver.delay = delay;
|
|
if (!driver.enable)
|
|
return YAS_NO_ERROR;
|
|
/* stop the continuous measurement */
|
|
if (yas_single_write(YAS539_REG_CMDR, 0x00) < 0)
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
if (update_intrvlr(driver.delay) < 0)
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
if (cont_start_yas539() < 0)
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
return YAS_NO_ERROR;
|
|
}
|
|
|
|
static int yas_get_enable(void)
|
|
{
|
|
if (!driver.initialized)
|
|
return YAS_ERROR_INITIALIZE;
|
|
return driver.enable;
|
|
}
|
|
|
|
static int yas_set_enable_wrap(int enable, int rcoil)
|
|
{
|
|
int rt;
|
|
if (!driver.initialized)
|
|
return YAS_ERROR_INITIALIZE;
|
|
enable = !!enable;
|
|
if (driver.enable == enable)
|
|
return YAS_NO_ERROR;
|
|
if (enable) {
|
|
if (yas_open() < 0)
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
rt = reset_yas539();
|
|
if (rt < 0) {
|
|
driver.cbk.device_close(YAS_TYPE_MAG);
|
|
return rt;
|
|
}
|
|
if (rcoil) {
|
|
rt = enable_rcoil();
|
|
if (rt < 0) {
|
|
driver.cbk.device_close(YAS_TYPE_MAG);
|
|
return rt;
|
|
}
|
|
if (rt) {
|
|
driver.flowflag = 0;
|
|
driver.invalid_data = 0;
|
|
driver.measure_state = YAS539_MAG_STATE_NORMAL;
|
|
} else {
|
|
driver.invalid_data_time = curtime();
|
|
driver.flowflag = 1;
|
|
driver.invalid_data = 1;
|
|
driver.measure_state
|
|
= YAS539_MAG_STATE_INIT_COIL;
|
|
}
|
|
}
|
|
if (cont_start_yas539() < 0) {
|
|
driver.cbk.device_close(YAS_TYPE_MAG);
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
}
|
|
} else {
|
|
yas_single_write(YAS539_REG_CMDR, 0x00);
|
|
driver.cbk.device_close(YAS_TYPE_MAG);
|
|
}
|
|
driver.enable = enable;
|
|
return YAS_NO_ERROR;
|
|
}
|
|
|
|
static int yas_set_enable(int enable)
|
|
{
|
|
return yas_set_enable_wrap(enable, 1);
|
|
}
|
|
|
|
static int yas_ext(int32_t cmd, void *p)
|
|
{
|
|
struct yas539_self_test_result *r;
|
|
struct yas_data data;
|
|
int32_t *xyz;
|
|
int16_t *ouflow, *m;
|
|
int8_t average;
|
|
int rt, i, enable, overflow, busy, position;
|
|
uint16_t xy1y2[3], t;
|
|
if (!driver.initialized)
|
|
return YAS_ERROR_INITIALIZE;
|
|
if (p == NULL)
|
|
return YAS_ERROR_ARG;
|
|
switch (cmd) {
|
|
case YAS539_SELF_TEST:
|
|
r = (struct yas539_self_test_result *) p;
|
|
r->id = driver.dev_id;
|
|
enable = driver.enable;
|
|
if (!enable) {
|
|
if (yas_open() < 0)
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
}
|
|
rt = reset_yas539();
|
|
if (rt < 0)
|
|
goto self_test_exit;
|
|
rt = enable_rcoil();
|
|
if (rt < 0)
|
|
goto self_test_exit;
|
|
rt = single_read(&busy, &t, xy1y2, &overflow);
|
|
if (rt < 0)
|
|
goto self_test_exit;
|
|
if (busy) {
|
|
rt = YAS_ERROR_BUSY;
|
|
goto self_test_exit;
|
|
}
|
|
sensitivity_correction(xy1y2, t);
|
|
xy1y2_to_xyz(xy1y2, r->xyz);
|
|
for (i = 0; i < 3; i++)
|
|
r->xyz[i] = r->xyz[i] / 1000;
|
|
if (overflow & YAS_OVERFLOW) {
|
|
rt = YAS_ERROR_OVERFLOW;
|
|
goto self_test_exit;
|
|
}
|
|
if (overflow & YAS_UNDERFLOW) {
|
|
rt = YAS_ERROR_UNDERFLOW;
|
|
goto self_test_exit;
|
|
}
|
|
if (r->xyz[0] == 0 && r->xyz[1] == 0 && r->xyz[2] == 0) {
|
|
rt = YAS_ERROR_DIRCALC;
|
|
goto self_test_exit;
|
|
}
|
|
r->dir = 99;
|
|
rt = sensitivity_measuremnet(r->sxy1y2);
|
|
if (rt < 0)
|
|
goto self_test_exit;
|
|
rt = YAS_NO_ERROR;
|
|
self_test_exit:
|
|
if (enable)
|
|
cont_start_yas539();
|
|
else
|
|
driver.cbk.device_close(YAS_TYPE_MAG);
|
|
return rt;
|
|
case YAS539_SELF_TEST_NOISE:
|
|
xyz = (int32_t *) p;
|
|
enable = driver.enable;
|
|
if (!enable) {
|
|
if (driver.noise_rcoil_flag)
|
|
rt = yas_set_enable_wrap(1, 1);
|
|
else
|
|
rt = yas_set_enable_wrap(1, 0);
|
|
if (rt < 0)
|
|
return rt;
|
|
driver.noise_rcoil_flag = 0;
|
|
}
|
|
position = yas_get_position();
|
|
yas_set_position(YAS539_MAG_NOTRANS_POSITION);
|
|
rt = yas_measure(&data, 1, &overflow);
|
|
yas_set_position(position);
|
|
if (rt < 0) {
|
|
if (!enable)
|
|
yas_set_enable(0);
|
|
return rt;
|
|
}
|
|
for (i = 0; i < 3; i++)
|
|
xyz[i] = data.xyz.v[i] / 150;
|
|
if (!enable)
|
|
yas_set_enable(0);
|
|
return YAS_NO_ERROR;
|
|
case YAS539_GET_LAST_RAWDATA:
|
|
for (i = 0; i < 4; i++)
|
|
((uint16_t *) p)[i] = driver.last_raw[i];
|
|
return YAS_NO_ERROR;
|
|
case YAS539_GET_AVERAGE_SAMPLE:
|
|
*(int8_t *) p = driver.average;
|
|
return YAS_NO_ERROR;
|
|
case YAS539_SET_AVERAGE_SAMPLE:
|
|
average = *(int8_t *) p;
|
|
if (average < YAS539_MAG_AVERAGE_16
|
|
|| YAS539_MAG_AVERAGE_256 < average)
|
|
return YAS_ERROR_ARG;
|
|
driver.average = average;
|
|
if (!driver.enable)
|
|
return YAS_NO_ERROR;
|
|
/* stop the continuous measurement */
|
|
if (yas_single_write(YAS539_REG_CMDR, 0x00) < 0)
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
if (update_avrr(driver.average) < 0)
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
if (cont_start_yas539() < 0)
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
return YAS_NO_ERROR;
|
|
case YAS539_GET_STATIC_MATRIX:
|
|
m = (int16_t *) p;
|
|
for (i = 0; i < 9; i++)
|
|
m[i] = driver.static_matrix.m[i];
|
|
return YAS_NO_ERROR;
|
|
case YAS539_SET_STATIC_MATRIX:
|
|
m = (int16_t *) p;
|
|
for (i = 0; i < 9; i++)
|
|
driver.static_matrix.m[i] = m[i];
|
|
return YAS_NO_ERROR;
|
|
case YAS539_GET_OUFLOW_THRESH:
|
|
ouflow = (int16_t *) p;
|
|
for (i = 0; i < 3; i++) {
|
|
ouflow[i] = driver.overflow[i];
|
|
ouflow[i+3] = driver.underflow[i];
|
|
}
|
|
return YAS_NO_ERROR;
|
|
default:
|
|
break;
|
|
}
|
|
return YAS_ERROR_ARG;
|
|
}
|
|
|
|
static int yas_init(void)
|
|
{
|
|
static const int16_t h[] = {16000, 16256, 16512, 16768};
|
|
int i, cal_valid = 0;
|
|
uint8_t data[18];
|
|
int32_t c[3], a[9], f[3];
|
|
int32_t of[3], uf[3], eof[3], euf[3];
|
|
uint8_t k;
|
|
if (driver.initialized)
|
|
return YAS_ERROR_INITIALIZE;
|
|
if (yas_open() < 0)
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
if (yas_read(YAS539_REG_DIDR, data, 1) < 0) {
|
|
driver.cbk.device_close(YAS_TYPE_MAG);
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
}
|
|
driver.dev_id = data[0] & 0x7f;
|
|
if (driver.dev_id != YAS539_DEVICE_ID) {
|
|
driver.cbk.device_close(YAS_TYPE_MAG);
|
|
return YAS_ERROR_CHIP_ID;
|
|
}
|
|
if (yas_single_write(YAS539_REG_SRSTR, 0x80) < 0) {
|
|
driver.cbk.device_close(YAS_TYPE_MAG);
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
}
|
|
driver.cbk.usleep(YAS539_MAG_SOFT_RESET_TIME);
|
|
if (yas_read(YAS539_REG_CALR, data, 18) < 0) {
|
|
driver.cbk.device_close(YAS_TYPE_MAG);
|
|
return YAS_ERROR_DEVICE_COMMUNICATION;
|
|
}
|
|
for (i = 0; i < 13; i++)
|
|
if (data[i] != 0)
|
|
cal_valid = 1;
|
|
if (!cal_valid) {
|
|
driver.cbk.device_close(YAS_TYPE_MAG);
|
|
return YAS_ERROR_CALREG;
|
|
}
|
|
driver.cbk.device_close(YAS_TYPE_MAG);
|
|
|
|
c[0] = ((data[0]<<1) | (data[1]>>7)) - 256;
|
|
c[1] = (((data[1]<<2)&0x1fc) | (data[2]>>6)) - 256;
|
|
c[2] = (((data[2]<<3)&0x1f8) | (data[3]>>5)) - 256;
|
|
a[0] = 128;
|
|
a[1] = (((data[3]<<2)&0x7c) | (data[4]>>6)) - 64;
|
|
a[2] = (((data[4]<<1)&0x7e) | (data[5]>>7)) - 64;
|
|
a[3] = (((data[5]<<1)&0xfe) | (data[6]>>7)) - 128;
|
|
a[4] = (((data[6]<<2)&0x1fc) | (data[7]>>6)) - 112;
|
|
a[5] = (((data[7]<<1)&0x7e) | (data[8]>>7)) - 64;
|
|
a[6] = (((data[8]<<1)&0xfe) | (data[9]>>7)) - 128;
|
|
a[7] = (data[9]&0x7f) - 64;
|
|
a[8] = (((data[10]<<1)&0x1fe) | (data[11]>>7)) - 112;
|
|
k = data[11]&0x7f;
|
|
f[0] = (data[12]>>4)&0x03;
|
|
f[1] = (data[12]>>2)&0x03;
|
|
f[2] = data[12]&0x03;
|
|
for (i = 0; i < 3; i++) {
|
|
eof[i] = 32768 - h[f[i]] - ABS(c[i]) * 225 / 8;
|
|
euf[i] = h[f[i]] - ABS(c[i]) * 225 / 8;
|
|
}
|
|
of[0] = 16384 + k * (a[0] * eof[0] - ABS(a[1]) * eof[1]
|
|
- ABS(a[2]) * eof[2]) / 8192;
|
|
of[1] = 16384 + k * (-ABS(a[3]) * eof[0] + a[4] * eof[1]
|
|
- ABS(a[5]) * eof[2]) / 8192;
|
|
of[2] = 16384 + k * (-ABS(a[6]) * eof[0] - ABS(a[7]) * eof[1]
|
|
+ a[8] * eof[2]) / 8192;
|
|
uf[0] = 16384 - k * (a[0] * euf[0] - ABS(a[1]) * euf[1]
|
|
- ABS(a[2]) * euf[2]) / 8192;
|
|
uf[1] = 16384 - k * (-ABS(a[3]) * euf[0] + a[4] * euf[1]
|
|
- ABS(a[5]) * euf[2]) / 8192;
|
|
uf[2] = 16384 - k * (-ABS(a[6]) * euf[0] - ABS(a[7]) * euf[1]
|
|
+ a[8] * euf[2]) / 8192;
|
|
for (i = 0; i < 3; i++) {
|
|
if (YAS539_DATA_OVERFLOW < of[i])
|
|
driver.overflow[i] = YAS539_DATA_OVERFLOW;
|
|
else
|
|
driver.overflow[i] = (int16_t) of[i];
|
|
if (uf[i] < YAS539_DATA_UNDERFLOW)
|
|
driver.underflow[i] = YAS539_DATA_UNDERFLOW;
|
|
else
|
|
driver.underflow[i] = (int16_t) uf[i];
|
|
}
|
|
|
|
driver.measure_state = YAS539_MAG_STATE_NORMAL;
|
|
if (driver.cbk.current_time)
|
|
driver.current_time = driver.cbk.current_time();
|
|
else
|
|
driver.current_time = 0;
|
|
driver.invalid_data = 0;
|
|
driver.invalid_data_time = driver.current_time;
|
|
driver.position = YAS539_MAG_NOTRANS_POSITION;
|
|
driver.delay = YAS_DEFAULT_SENSOR_DELAY;
|
|
driver.enable = 0;
|
|
driver.transform = NULL;
|
|
driver.average = YAS539_MAG_AVERAGE_64;
|
|
driver.noise_rcoil_flag = 1;
|
|
driver.flowflag = 0;
|
|
for (i = 0; i < 3; i++)
|
|
driver.last_after_rcoil[i] = 0;
|
|
for (i = 0; i < 4; i++)
|
|
driver.last_raw[i] = 0;
|
|
driver.static_matrix = no_conversion;
|
|
driver.initialized = 1;
|
|
return YAS_NO_ERROR;
|
|
}
|
|
|
|
static int yas_term(void)
|
|
{
|
|
int rt;
|
|
if (!driver.initialized)
|
|
return YAS_ERROR_INITIALIZE;
|
|
rt = yas_set_enable(0);
|
|
driver.initialized = 0;
|
|
return rt;
|
|
}
|
|
|
|
int yas_mag_driver_init(struct yas_mag_driver *f)
|
|
{
|
|
if (f == NULL || f->callback.device_open == NULL
|
|
|| f->callback.device_close == NULL
|
|
|| f->callback.device_read == NULL
|
|
|| f->callback.device_write == NULL
|
|
|| f->callback.usleep == NULL)
|
|
return YAS_ERROR_ARG;
|
|
|
|
f->init = yas_init;
|
|
f->term = yas_term;
|
|
f->get_delay = yas_get_delay;
|
|
f->set_delay = yas_set_delay;
|
|
f->get_enable = yas_get_enable;
|
|
f->set_enable = yas_set_enable;
|
|
f->get_position = yas_get_position;
|
|
f->set_position = yas_set_position;
|
|
f->measure = yas_measure_wrap;
|
|
f->ext = yas_ext;
|
|
driver.cbk = f->callback;
|
|
yas_term();
|
|
return YAS_NO_ERROR;
|
|
}
|
|
#endif
|