android13/hardware/rockchip/sensor/st/akm8975/AK8975Driver.c

335 lines
8.8 KiB
C

/******************************************************************************
*
* $Id: AK8975Driver.c 217 2010-03-26 07:11:56Z rikita $
*
* -- Copyright Notice --
*
* Copyright (c) 2009 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 "AK8975Driver.h"
#include "AKCommon.h" // DBGPRINT()
#include <fcntl.h>
/* Include proper acceleration file. */
//#include "Acc_bma150.c"
//#include "Acc_adxl345.c"
// #include "Acc_dummy.c"
// #include "Acc_mma8452.c"
#include "Acc_mma8452.h"
#define DBG_DATA_MONITOR 0
#define MSENSOR_NAME "/dev/akm8975_dev"
//#define GETMAG_WITH_POLLING
int g_file = -1;
void Android2AK(const float fData[], int16_t data[3]);
/*!
Open device driver.
This function opens both device drivers of magnetic sensor and acceleration
sensor. Additionally, some initial hardware settings are done, such as
measurement range, built-in filter function and etc.
@return If this function succeeds, the return value is #AKD_SUCCESS.
If device driver is already opened, the return value is #AKD_ERROR.
Otherwise the return value is #AKD_FAIL.
*/
int16_t AKD_InitDevice(void)
{
if (g_file >= 0) {
// Already initialized.
return AKD_ERROR;
}
// Open magnetic sensor's device driver.
if ((g_file = open(MSENSOR_NAME, O_RDWR)) < 0) {
DBGPRINT(DBG_LEVEL0, "open error.\n");
return AKD_FAIL;
}
// Open acceleration sensor's device driver.
if (Acc_InitDevice() != AKD_SUCCESS) {
DBGPRINT(DBG_LEVEL0, "Acc initialize error.\n");
return AKD_FAIL;
}
return AKD_SUCCESS;
}
/*!
Close device driver.
This function closes both device drivers of magnetic sensor and acceleration
sensor.
*/
void AKD_DeinitDevice(void)
{
if (g_file >= 0) {
close(g_file);
g_file = -1;
}
Acc_DeinitDevice();
}
/*!
Writes data to a register of the AK8975. When more than one byte of data is
specified, the data is written in contiguous locations starting at an address
specified in \a address.
@return If this function succeeds, the return value is #AKD_SUCCESS. Otherwise
the return value is #AKD_FAIL.
@param[in] address Specify the address of a register in which data is to be
written.
@param[in] data Specify data to write or a pointer to a data array containing
the data. When specifying more than one byte of data, specify the starting
address of the array.
@param[in] numberOfBytesToWrite Specify the number of bytes that make up the
data to write. When a pointer to an array is specified in data, this argument
equals the number of elements of the array.
*/
int16_t AKD_TxData(const BYTE address,
const BYTE * data,
const uint16_t numberOfBytesToWrite)
{
int i;
char buf[RWBUF_SIZE];
if (g_file < 0) {
DBGPRINT(DBG_LEVEL0, "Device file is not opened.\n");
return AKD_FAIL;
}
if (numberOfBytesToWrite > (RWBUF_SIZE-2)) {
DBGPRINT(DBG_LEVEL1, "Tx size is too large.\n");
return AKD_FAIL;
}
buf[0] = numberOfBytesToWrite + 1;
buf[1] = address;
for (i = 0; i < numberOfBytesToWrite; i++) {
buf[i + 2] = data[i];
}
if (ioctl(g_file, ECS_IOCTL_WRITE, buf) < 0) {
DBGPRINT(DBG_LEVEL1, "ioctl error.\n");
return AKD_FAIL;
} else {
#if DBG_DATA_MONITOR
printf("addr=%02x data=", address);
for (i = 0; i < numberOfBytesToWrite; i++) {
printf(" %02x", data[i]);
}
printf("\n");
#endif
return AKD_SUCCESS;
}
}
/*!
Acquires data from a register or the EEPROM of the AK8975.
@return If this function succeeds, the return value is #AKD_SUCCESS. Otherwise
the return value is #AKD_FAIL.
@param[in] address Specify the address of a register from which data is to be
read.
@param[out] data Specify a pointer to a data array which the read data are
stored.
@param[in] numberOfBytesToRead Specify the number of bytes that make up the
data to read. When a pointer to an array is specified in data, this argument
equals the number of elements of the array.
*/
int16_t AKD_RxData(const BYTE address,
BYTE * data,
const uint16_t numberOfBytesToRead)
{
int i;
char buf[RWBUF_SIZE];
memset(data, 0, numberOfBytesToRead);
if (g_file < 0) {
DBGPRINT(DBG_LEVEL0, "Device file is not opened.\n");
return AKD_FAIL;
}
if (numberOfBytesToRead > (RWBUF_SIZE-1)) {
DBGPRINT(DBG_LEVEL1, "Rx size is too large.\n");
return AKD_FAIL;
}
buf[0] = numberOfBytesToRead;
buf[1] = address;
if (ioctl(g_file, ECS_IOCTL_READ, buf) < 0) {
DBGPRINT(DBG_LEVEL1, "ioctl error.\n");
return AKD_FAIL;
} else {
for (i = 0; i < numberOfBytesToRead; i++) {
data[i] = buf[i + 1];
}
#if DBG_DATA_MONITOR
printf("addr=%02x len=%d data=", address, numberOfBytesToRead);
for (i = 0; i < numberOfBytesToRead; i++) {
printf(" %02x", data[i]);
}
printf("\n");
#endif
return AKD_SUCCESS;
}
}
/*!
Acquire magnetic data from AK8975. If measurement is not done, this function
waits until measurement completion.
@return If this function succeeds, the return value is #AKD_SUCCESS. Otherwise
the return value is #AKD_FAIL.
@param[out] data A magnetic data array. The size should be larger than #SENSOR_DATA_SIZE.
*/
int16_t AKD_GetMagneticData(BYTE data[SENSOR_DATA_SIZE])
{
int i;
memset(data, 0, SENSOR_DATA_SIZE);
if (g_file < 0) {
DBGPRINT(DBG_LEVEL0, "Device file is not opened.\n");
return AKD_FAIL;
}
#ifdef GETMAG_WITH_POLLING
#warning "get magnetic data with polling!"
// Wait until measurement done.
msleep(AK8975_MEASUREMENT_TIME);
for (i = 0; i < AK8975_MEASURE_TIMEOUT; i++) {
if (AKD_RxData(AK8975_REG_ST1, data, 1) != AKD_SUCCESS) {
DBGPRINT(DBG_LEVEL1, "ioctl error.\n");
return AKD_FAIL;
}
if (data[0] & 0x01) {
if (AKD_RxData(AK8975_REG_ST1, data, SENSOR_DATA_SIZE) != AKD_SUCCESS) {
DBGPRINT(DBG_LEVEL1, "ioctl error.\n");
return AKD_FAIL;
}
break;
}
usleep(1000);
}
if (i >= AK8975_MEASURE_TIMEOUT) {
DBGPRINT(DBG_LEVEL1, "DRDY timeout.\n");
return AKD_FAIL;
}
#else
if (ioctl(g_file, ECS_IOCTL_GETDATA, data) < 0) {
DBGPRINT(DBG_LEVEL1, "ioctl error.\n");
return AKD_FAIL;
}
#endif
#if DBG_DATA_MONITOR
printf("bdata=");
for (i = 0; i < SENSOR_DATA_SIZE; i++) {
printf(" %02x", data[i]);
}
printf("\n");
#endif
return AKD_SUCCESS;
}
/*!
Set AK8975 to the specific mode.
@return If this function succeeds, the return value is #AKD_SUCCESS. Otherwise
the return value is #AKD_FAIL.
@param[in] mode This value should be one of the AK8975_Mode which is defined in
akm8975.h file.
*/
int16_t AKD_SetMode(const BYTE mode)
{
if (g_file < 0) {
DBGPRINT(DBG_LEVEL0, "Device file is not opened.\n");
return AKD_FAIL;
}
if (ioctl(g_file, ECS_IOCTL_SET_MODE, &mode) < 0) {
DBGPRINT(DBG_LEVEL1, "ioctl error.\n");
return AKD_FAIL;
}
return AKD_SUCCESS;
}
/*!
Acquire delay
@return If this function succeeds, the return value is #AKD_SUCCESS. Otherwise
the return value is #AKD_FAIL.
@param[out] delay A delay in microsecond.
*/
int16_t AKD_GetDelay(int32_t* delay)
{
short tmp;
if (g_file < 0) {
DBGPRINT(DBG_LEVEL0, "Device file is not opened.\n");
return AKD_FAIL;
}
if (ioctl(g_file, ECS_IOCTL_GET_DELAY, &tmp) < 0) {
DBGPRINT(DBG_LEVEL1, "ioctl error.\n");
return AKD_FAIL;
}
// The API returns delay time in millisecond.
*delay = tmp * 1000;
return AKD_SUCCESS;
}
/*!
Acquire acceleration data from acceleration sensor.
@return If this function succeeds, the return value is #AKD_SUCCESS. Otherwise
the return value is #AKD_FAIL.
@param[out] data A acceleration data array. The coordinate system of the
acquired data follows the definition of AK.
*/
int16_t AKD_GetAccelerationData(int16_t data[3])
{
float fData[3];
if (Acc_GetAccelerationData(fData) != AKD_SUCCESS) {
return AKD_FAIL;
} else {
Android2AK(fData, data);
return AKD_SUCCESS;
}
}
/*!
Convert Acceleration sensor coordinate system from Android's one to AK's one.
In Android coordinate system, 1G = 9.8f (m/s^2). In AK coordinate system,
1G = 720 (LSB).
@param[in] fData A acceleration data array. The coordinate system of this data
should follows the definition of Android.
@param[out] data A acceleration data array. The coordinate system of the
acquired data follows the definition of AK.
*/
void Android2AK(const float fData[], int16_t data[3])
{
/*
* 若将送入 AKSC_DirectionS3() 的 acc 数据使用 SmartCompass 坐标系, ...
* .! : 这里 acc 的坐标定义有蹊跷, 下面的实现是正确的.
*/
data[0] = fData[0] / 9.8f * 720;
data[1] = fData[1] / 9.8f * 720;
data[2] = fData[2] / 9.8f * 720;
}