android13/hardware/rockchip/sensor/mpu_vr/akm8963/Measure.c

1359 lines
38 KiB
C
Executable File

/******************************************************************************
*
* $Id: Measure.c 327 2011-08-25 06:00:17Z yamada.rj $
*
* -- Copyright Notice --
*
* Copyright (c) 2004 Asahi Kasei Microdevices Corporation, Japan
* All Rights Reserved.
*
* This software program is proprietary program of Asahi Kasei Microdevices
* Corporation("AKM") licensed to authorized Licensee under Software License
* Agreement (SLA) executed between the Licensee and AKM.
*
* Use of the software by unauthorized third party, or use of the software
* beyond the scope of the SLA is strictly prohibited.
*
* -- End Asahi Kasei Microdevices Copyright Notice --
*
******************************************************************************/
#include "AKCommon.h"
#include "AK8963Driver.h"
#include "Measure.h"
#include "TestLimit.h"
#include "FileIO.h"
#include "DispMessage.h"
#include "misc.h"
extern int s_fdDev;
#define ACC_ACQ_FLAG_POS ACC_DATA_FLAG
#define MAG_ACQ_FLAG_POS MAG_DATA_FLAG
#define ORI_ACQ_FLAG_POS ORI_DATA_FLAG
#define ACC_MES_FLAG_POS 8
#define ACC_INT_FLAG_POS 9
#define MAG_MES_FLAG_POS 10
#define MAG_INT_FLAG_POS 11
#define SETTING_FLAG_POS 12
/* deg x (pi/180.0) */
#define DEG2RAD(deg) ((deg) * 0.017453292)
static FORM_CLASS* g_form = NULL;
/*!
This function open formation status device.
@return Return 0 on success. Negative value on fail.
*/
static int16 openForm(void)
{
if (g_form != NULL) {
if (g_form->open != NULL) {
return g_form->open();
}
}
// If function is not set, return success.
return 0;
}
/*!
This function close formation status device.
@return None.
*/
static void closeForm(void)
{
if (g_form != NULL) {
if (g_form->close != NULL) {
g_form->close();
}
}
}
/*!
This function check formation status
@return The index of formation.
*/
static int16 checkForm(void)
{
if (g_form != NULL) {
if (g_form->check != NULL) {
return g_form->check();
}
}
// If function is not set, return default value.
return 0;
}
/*!
This function registers the callback function.
@param[in]
*/
void RegisterFormClass(FORM_CLASS* pt)
{
g_form = pt;
}
/*!
Initialize #AK8963PRMS structure. At first, 0 is set to all parameters.
After that, some parameters, which should not be 0, are set to specific
value. Some of initial values can be customized by editing the file
\c "CustomerSpec.h".
@param[out] prms A pointer to #AK8963PRMS structure.
*/
void InitAK8963PRMS(AK8963PRMS* prms)
{
int i,j,k;
struct akm_platform_data pdata;
// Set 0 to the AK8963PRMS structure.
memset(prms, 0, sizeof(AK8963PRMS));
// Sensitivity
prms->m_hs.u.x = AKSC_HSENSE_TARGET;
prms->m_hs.u.y = AKSC_HSENSE_TARGET;
prms->m_hs.u.z = AKSC_HSENSE_TARGET;
// HDOE
prms->m_hdst = AKSC_HDST_UNSOLVED;
// (m_hdata is initialized with AKSC_InitDecomp8963)
prms->m_hnave = CSPEC_HNAVE;
prms->m_dvec.u.x = CSPEC_DVEC_X;
prms->m_dvec.u.y = CSPEC_DVEC_Y;
prms->m_dvec.u.z = CSPEC_DVEC_Z;
if (ioctl(s_fdDev, ECS_IOCTL_GET_PLATFORM_DATA, &pdata) >= 0)
{
// Form 0
prms->m_hlayout[0].u._11 = pdata.m_layout[0][0][0];
prms->m_hlayout[0].u._12 = pdata.m_layout[0][0][1];
prms->m_hlayout[0].u._13 = pdata.m_layout[0][0][2];
prms->m_hlayout[0].u._21 = pdata.m_layout[0][1][0];
prms->m_hlayout[0].u._22 = pdata.m_layout[0][1][1];
prms->m_hlayout[0].u._23 = pdata.m_layout[0][1][2];
prms->m_hlayout[0].u._31 = pdata.m_layout[0][2][0];
prms->m_hlayout[0].u._32 = pdata.m_layout[0][2][1];
prms->m_hlayout[0].u._33 = pdata.m_layout[0][2][2];
// Form 1
prms->m_hlayout[1].u._11 = pdata.m_layout[1][0][0];
prms->m_hlayout[1].u._12 = pdata.m_layout[1][0][1];
prms->m_hlayout[1].u._13 = pdata.m_layout[1][0][2];
prms->m_hlayout[1].u._21 = pdata.m_layout[1][1][0];
prms->m_hlayout[1].u._22 = pdata.m_layout[1][1][1];
prms->m_hlayout[1].u._23 = pdata.m_layout[1][1][2];
prms->m_hlayout[1].u._31 = pdata.m_layout[1][2][0];
prms->m_hlayout[1].u._32 = pdata.m_layout[1][2][1];
prms->m_hlayout[1].u._33 = pdata.m_layout[1][2][2];
//***********************************************
// Set ALAYOUT
//***********************************************
// Form 0
prms->m_alayout[0].u._11 = pdata.m_layout[2][0][0];
prms->m_alayout[0].u._12 = pdata.m_layout[2][0][1];
prms->m_alayout[0].u._13 = pdata.m_layout[2][0][2];
prms->m_alayout[0].u._21 = pdata.m_layout[2][1][0];
prms->m_alayout[0].u._22 = pdata.m_layout[2][1][1];
prms->m_alayout[0].u._23 = pdata.m_layout[2][1][2];
prms->m_alayout[0].u._31 = pdata.m_layout[2][2][0];
prms->m_alayout[0].u._32 = pdata.m_layout[2][2][1];
prms->m_alayout[0].u._33 = pdata.m_layout[2][2][2];
// Form 1
prms->m_alayout[1].u._11 = pdata.m_layout[3][0][0];
prms->m_alayout[1].u._12 = pdata.m_layout[3][0][1];
prms->m_alayout[1].u._13 = pdata.m_layout[3][0][2];
prms->m_alayout[1].u._21 = pdata.m_layout[3][1][0];
prms->m_alayout[1].u._22 = pdata.m_layout[3][1][1];
prms->m_alayout[1].u._23 = pdata.m_layout[3][1][2];
prms->m_alayout[1].u._31 = pdata.m_layout[3][2][0];
prms->m_alayout[1].u._32 = pdata.m_layout[3][2][1];
prms->m_alayout[1].u._33 = pdata.m_layout[3][2][2];
for(i=0; i<4; i++)
for(j=0; j<3; j++)
for(k=0; k<3; k++)
{
AKM_LOG("%s:m_layout[%d][%d][%d]=%d\n",__FUNCTION__,i,j,k,pdata.m_layout[i][j][k]);
}
}
else
{
//***********************************************
// Set HLAYOUT
//***********************************************
LOGD("%s:%s\n",__FUNCTION__,strerror(errno));
// Form 0
prms->m_hlayout[0].u._11 = CSPEC_FORM0_HLAYOUT_11;
prms->m_hlayout[0].u._12 = CSPEC_FORM0_HLAYOUT_12;
prms->m_hlayout[0].u._13 = CSPEC_FORM0_HLAYOUT_13;
prms->m_hlayout[0].u._21 = CSPEC_FORM0_HLAYOUT_21;
prms->m_hlayout[0].u._22 = CSPEC_FORM0_HLAYOUT_22;
prms->m_hlayout[0].u._23 = CSPEC_FORM0_HLAYOUT_23;
prms->m_hlayout[0].u._31 = CSPEC_FORM0_HLAYOUT_31;
prms->m_hlayout[0].u._32 = CSPEC_FORM0_HLAYOUT_32;
prms->m_hlayout[0].u._33 = CSPEC_FORM0_HLAYOUT_33;
// Form 1
prms->m_hlayout[1].u._11 = CSPEC_FORM1_HLAYOUT_11;
prms->m_hlayout[1].u._12 = CSPEC_FORM1_HLAYOUT_12;
prms->m_hlayout[1].u._13 = CSPEC_FORM1_HLAYOUT_13;
prms->m_hlayout[1].u._21 = CSPEC_FORM1_HLAYOUT_21;
prms->m_hlayout[1].u._22 = CSPEC_FORM1_HLAYOUT_22;
prms->m_hlayout[1].u._23 = CSPEC_FORM1_HLAYOUT_23;
prms->m_hlayout[1].u._31 = CSPEC_FORM1_HLAYOUT_31;
prms->m_hlayout[1].u._32 = CSPEC_FORM1_HLAYOUT_32;
prms->m_hlayout[1].u._33 = CSPEC_FORM1_HLAYOUT_33;
//***********************************************
// Set ALAYOUT
//***********************************************
// Form 0
prms->m_alayout[0].u._11 = CSPEC_FORM0_ALAYOUT_11;
prms->m_alayout[0].u._12 = CSPEC_FORM0_ALAYOUT_12;
prms->m_alayout[0].u._13 = CSPEC_FORM0_ALAYOUT_13;
prms->m_alayout[0].u._21 = CSPEC_FORM0_ALAYOUT_21;
prms->m_alayout[0].u._22 = CSPEC_FORM0_ALAYOUT_22;
prms->m_alayout[0].u._23 = CSPEC_FORM0_ALAYOUT_23;
prms->m_alayout[0].u._31 = CSPEC_FORM0_ALAYOUT_31;
prms->m_alayout[0].u._32 = CSPEC_FORM0_ALAYOUT_32;
prms->m_alayout[0].u._33 = CSPEC_FORM0_ALAYOUT_33;
// Form 1
prms->m_alayout[1].u._11 = CSPEC_FORM1_ALAYOUT_11;
prms->m_alayout[1].u._12 = CSPEC_FORM1_ALAYOUT_12;
prms->m_alayout[1].u._13 = CSPEC_FORM1_ALAYOUT_13;
prms->m_alayout[1].u._21 = CSPEC_FORM1_ALAYOUT_21;
prms->m_alayout[1].u._22 = CSPEC_FORM1_ALAYOUT_22;
prms->m_alayout[1].u._23 = CSPEC_FORM1_ALAYOUT_23;
prms->m_alayout[1].u._31 = CSPEC_FORM1_ALAYOUT_31;
prms->m_alayout[1].u._32 = CSPEC_FORM1_ALAYOUT_32;
prms->m_alayout[1].u._33 = CSPEC_FORM1_ALAYOUT_33;
}
}
/*!
Fill #AK8963PRMS structure with default value.
@param[out] prms A pointer to #AK8963PRMS structure.
*/
void SetDefaultPRMS(AK8963PRMS* prms)
{
int16 i;
// Set parameter to HDST, HO, HREF
for (i = 0; i < CSPEC_NUM_FORMATION; i++) {
prms->HSUC_HDST[i] = AKSC_HDST_UNSOLVED;
prms->HSUC_HO[i].u.x = 0;
prms->HSUC_HO[i].u.y = 0;
prms->HSUC_HO[i].u.z = 0;
prms->HFLUCV_HREF[i].u.x = 0;
prms->HFLUCV_HREF[i].u.y = 0;
prms->HFLUCV_HREF[i].u.z = 0;
prms->HSUC_HBASE[i].u.x = 0;
prms->HSUC_HBASE[i].u.y = 0;
prms->HSUC_HBASE[i].u.z = 0;
}
}
/*!
Get interval from device driver. This function will not resolve dependencies.
Dependencies will be resolved in Sensor HAL.
@param[out] mag_acq Magnetometer acquisition timing.
@param[out] acc_acq Accelerometer acquisition timing.
@param[out] ori_acq Orientation sensor acquisition timing.
@param[out] mag_mes Magnetometer measurement timing.
@param[out] acc_mes Accelerometer measurement timing.
@param[out] hdoe_interval HDOE decimator.
*/
int16 GetInterval(
AKMD_LOOP_TIME* acc_acq,
AKMD_LOOP_TIME* mag_acq,
AKMD_LOOP_TIME* ori_acq,
AKMD_LOOP_TIME* mag_mes,
AKMD_LOOP_TIME* acc_mes,
int16* hdoe_dec)
{
/* Accelerometer, Magnetometer, Orientation */
/* Delay is in nano second unit. */
/* Negative value means the sensor is disabled.*/
int64_t delay[AKM_NUM_SENSORS];
if (AKD_GetDelay(delay) < 0) {
return AKRET_PROC_FAIL;
}
AKMDATA(AKMDATA_GETINTERVAL,"delay=%lld,%lld,%lld\n",
delay[0], delay[1], delay[2]);
#ifdef AKMD_ACC_COMBINED
/* Accelerometer's interval limit */
if ((0 <= delay[0]) && (delay[0] <= AKMD_ACC_MIN_INTERVAL)) {
delay[0] = AKMD_ACC_MIN_INTERVAL;
}
#else
/* Always disabled */
delay[0] = -1;
#endif
/* Magnetmeter's frequency should be discrete value */
if ((0 <= delay[1]) && (delay[1] <= AKMD_MAG_MIN_INTERVAL)) {
delay[1] = AKMD_MAG_MIN_INTERVAL;
}
/* Orientation sensor's interval limit */
if ((0 <= delay[2]) && (delay[2] <= AKMD_ORI_MIN_INTERVAL)) {
delay[2] = AKMD_ORI_MIN_INTERVAL;
}
/* update */
if ((delay[0] != acc_acq->interval) ||
(delay[1] != mag_acq->interval) ||
(delay[2] != ori_acq->interval)) {
acc_acq->duration = acc_acq->interval = delay[0];
mag_acq->duration = mag_acq->interval = delay[1];
ori_acq->duration = ori_acq->interval = delay[2];
mag_mes->interval = mag_acq->interval;
mag_mes->duration = 0;
// Adjust frequency for HDOE
if (0 <= (mag_mes->interval)) {
GetHDOEDecimator(&(mag_mes->interval), hdoe_dec);
}
#ifndef AKMD_ACC_COMBINED
// Solve dependencies
if (ori_acq->interval >= 0) {
// Orientation is enabled
acc_mes->interval = ori_acq->interval;
acc_mes->duration = 0;
} else {
// Both are disabled
acc_mes->interval = -1;
acc_mes->duration = 0;
}
#endif
AKMDATA(AKMDATA_GETINTERVAL,
"%s:\n"
" AcqInterval(M,A,O,G)=%lld,%lld,%lld\n"
" MesInterval(M,A)=%lld,%lld\n",
__FUNCTION__,
mag_acq->interval, acc_acq->interval, ori_acq->interval,
mag_mes->interval, acc_mes->interval);
}
return AKRET_PROC_SUCCEED;
}
/*!
Calculate loop duration
@return If it is time to fire the event, the return value is 1, otherwise 0.
@param[in,out] tm An event.
@param[in] execTime The time to execute main loop for one time.
@param[in,out] minDuration The minimum sleep time in all events.
*/
int SetLoopTime(
AKMD_LOOP_TIME* tm,
int64_t execTime,
int64_t* minDuration)
{
int ret = 0;
if (tm->interval >= 0) {
tm->duration -= execTime;
if (tm->duration <= AKMD_LOOP_MARGIN) {
tm->duration = tm->interval;
ret = 1;
} else if (tm->duration < *minDuration) {
*minDuration = tm->duration;
}
}
return ret;
}
/*!
Read hard coded value (Fuse ROM) from AK8963. Then set the read value to
calculation parameter.
@return If parameters are read successfully, the return value is
#AKRET_PROC_SUCCEED. Otherwise the return value is #AKRET_PROC_FAIL. No
error code is reserved to show which operation has failed.
@param[out] prms A pointer to #AK8963PRMS structure.
*/
int16 ReadAK8963FUSEROM(AK8963PRMS* prms)
{
BYTE i2cData[6];
// Set to PowerDown mode
if (AKD_SetMode(AK8963_MODE_POWERDOWN) != AKD_SUCCESS) {
AKMERROR;
return AKRET_PROC_FAIL;
}
// Set to FUSE ROM access mode
if (AKD_SetMode(AK8963_MODE_FUSE_ACCESS) != AKD_SUCCESS) {
AKMERROR;
return AKRET_PROC_FAIL;
}
// Read values. ASAX, ASAY, ASAZ
if (AKD_RxData(AK8963_FUSE_ASAX, i2cData, 3) != AKD_SUCCESS) {
AKMERROR;
return AKRET_PROC_FAIL;
}
prms->m_asa.u.x = (int16)i2cData[0];
prms->m_asa.u.y = (int16)i2cData[1];
prms->m_asa.u.z = (int16)i2cData[2];
AKMDEBUG(DBG_LEVEL2, "%s: asa(dec)=%d,%d,%d\n", __FUNCTION__,
prms->m_asa.u.x, prms->m_asa.u.y, prms->m_asa.u.z);
// Set keywords for SmartCompassLibrary certification
prms->m_key[2] = (int16)i2cData[0];
prms->m_key[3] = (int16)i2cData[1];
prms->m_key[4] = (int16)i2cData[2];
// Set to PowerDown mode
if (AKD_SetMode(AK8963_MODE_POWERDOWN) != AKD_SUCCESS) {
AKMERROR;
return AKRET_PROC_FAIL;
}
// Set keywords for SmartCompassLibrary certification
if (AKD_RxData(AK8963_REG_WIA, i2cData, 1) != AKD_SUCCESS) {
AKMERROR;
return AKRET_PROC_FAIL;
}
prms->m_key[0] = CSPEC_CI_AK_DEVICE;
prms->m_key[1] = (int16)i2cData[0];
strncpy((char *)prms->m_licenser, CSPEC_CI_LICENSER, AKSC_CI_MAX_CHARSIZE);
strncpy((char *)prms->m_licensee, CSPEC_CI_LICENSEE, AKSC_CI_MAX_CHARSIZE);
AKMDEBUG(DBG_LEVEL2, "%s: key=%d, licenser=%s, licensee=%s\n",
__FUNCTION__, prms->m_key[1], prms->m_licenser, prms->m_licensee);
return AKRET_PROC_SUCCEED;
}
/*!
Set initial values to registers of AK8963. Then initialize algorithm
parameters.
@return If parameters are read successfully, the return value is
#AKRET_PROC_SUCCEED. Otherwise the return value is #AKRET_PROC_FAIL. No
error code is reserved to show which operation has failed.
@param[in,out] prms A pointer to a #AK8963PRMS structure.
*/
int16 InitAK8963_Measure(AK8963PRMS* prms)
{
// Reset device.
if (AKD_ResetAK8963() != AKD_SUCCESS) {
AKMERROR;
return AKRET_PROC_FAIL;
}
prms->m_form = checkForm();
// Restore the value when succeeding in estimating of HOffset.
prms->m_ho = prms->HSUC_HO[prms->m_form];
prms->m_ho32.u.x = (int32)prms->HSUC_HO[prms->m_form].u.x;
prms->m_ho32.u.y = (int32)prms->HSUC_HO[prms->m_form].u.y;
prms->m_ho32.u.z = (int32)prms->HSUC_HO[prms->m_form].u.z;
prms->m_hdst = prms->HSUC_HDST[prms->m_form];
prms->m_hbase = prms->HSUC_HBASE[prms->m_form];
// Initialize the decompose parameters
AKSC_InitDecomp8963(prms->m_hdata);
// Initialize HDOE parameters
AKSC_InitHDOEProcPrmsS3(
&prms->m_hdoev,
1,
&prms->m_ho,
prms->m_hdst
);
AKSC_InitHFlucCheck(
&(prms->m_hflucv),
&(prms->HFLUCV_HREF[prms->m_form]),
HFLUCV_TH
);
// Reset counter
prms->m_cntSuspend = 0;
prms->m_callcnt = 0;
LOGD("%s: m_form=%d", __FUNCTION__, prms->m_form);
return AKRET_PROC_SUCCEED;
}
/*!
Execute "Onboard Function Test" (includes "START" and "END" command).
@retval 1 The test is passed successfully.
@retval -1 The test is failed.
@retval 0 The test is aborted by kind of system error.
@param[in] prms A pointer to a #AK8963PRMS structure.
*/
int16 FctShipmntTest_Body(AK8963PRMS* prms)
{
int16 pf_total = 1;
//***********************************************
// Reset Test Result
//***********************************************
TEST_DATA(NULL, "START", 0, 0, 0, &pf_total);
//***********************************************
// Step 1 to 2
//***********************************************
pf_total = FctShipmntTestProcess_Body(prms);
//***********************************************
// Judge Test Result
//***********************************************
TEST_DATA(NULL, "END", 0, 0, 0, &pf_total);
return pf_total;
}
/*!
Execute "Onboard Function Test" (NOT includes "START" and "END" command).
@retval 1 The test is passed successfully.
@retval -1 The test is failed.
@retval 0 The test is aborted by kind of system error.
@param[in] prms A pointer to a #AK8963PRMS structure.
*/
int16 FctShipmntTestProcess_Body(AK8963PRMS* prms)
{
int16 pf_total; //p/f flag for this subtest
BYTE i2cData[16];
int16 hdata[3];
int16 asax;
int16 asay;
int16 asaz;
//***********************************************
// Reset Test Result
//***********************************************
pf_total = 1;
//***********************************************
// Step1
//***********************************************
// Reset device.
if (AKD_ResetAK8963() != AKD_SUCCESS) {
AKMERROR;
return 0;
}
// When the serial interface is SPI,
// write "00011011" to I2CDIS register(to disable I2C,).
if (CSPEC_SPI_USE == 1) {
i2cData[0] = 0x1B;
if (AKD_TxData(AK8963_REG_I2CDIS, i2cData, 1) != AKD_SUCCESS) {
AKMERROR;
return 0;
}
}
// Read values from WIA to ASTC.
if (AKD_RxData(AK8963_REG_WIA, i2cData, 13) != AKD_SUCCESS) {
AKMERROR;
return 0;
}
// TEST
TEST_DATA(TLIMIT_NO_RST_WIA, TLIMIT_TN_RST_WIA, (int16)i2cData[0], TLIMIT_LO_RST_WIA, TLIMIT_HI_RST_WIA, &pf_total);
TEST_DATA(TLIMIT_NO_RST_INFO, TLIMIT_TN_RST_INFO, (int16)i2cData[1], TLIMIT_LO_RST_INFO, TLIMIT_HI_RST_INFO, &pf_total);
TEST_DATA(TLIMIT_NO_RST_ST1, TLIMIT_TN_RST_ST1, (int16)i2cData[2], TLIMIT_LO_RST_ST1, TLIMIT_HI_RST_ST1, &pf_total);
TEST_DATA(TLIMIT_NO_RST_HXL, TLIMIT_TN_RST_HXL, (int16)i2cData[3], TLIMIT_LO_RST_HXL, TLIMIT_HI_RST_HXL, &pf_total);
TEST_DATA(TLIMIT_NO_RST_HXH, TLIMIT_TN_RST_HXH, (int16)i2cData[4], TLIMIT_LO_RST_HXH, TLIMIT_HI_RST_HXH, &pf_total);
TEST_DATA(TLIMIT_NO_RST_HYL, TLIMIT_TN_RST_HYL, (int16)i2cData[5], TLIMIT_LO_RST_HYL, TLIMIT_HI_RST_HYL, &pf_total);
TEST_DATA(TLIMIT_NO_RST_HYH, TLIMIT_TN_RST_HYH, (int16)i2cData[6], TLIMIT_LO_RST_HYH, TLIMIT_HI_RST_HYH, &pf_total);
TEST_DATA(TLIMIT_NO_RST_HZL, TLIMIT_TN_RST_HZL, (int16)i2cData[7], TLIMIT_LO_RST_HZL, TLIMIT_HI_RST_HZL, &pf_total);
TEST_DATA(TLIMIT_NO_RST_HZH, TLIMIT_TN_RST_HZH, (int16)i2cData[8], TLIMIT_LO_RST_HZH, TLIMIT_HI_RST_HZH, &pf_total);
TEST_DATA(TLIMIT_NO_RST_ST2, TLIMIT_TN_RST_ST2, (int16)i2cData[9], TLIMIT_LO_RST_ST2, TLIMIT_HI_RST_ST2, &pf_total);
TEST_DATA(TLIMIT_NO_RST_CNTL1, TLIMIT_TN_RST_CNTL1, (int16)i2cData[10], TLIMIT_LO_RST_CNTL1, TLIMIT_HI_RST_CNTL1, &pf_total);
TEST_DATA(TLIMIT_NO_RST_CNTL2, TLIMIT_TN_RST_CNTL2, (int16)i2cData[11], TLIMIT_LO_RST_CNTL2, TLIMIT_HI_RST_CNTL2, &pf_total);
TEST_DATA(TLIMIT_NO_RST_ASTC, TLIMIT_TN_RST_ASTC, (int16)i2cData[12], TLIMIT_LO_RST_ASTC, TLIMIT_HI_RST_ASTC, &pf_total);
// Read values from I2CDIS.
if (AKD_RxData(AK8963_REG_I2CDIS, i2cData, 1) != AKD_SUCCESS) {
AKMERROR;
return 0;
}
if (CSPEC_SPI_USE == 1) {
TEST_DATA(TLIMIT_NO_RST_I2CDIS, TLIMIT_TN_RST_I2CDIS, (int16)i2cData[0], TLIMIT_LO_RST_I2CDIS_USESPI, TLIMIT_HI_RST_I2CDIS_USESPI, &pf_total);
}else{
TEST_DATA(TLIMIT_NO_RST_I2CDIS, TLIMIT_TN_RST_I2CDIS, (int16)i2cData[0], TLIMIT_LO_RST_I2CDIS_USEI2C, TLIMIT_HI_RST_I2CDIS_USEI2C, &pf_total);
}
// Set to FUSE ROM access mode
if (AKD_SetMode(AK8963_MODE_FUSE_ACCESS) != AKD_SUCCESS) {
AKMERROR;
return 0;
}
// Read values from ASAX to ASAZ
if (AKD_RxData(AK8963_FUSE_ASAX, i2cData, 3) != AKD_SUCCESS) {
AKMERROR;
return 0;
}
asax = (int16)i2cData[0];
asay = (int16)i2cData[1];
asaz = (int16)i2cData[2];
// TEST
TEST_DATA(TLIMIT_NO_ASAX, TLIMIT_TN_ASAX, asax, TLIMIT_LO_ASAX, TLIMIT_HI_ASAX, &pf_total);
TEST_DATA(TLIMIT_NO_ASAY, TLIMIT_TN_ASAY, asay, TLIMIT_LO_ASAY, TLIMIT_HI_ASAY, &pf_total);
TEST_DATA(TLIMIT_NO_ASAZ, TLIMIT_TN_ASAZ, asaz, TLIMIT_LO_ASAZ, TLIMIT_HI_ASAZ, &pf_total);
// Read values. CNTL
if (AKD_RxData(AK8963_REG_CNTL1, i2cData, 1) != AKD_SUCCESS) {
AKMERROR;
return 0;
}
// Set to PowerDown mode
if (AKD_SetMode(AK8963_MODE_POWERDOWN) != AKD_SUCCESS) {
AKMERROR;
return 0;
}
// TEST
TEST_DATA(TLIMIT_NO_WR_CNTL1, TLIMIT_TN_WR_CNTL1, (int16)i2cData[0], TLIMIT_LO_WR_CNTL1, TLIMIT_HI_WR_CNTL1, &pf_total);
//***********************************************
// Step2
//***********************************************
// Set to SNG measurement pattern (Set CNTL register)
if (AKD_SetMode(AK8963_MODE_SNG_MEASURE | (prms->m_outbit << 4)) != AKD_SUCCESS) {
AKMERROR;
return 0;
}
// Wait for DRDY pin changes to HIGH.
// Get measurement data from AK8963
// ST1 + (HXL + HXH) + (HYL + HYH) + (HZL + HZH) + ST2
// = 1 + (1 + 1) + (1 + 1) + (1 + 1) + 1 = 8 bytes
if (AKD_GetMagneticData(i2cData) != AKD_SUCCESS) {
AKMERROR;
return 0;
}
hdata[0] = (int16)((((uint16)(i2cData[2]))<<8)+(uint16)(i2cData[1]));
hdata[1] = (int16)((((uint16)(i2cData[4]))<<8)+(uint16)(i2cData[3]));
hdata[2] = (int16)((((uint16)(i2cData[6]))<<8)+(uint16)(i2cData[5]));
if((i2cData[7] & 0x10) == 0){ // 14bit mode
hdata[0] <<= 2;
hdata[1] <<= 2;
hdata[2] <<= 2;
}
// TEST
TEST_DATA(TLIMIT_NO_SNG_ST1, TLIMIT_TN_SNG_ST1, (int16)i2cData[0], TLIMIT_LO_SNG_ST1, TLIMIT_HI_SNG_ST1, &pf_total);
TEST_DATA(TLIMIT_NO_SNG_HX, TLIMIT_TN_SNG_HX, hdata[0], TLIMIT_LO_SNG_HX, TLIMIT_HI_SNG_HX, &pf_total);
TEST_DATA(TLIMIT_NO_SNG_HY, TLIMIT_TN_SNG_HY, hdata[1], TLIMIT_LO_SNG_HY, TLIMIT_HI_SNG_HY, &pf_total);
TEST_DATA(TLIMIT_NO_SNG_HZ, TLIMIT_TN_SNG_HZ, hdata[2], TLIMIT_LO_SNG_HZ, TLIMIT_HI_SNG_HZ, &pf_total);
if((i2cData[7] & 0x10) == 0){ // 14bit mode
TEST_DATA(
TLIMIT_NO_SNG_ST2,
TLIMIT_TN_SNG_ST2,
(int16)i2cData[7],
TLIMIT_LO_SNG_ST2_14BIT,
TLIMIT_HI_SNG_ST2_14BIT,
&pf_total
);
} else { // 16bit mode
TEST_DATA(
TLIMIT_NO_SNG_ST2,
TLIMIT_TN_SNG_ST2,
(int16)i2cData[7],
TLIMIT_LO_SNG_ST2_16BIT,
TLIMIT_HI_SNG_ST2_16BIT,
&pf_total
);
}
// Generate magnetic field for self-test (Set ASTC register)
i2cData[0] = 0x40;
if (AKD_TxData(AK8963_REG_ASTC, i2cData, 1) != AKD_SUCCESS) {
AKMERROR;
return 0;
}
// Set to Self-test mode (Set CNTL register)
if (AKD_SetMode(AK8963_MODE_SELF_TEST | (prms->m_outbit << 4)) != AKD_SUCCESS) {
AKMERROR;
return 0;
}
// Wait for DRDY pin changes to HIGH.
// Get measurement data from AK8963
// ST1 + (HXL + HXH) + (HYL + HYH) + (HZL + HZH) + ST2
// = 1 + (1 + 1) + (1 + 1) + (1 + 1) + 1 = 8Byte
if (AKD_GetMagneticData(i2cData) != AKD_SUCCESS) {
AKMERROR;
return 0;
}
// TEST
TEST_DATA(TLIMIT_NO_SLF_ST1, TLIMIT_TN_SLF_ST1, (int16)i2cData[0], TLIMIT_LO_SLF_ST1, TLIMIT_HI_SLF_ST1, &pf_total);
hdata[0] = (int16)((((uint16)(i2cData[2]))<<8)+(uint16)(i2cData[1]));
hdata[1] = (int16)((((uint16)(i2cData[4]))<<8)+(uint16)(i2cData[3]));
hdata[2] = (int16)((((uint16)(i2cData[6]))<<8)+(uint16)(i2cData[5]));
if((i2cData[7] & 0x10) == 0){ // 14bit mode
hdata[0] <<= 2;
hdata[1] <<= 2;
hdata[2] <<= 2;
}
// TEST
TEST_DATA(
TLIMIT_NO_SLF_RVHX,
TLIMIT_TN_SLF_RVHX,
(hdata[0])*((asax - 128)*0.5f/128.0f + 1),
TLIMIT_LO_SLF_RVHX,
TLIMIT_HI_SLF_RVHX,
&pf_total
);
TEST_DATA(
TLIMIT_NO_SLF_RVHY,
TLIMIT_TN_SLF_RVHY,
(hdata[1])*((asay - 128)*0.5f/128.0f + 1),
TLIMIT_LO_SLF_RVHY,
TLIMIT_HI_SLF_RVHY,
&pf_total
);
TEST_DATA(
TLIMIT_NO_SLF_RVHZ,
TLIMIT_TN_SLF_RVHZ,
(hdata[2])*((asaz - 128)*0.5f/128.0f + 1),
TLIMIT_LO_SLF_RVHZ,
TLIMIT_HI_SLF_RVHZ,
&pf_total
);
// TEST
if((i2cData[7] & 0x10) == 0){ // 14bit mode
TEST_DATA(
TLIMIT_NO_SLF_ST2,
TLIMIT_TN_SLF_ST2,
(int16)i2cData[7],
TLIMIT_LO_SLF_ST2_14BIT,
TLIMIT_HI_SLF_ST2_14BIT,
&pf_total
);
}else{ // 16bit mode
TEST_DATA(
TLIMIT_NO_SLF_ST2,
TLIMIT_TN_SLF_ST2,
(int16)i2cData[7],
TLIMIT_LO_SLF_ST2_16BIT,
TLIMIT_HI_SLF_ST2_16BIT,
&pf_total
);
}
// Set to Normal mode for self-test.
i2cData[0] = 0x00;
if (AKD_TxData(AK8963_REG_ASTC, i2cData, 1) != AKD_SUCCESS) {
AKMERROR;
return 0;
}
return pf_total;
}
/*!
This is the main routine of measurement.
@param[in,out] prms A pointer to a #AK8963PRMS structure.
*/
void MeasureSNGLoop(AK8963PRMS* prms)
{
BYTE i2cData[AKSC_BDATA_SIZE];
int16 bData[AKSC_BDATA_SIZE]; // Measuring block data
int16 ret;
int16 i;
int16 hdoe_interval = 1;
/* Acceleration interval */
AKMD_LOOP_TIME acc_acq = { -1, 0 };
/* Magnetic field interval */
AKMD_LOOP_TIME mag_acq = { -1, 0 };
/* Orientation interval */
AKMD_LOOP_TIME ori_acq = { -1, 0 };
/* Magnetic acquisition interval */
AKMD_LOOP_TIME mag_mes = { -1, 0 };
/* Acceleration acquisition interval */
AKMD_LOOP_TIME acc_mes = { -1, 0 };
/* Magnetic measurement interval */
AKMD_LOOP_TIME mag_int = { AK8963_MEASUREMENT_TIME_NS, 0 };
/* Setting interval */
AKMD_LOOP_TIME setting = { AKMD_SETTING_INTERVAL, 0 };
/* 0x0001: Acceleration execute flag (data output) */
/* 0x0002: Magnetic execute flag (data output) */
/* 0x0004: Orientation execute flag (data output) */
/* 0x0100: Magnetic measurement flag */
/* 0x0200: Magnetic interrupt flag */
/* 0x0400: Acceleration measurement flag */
/* 0x0800: Acceleration interrupt flag */
/* 0x1000: Setting execute flag */
uint16 exec_flags;
struct timespec currTime = { 0, 0 }; /* Current time */
struct timespec lastTime = { 0, 0 }; /* Previous time */
int64_t execTime; /* Time between two points */
int64_t minVal; /* The minimum duration to the next event */
int measuring = 0; /* The value is 1, if while measuring. */
if (openForm() < 0) {
AKMERROR;
return;
}
/* Get initial interva */
if (GetInterval(&acc_acq, &mag_acq, &ori_acq,
&mag_mes, &acc_mes,
&hdoe_interval) != AKRET_PROC_SUCCEED) {
AKMERROR;
goto MEASURE_SNG_END;
}
/* Initialize */
if (InitAK8963_Measure(prms) != AKRET_PROC_SUCCEED) {
goto MEASURE_SNG_END;
}
/* Beginning time */
if (clock_gettime(CLOCK_MONOTONIC, &currTime) < 0) {
AKMERROR;
goto MEASURE_SNG_END;
}
while (g_stopRequest != AKKEY_STOP_MEASURE) {
exec_flags = 0;
minVal = 1000000000; /*1sec*/
/* Copy the last time */
lastTime = currTime;
/* Get current time */
if (clock_gettime(CLOCK_MONOTONIC, &currTime) < 0) {
AKMERROR;
break;
}
/* Calculate the difference */
execTime = CalcDuration(&currTime, &lastTime);
AKMDATA(AKMDATA_EXECTIME,
"Executing(%6.2f)\n", (double)execTime / 1000000.0);
/* Subtract the differential time from each event.
If subtracted value is negative turn event flag on. */
exec_flags |= (SetLoopTime(&setting, execTime, &minVal)
<< (SETTING_FLAG_POS));
exec_flags |= (SetLoopTime(&mag_acq, execTime, &minVal)
<< (MAG_ACQ_FLAG_POS));
exec_flags |= (SetLoopTime(&acc_acq, execTime, &minVal)
<< (ACC_ACQ_FLAG_POS));
exec_flags |= (SetLoopTime(&ori_acq, execTime, &minVal)
<< (ORI_ACQ_FLAG_POS));
exec_flags |= (SetLoopTime(&acc_mes, execTime, &minVal)
<< (ACC_MES_FLAG_POS));
/* Magnetometer needs special care. While the device is
under measuring, measurement start flag should not be turned on.*/
if (mag_mes.interval >= 0) {
mag_mes.duration -= execTime;
if (!measuring) {
/* Not measuring */
if (mag_mes.duration <= AKMD_LOOP_MARGIN) {
exec_flags |= (1 << (MAG_MES_FLAG_POS));
} else if (mag_mes.duration < minVal) {
minVal = mag_mes.duration;
}
} else {
/* While measuring */
mag_int.duration -= execTime;
/* NO_MARGIN! */
if (mag_int.duration <= 0) {
exec_flags |= (1 << (MAG_INT_FLAG_POS));
} else if (mag_int.duration < minVal) {
minVal = mag_int.duration;
}
}
}
/* If all flag is off, go sleep */
if (exec_flags == 0) {
AKMDATA(AKMDATA_EXECTIME, "Sleeping(%6.2f)...\n",
(double)minVal / 1000000.0);
if (minVal > 0) {
struct timespec doze = { 0, 0 };
doze = int64_to_timespec(minVal);
nanosleep(&doze, NULL);
}
} else {
AKMDATA(AKMDATA_EXECFLAG, "ExecFlags=0x%04X\n", exec_flags);
if (exec_flags & (1 << (MAG_MES_FLAG_POS))) {
/* Set to SNG measurement pattern (Set CNTL register) */
if (AKD_SetMode(AK8963_MODE_SNG_MEASURE | (prms->m_outbit << 4)) != AKD_SUCCESS) {
AKMERROR;
break;
}
mag_mes.duration = mag_mes.interval;
mag_int.duration = mag_int.interval;
measuring = 1;
}
if (exec_flags & (1 << (MAG_INT_FLAG_POS))) {
/* Get magnetometer measurement data */
/* ST1 + HXL,HXH + HYL,HYH + HZL,HZH + ST2 = 8 Byte */
if (AKD_GetMagneticData(i2cData) != AKD_SUCCESS) {
AKMERROR;
break;
}
// Copy to local variable
AKMDATA(AKMDATA_BDATA, "bData(Hex)=");
for (i=0; i<AKSC_BDATA_SIZE; i++) {
bData[i] = i2cData[i];
AKMDATA(AKMDATA_BDATA, "%02x,", bData[i]);
}
AKMDATA(AKMDATA_BDATA, "\n");
ret = GetMagneticVector(
bData,
prms,
checkForm(),
hdoe_interval);
// Check the return value
if (ret == AKRET_PROC_SUCCEED) {
;/* Do nothing */
} else if (ret == AKRET_FORMATION_CHANGED) {
;/* Do nothing */
/*} else if (ret == AKRET_DATA_READERROR) {
AKMDEBUG(DBG_LEVEL3, "Data read error occurred.\n");
} else if (ret == AKRET_DATA_OVERFLOW) {
AKMDEBUG(DBG_LEVEL3, "Data overflow occurred.\n");
} else if (ret == AKRET_OFFSET_OVERFLOW) {
AKMDEBUG(DBG_LEVEL3, "Offset overflow occurred.\n");
} else if (ret == AKRET_HBASE_CHANGED) {
AKMDEBUG(DBG_LEVEL3, "Huge magnetic force.\n");
} else if (ret == AKRET_HFLUC_OCCURRED) {
AKMDEBUG(DBG_LEVEL3, "A fluctuation of magnetic field.\n");
} else if (ret == AKRET_VNORM_ERROR) {
AKMDEBUG(DBG_LEVEL3, "Data normalizeation was failed.\n");*/
} else {
ALOGE("GetMagneticVector has failed (0x%04X).\n", ret);
}
measuring = 0;
}
if (exec_flags & (1 << (ACC_MES_FLAG_POS))) {
/* Get accelerometer data */
if (AKD_GetAccelerationData(prms->m_avec.v) != AKD_SUCCESS) {
AKMERROR;
break;
}
#ifdef AKMD_ACC_COMBINED
ConvertCoordinate(prms->m_layout, &prms->m_avec);
#endif
AKMDATA(AKMDATA_AVEC, "acc(dec)=%d,%d,%d\n",
prms->m_avec.u.x, prms->m_avec.u.y, prms->m_avec.u.z);
}
if (exec_flags & (1 << (ORI_ACQ_FLAG_POS))) {
/* Calculate direction angle */
if (CalcDirection(prms) != AKRET_PROC_SUCCEED) {
AKMERROR;
}
}
}
if (exec_flags & 0x0F) {
/* If any ACQ flag is on, report the data to device driver */
Disp_MeasurementResultHook(prms, (uint16)(exec_flags & 0x0F));
}
if (exec_flags & (1 << (SETTING_FLAG_POS))) {
/* Get measurement interval from device driver */
GetInterval(&acc_acq, &mag_acq, &ori_acq,
&mag_mes, &acc_mes, &hdoe_interval);
}
}
MEASURE_SNG_END:
// Set to PowerDown mode
if (AKD_SetMode(AK8963_MODE_POWERDOWN) != AKD_SUCCESS) {
AKMERROR;
}
closeForm();
}
/*!
SmartCompass main calculation routine. This function will be processed
when INT pin event is occurred.
@retval AKRET_
@param[in] bData An array of register values which holds,
ST1, HXL, HXH, HYL, HYH, HZL, HZH and ST2 value respectively.
@param[in,out] prms A pointer to a #AK8963PRMS structure.
@param[in] curForm The index of hardware position which represents the
index when this function is called.
@param[in] hDecimator HDOE will execute once while this function is called
this number of times.
*/
int16 GetMagneticVector(
const int16 bData[],
AK8963PRMS* prms,
const int16 curForm,
const int16 hDecimator)
{
const int16vec hrefZero = {{0, 0, 0}};
int16vec have;
int16 dor, derr, hofl, cb;
int32vec preHbase;
int16 overflow;
int16 hfluc;
int16 hdSucc;
int16 aksc_ret;
int16 ret;
have.u.x = 0;
have.u.y = 0;
have.u.z = 0;
dor = 0;
derr = 0;
hofl = 0;
cb = 0;
preHbase = prms->m_hbase;
overflow = 0;
ret = AKRET_PROC_SUCCEED;
// Subtract the formation suspend counter
if (prms->m_cntSuspend > 0) {
prms->m_cntSuspend--;
// Check the suspend counter
if (prms->m_cntSuspend == 0) {
// Restore the value when succeeding in estimating of HOffset.
prms->m_ho = prms->HSUC_HO[prms->m_form];
prms->m_ho32.u.x = (int32)prms->HSUC_HO[prms->m_form].u.x;
prms->m_ho32.u.y = (int32)prms->HSUC_HO[prms->m_form].u.y;
prms->m_ho32.u.z = (int32)prms->HSUC_HO[prms->m_form].u.z;
prms->m_hdst = prms->HSUC_HDST[prms->m_form];
prms->m_hbase = prms->HSUC_HBASE[prms->m_form];
// Initialize the decompose parameters
AKSC_InitDecomp8963(prms->m_hdata);
// Initialize HDOE parameters
AKSC_InitHDOEProcPrmsS3(
&prms->m_hdoev,
1,
&prms->m_ho,
prms->m_hdst
);
// Initialize HFlucCheck parameters
AKSC_InitHFlucCheck(
&(prms->m_hflucv),
&(prms->HFLUCV_HREF[prms->m_form]),
HFLUCV_TH
);
}
}
// Decompose one block data into each Magnetic sensor's data
aksc_ret = AKSC_Decomp8963(
bData,
prms->m_hnave,
&prms->m_asa,
prms->m_hdata,
&prms->m_hbase,
&prms->m_hn,
&have,
&dor,
&derr,
&hofl,
&cb
);
AKM_LOG("%s: ST1, HXH&HXL, HYH&HYL, HZH&HZL, ST2,"
" hdata[0].u.x, hdata[0].u.y, hdata[0].u.z,"
" asax, asay, asaz ="
" %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n",
__FUNCTION__,
bData[0],
(int16)(((uint16)bData[2])<<8|bData[1]),
(int16)(((uint16)bData[4])<<8|bData[3]),
(int16)(((uint16)bData[6])<<8|bData[5]), bData[7],
prms->m_hdata[0].u.x, prms->m_hdata[0].u.y, prms->m_hdata[0].u.z,
prms->m_asa.u.x, prms->m_asa.u.y, prms->m_asa.u.z);
if (aksc_ret == 0) {
AKMDUMP("AKSC_Decomp8963 failed.\n"
" ST1=0x%02X, ST2=0x%02X\n"
" XYZ(HEX)=%02X,%02X,%02X,%02X,%02X,%02X\n"
" asa(dec)=%d,%d,%d\n"
" hbase(dec)=%ld,%ld,%ld\n",
bData[0], bData[7],
bData[1], bData[2], bData[3], bData[4], bData[5], bData[6],
prms->m_asa.u.x, prms->m_asa.u.y, prms->m_asa.u.z,
prms->m_hbase.u.x, prms->m_hbase.u.y, prms->m_hbase.u.z);
return AKRET_PROC_FAIL;
}
// Check the formation change
if (prms->m_form != curForm) {
prms->m_form = curForm;
prms->m_cntSuspend = CSPEC_CNTSUSPEND_SNG;
prms->m_callcnt = 0;
ret |= AKRET_FORMATION_CHANGED;
return ret;
}
// Check derr
if (derr == 1) {
ret |= AKRET_DATA_READERROR;
return ret;
}
// Check hofl
if (hofl == 1) {
if (prms->m_cntSuspend <= 0) {
// Set a HDOE level as "HDST_UNSOLVED"
AKSC_SetHDOELevel(
&prms->m_hdoev,
&prms->m_ho,
AKSC_HDST_UNSOLVED,
1
);
prms->m_hdst = AKSC_HDST_UNSOLVED;
}
ret |= AKRET_DATA_OVERFLOW;
return ret;
}
// Check hbase
if (cb == 1) {
// Translate HOffset
AKSC_TransByHbase(
&(preHbase),
&(prms->m_hbase),
&(prms->m_ho),
&(prms->m_ho32),
&overflow
);
if (overflow == 1) {
ret |= AKRET_OFFSET_OVERFLOW;
}
// Set hflucv.href to 0
AKSC_InitHFlucCheck(
&(prms->m_hflucv),
&(hrefZero),
HFLUCV_TH
);
if (prms->m_cntSuspend <= 0) {
AKSC_SetHDOELevel(
&prms->m_hdoev,
&prms->m_ho,
AKSC_HDST_UNSOLVED,
1
);
prms->m_hdst = AKSC_HDST_UNSOLVED;
}
ret |= AKRET_HBASE_CHANGED;
return ret;
}
if (prms->m_cntSuspend <= 0) {
// Detect a fluctuation of magnetic field.
hfluc = AKSC_HFlucCheck(&(prms->m_hflucv), &(prms->m_hdata[0]));
if (hfluc == 1) {
// Set a HDOE level as "HDST_UNSOLVED"
AKSC_SetHDOELevel(
&prms->m_hdoev,
&prms->m_ho,
AKSC_HDST_UNSOLVED,
1
);
prms->m_hdst = AKSC_HDST_UNSOLVED;
ret |= AKRET_HFLUC_OCCURRED;
return ret;
}
else {
prms->m_callcnt--;
if (prms->m_callcnt <= 0) {
//Calculate Magnetic sensor's offset by DOE
hdSucc = AKSC_HDOEProcessS3(
prms->m_licenser,
prms->m_licensee,
prms->m_key,
&prms->m_hdoev,
prms->m_hdata,
prms->m_hn,
&prms->m_ho,
&prms->m_hdst
);
if (hdSucc == AKSC_CERTIFICATION_DENIED) {
AKMERROR;
return AKRET_PROC_FAIL;
}
if (hdSucc > 0) {
prms->HSUC_HO[prms->m_form] = prms->m_ho;
prms->m_ho32.u.x = (int32)prms->m_ho.u.x;
prms->m_ho32.u.y = (int32)prms->m_ho.u.y;
prms->m_ho32.u.z = (int32)prms->m_ho.u.z;
prms->HSUC_HDST[prms->m_form] = prms->m_hdst;
prms->HFLUCV_HREF[prms->m_form] = prms->m_hflucv.href;
prms->HSUC_HBASE[prms->m_form] = prms->m_hbase;
}
//Set decimator counter
prms->m_callcnt = hDecimator;
}
}
}
// Subtract offset and normalize magnetic field vector.
aksc_ret = AKSC_VNorm(
&have,
&prms->m_ho,
&prms->m_hs,
AKSC_HSENSE_TARGET,
&prms->m_hvec
);
if (aksc_ret == 0) {
AKMDUMP("AKSC_VNorm failed.\n"
" have=%6d,%6d,%6d ho=%6d,%6d,%6d hs=%6d,%6d,%6d\n",
have.u.x, have.u.y, have.u.z,
prms->m_ho.u.x, prms->m_ho.u.y, prms->m_ho.u.z,
prms->m_hs.u.x, prms->m_hs.u.y, prms->m_hs.u.z);
ret |= AKRET_VNORM_ERROR;
return ret;
}
//Convert layout from sensor to Android by using PAT number.
// Magnetometer
ConvertCoordinate(prms->m_layout, &prms->m_hvec);
return AKRET_PROC_SUCCEED;
}
/*!
Calculate Yaw, Pitch, Roll angle.
m_hvec and m_avec should be Android coordination.
@return Always return #AKRET_PROC_SUCCEED.
@param[in,out] prms A pointer to a #AK8963PRMS structure.
*/
int16 CalcDirection(AK8963PRMS* prms)
{
/* Conversion matrix from Android to SmartCompass coordination */
/*
const I16MATRIX hlayout = {{
0, 1, 0,
-1, 0, 0,
0, 0, 1}};
const I16MATRIX alayout = {{
0,-1, 0,
1, 0, 0,
0, 0,-1}};
*/
int16 preThe;
preThe = prms->m_theta;
prms->m_ds3Ret = AKSC_DirectionS3(
prms->m_licenser,
prms->m_licensee,
prms->m_key,
&prms->m_hvec,
&prms->m_avec,
&prms->m_dvec,
&prms->m_hlayout[prms->m_form],
&prms->m_alayout[prms->m_form],
&prms->m_theta,
&prms->m_delta,
&prms->m_hr,
&prms->m_hrhoriz,
&prms->m_ar,
&prms->m_phi180,
&prms->m_phi90,
&prms->m_eta180,
&prms->m_eta90,
&prms->m_mat,
&prms->m_quat
);
prms->m_theta = AKSC_ThetaFilter(
prms->m_theta,
preThe,
THETAFILTER_SCALE
);
if (prms->m_ds3Ret == AKSC_CERTIFICATION_DENIED) {
AKMERROR;
return AKRET_PROC_FAIL;
}
if (prms->m_ds3Ret != 3) {
/*
AKMDUMP("AKSC_Direction6D failed (0x%02x).\n"
" hvec=%d,%d,%d avec=%d,%d,%d dvec=%d,%d,%d\n",
prms->m_ds3Ret,
prms->m_hvec.u.x, prms->m_hvec.u.y, prms->m_hvec.u.z,
prms->m_avec.u.x, prms->m_avec.u.y, prms->m_avec.u.z,
prms->m_dvec.u.x, prms->m_dvec.u.y, prms->m_dvec.u.z);
*/
}
/* Convert Yaw, Pitch, Roll angle to Android coordinate system */
/* Actually, only Roll angle is opposite */
if (prms->m_ds3Ret & 0x02) {
prms->m_eta180 = -prms->m_eta180;
prms->m_eta90 = -prms->m_eta90;
AKMDATA(AKMDATA_D6D, "AKSC_Direction6D (0x%02x):\n"
" Yaw, Pitch, Roll=%6.1f,%6.1f,%6.1f\n",
prms->m_ds3Ret,
DISP_CONV_Q6F(prms->m_theta),
DISP_CONV_Q6F(prms->m_phi180),
DISP_CONV_Q6F(prms->m_eta90));
}
return AKRET_PROC_SUCCEED;
}