/* -------------------------------------------------------------------------------------------------------- * Copyright(C), 2010-2011, Fuzhou Rockchip Co. ,Ltd. All Rights Reserved. * * File: Acc_mma8452.c * * Desc: 实现 akmd8975 要求的 accelerometer sensor 的功能接口 : 开启, 关闭, 获取数据等. * * ----------------------------------------------------------------------------------- * < 习语 和 缩略语 > : * * acc : accelerometer sensor, "g sensor" 的 别名. * * ----------------------------------------------------------------------------------- * < 内部模块 or 对象的层次结构 > : * * ----------------------------------------------------------------------------------- * < 功能实现的基本流程 > : * * ----------------------------------------------------------------------------------- * < 关键标识符 > : * * ----------------------------------------------------------------------------------- * < 本模块实现依赖的外部模块 > : * ... * ----------------------------------------------------------------------------------- * Note: * * Author: ChenZhen * * -------------------------------------------------------------------------------------------------------- * Version: * v1.0 : init version * -------------------------------------------------------------------------------------------------------- * Log: ----Wed Jan 19 18:55:55 2011 v1.0 * * -------------------------------------------------------------------------------------------------------- */ /* --------------------------------------------------------------------------------------------------------- * Include Files * --------------------------------------------------------------------------------------------------------- */ #include #include #include #include #include #include #include #include #include #include #include "mma8452_kernel.h" #include "AKCommon.h" #include "AK8975Driver.h" #include "Acc_mma8452.h" //#define ENABLE_DEBUG_LOG #include "custom_log.h" /* --------------------------------------------------------------------------------------------------------- * Local Macros * --------------------------------------------------------------------------------------------------------- */ /** path to accelerometer control device. */ #define ASENSOR_PATH "/dev/mma8452_daemon" /** 表征相同的 加速度物理量的时, "Android 上层使用的 数值" 和 "sensor 数据设备送出的 数值" 之间的比值. */ #define ACCELERATION_RATIO_ANDROID_TO_HW (9.80665f / 1000000) /** "sDisableAccTimer" 在本 app 模块 scope 中的标识 ID. */ #define APP_TIME_ID__DISABLE_ACC (1) /* --------------------------------------------------------------------------------------------------------- * Local Typedefs * --------------------------------------------------------------------------------------------------------- */ typedef char bool; #undef TRUE #define TRUE 1 #undef FALSE #define FALSE 0 /* --------------------------------------------------------------------------------------------------------- * External Function Prototypes (referenced in other file) * --------------------------------------------------------------------------------------------------------- */ /* --------------------------------------------------------------------------------------------------------- * Local Function Prototypes * --------------------------------------------------------------------------------------------------------- */ void onTimeOut(sigval_t v); /* --------------------------------------------------------------------------------------------------------- * Local Variables * --------------------------------------------------------------------------------------------------------- */ /** acc(g sensor) 控制设备(ASENSOR_PATH) 的 FD. */ static int sAccFd = -1; /** timer, 用于定时超时之后 disable acc. 这里是 "系统 timer ID", 动态创建. */ static timer_t sDisableAccTimer = NULL; /** 若在 ENABLE_TIME_OUT 秒内, akmd8975 没有再次读取 acc 数据, 则 disable acc 设备. */ static const int ENABLE_TIME_OUT = 5; /** 标识当前模块是否 使能了 acc 设备(要求其采集 g sensor 数据). */ static bool sHasEnabledAcc = FALSE; /* --------------------------------------------------------------------------------------------------------- * Global Variables * --------------------------------------------------------------------------------------------------------- */ /* --------------------------------------------------------------------------------------------------------- * Global Functions Implementation * --------------------------------------------------------------------------------------------------------- */ /** * Open device driver. * This function opens device driver of acceleration sensor. * Additionally, measurement range is set to +/- 2G mode, bandwidth is set to 25Hz. * @return * If this function succeeds, the return value is #AKD_SUCCESS. * Otherwise the return value is #AKD_FAIL. */ int16_t Acc_InitDevice(void) { D("Entered."); int16_t result = AKD_SUCCESS; struct sigevent se; /* 将用来定义对 timer 超时事件的定制处理方式. */ struct itimerspec ts; /* 将用于定义超时时间. */ /* 尝试打开 acc 控制设备文件. */ if ( 0 > (sAccFd = open(ASENSOR_PATH, O_RDONLY ) ) ) { E("failed to open acc file '%s', error is '%s'", ASENSOR_PATH, strerror(errno)); result = AKD_FAIL; goto EXIT; } /* < 创建 sDisableAccTimer. > */ memset(&se, 0, sizeof(se) ); se.sigev_notify = SIGEV_THREAD; /* "A notification function will be called to perform notification". */ se.sigev_notify_function = onTimeOut; /* 通知回调函数. */ se.sigev_value.sival_int = APP_TIME_ID__DISABLE_ACC; /* sigev_value : sigev_notify_function 的回调实参. */ if ( timer_create (CLOCK_REALTIME, &se, &sDisableAccTimer) < 0 ) { E("failed create 'sDisableAccTimer'; error is '%s'.", strerror(errno)); result = AKD_FAIL; goto EXIT; } // sDisableAccTimer 将在 Acc_GetAccelerationData() 中启动. sHasEnabledAcc = FALSE; // 显式初始化. EXIT: if ( AKD_SUCCESS != result ) { if ( NULL != sDisableAccTimer ) { timer_delete(sDisableAccTimer); sDisableAccTimer = NULL; } if ( -1 != sAccFd ) { close(sAccFd); sAccFd = -1; } } return result; } /** * Close device driver. * This function closes device drivers of acceleration sensor. */ void Acc_DeinitDevice(void) { D("Entered."); timer_delete(sDisableAccTimer); sDisableAccTimer = NULL; /* 若 acc 设备已经被启动, 则... */ if ( sHasEnabledAcc ) { D("to call 'GSENSOR_IOCTL_CLOSE'."); if ( ioctl(sAccFd, GSENSOR_IOCTL_CLOSE) < 0 ) { E("failed to disable acc device."); } sHasEnabledAcc = FALSE; } close(sAccFd); sAccFd = -1; } /** * Acquire acceleration data from acceleration sensor and convert it to Android coordinate system. * .! : 目前设计为 尽量不阻塞的形式. * @param[out] fData * A acceleration data array. * The coordinate system of the acquired data follows the definition of Android. * @return * If this function succeeds, the return value is #AKD_SUCCESS. * Otherwise the return value is #AKD_FAIL. * */ int16_t Acc_GetAccelerationData(float fData[3]) { int16_t result = AKD_SUCCESS; struct itimerspec ts; /* 将用于定义超时时间. */ struct sensor_axis accData = {0, 0, 0}; /* 若尚未使能 acc, 则... */ if ( !sHasEnabledAcc ) { /* 使能 acc. */ if ( 0 > ioctl(sAccFd, GSENSOR_IOCTL_START) ) { E("failed to START acc device; error is '%s'.", strerror(errno)); result = AKD_FAIL; goto EXIT; } /* 设置采样率. */ int sample_rate = MMA8452_RATE_12P5; // .! : 暂时先使用 12.5 Hz. if ( 0 > ioctl(sAccFd, GSENSOR_IOCTL_APP_SET_RATE, &sample_rate) ) { E("failed to set sample rete of acc device; error is '%s'.", strerror(errno)); result = AKD_FAIL; goto EXIT; } /* 置位标识. */ sHasEnabledAcc = TRUE; } /* 获取 acc sensor 数据. */ // .! : 尽量不阻塞. if ( 0 > ioctl(sAccFd, GSENSOR_IOCTL_GETDATA, &accData) ) { E("failed to GET acc data, error is '%s.'", strerror(errno)); result = AKD_FAIL; goto EXIT; } /* 重置 sDisableAccTimer. */ // D("to reset 'sDisableAccTimer'."); memset(&ts, 0, sizeof(ts) ); ts.it_value.tv_sec = ENABLE_TIME_OUT; if ( timer_settime(sDisableAccTimer, 0, &ts, NULL) < 0 ) { E("failed start 'sDisableAccTimer'; error is '%s'.", strerror(errno)); result = AKD_FAIL; goto EXIT; } /* 转化为 Android 定义的格式, 待返回. */ // .! : 和 HAL 的 MmaSensor.cpp 中一致, 使用 默认横屏坐标定义 g sensor 数据. fData[0] = ( (accData.x) * ACCELERATION_RATIO_ANDROID_TO_HW); fData[1] = ( (accData.y) * ACCELERATION_RATIO_ANDROID_TO_HW); fData[2] = ( (accData.z) * ACCELERATION_RATIO_ANDROID_TO_HW); D_WHEN_REPEAT(100, "got acc sensor data : x = %f, y = %f, z = %f.", fData[0], fData[1], fData[2] ); EXIT: return result; } /* --------------------------------------------------------------------------------------------------------- * Local Functions Implementation * --------------------------------------------------------------------------------------------------------- */ /** * sDisableAccTimer 超时的通知回调. */ void onTimeOut(sigval_t v) { int appTimerId = v.sival_int; I("'sDisableAccTimer' timers out, appTimerId = %d.", appTimerId); switch ( appTimerId ) { case APP_TIME_ID__DISABLE_ACC: D("to disable acc device."); if ( sHasEnabledAcc ) { D("to call 'GSENSOR_IOCTL_CLOSE'."); if ( ioctl(sAccFd, GSENSOR_IOCTL_CLOSE) < 0 ) { E("failed to disable acc device."); } sHasEnabledAcc = FALSE; } break; default: E("unknow app timer ID."); return; } }