This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
resources:tools-software:android-drivers:sensor-acceleration:adxl345 [09 Nov 2011 14:01] – Approved Michael Hennerich | resources:tools-software:android-drivers:sensor-acceleration:adxl345 [11 Dec 2013 09:57] (current) – [Platform data configuration] Michael Hennerich | ||
---|---|---|---|
Line 71: | Line 71: | ||
**The files can be downloaded here:**\\ | **The files can be downloaded here:**\\ | ||
- | [[bf> | + | {{: |
- | + | ||
- | * [[http:// | + | |
- | * [[http://blackfin.uclinux.org/ | + | |
---- | ---- | ||
Line 98: | Line 95: | ||
</ | </ | ||
- | <note tip> | + | <WRAP tip> |
In case the ADXL345/6 is not always event0 you can alternatively approach via / | In case the ADXL345/6 is not always event0 you can alternatively approach via / | ||
- | </note> | + | </WRAP> |
* Rebuilt your Android tree | * Rebuilt your Android tree | ||
- | <note tip> | + | <WRAP tip> |
Upon start the Android log file (use logcat) should include following lines: | Upon start the Android log file (use logcat) should include following lines: | ||
Line 112: | Line 109: | ||
D/ | D/ | ||
</ | </ | ||
- | </note> | + | </WRAP> |
Line 122: | Line 119: | ||
The maximum sample rate is by default limited to 200Hz, to change this limit modify define ADXL_MAX_SAMPLE_RATE_VAL in the sensor file. | The maximum sample rate is by default limited to 200Hz, to change this limit modify define ADXL_MAX_SAMPLE_RATE_VAL in the sensor file. | ||
- | <note warning> | + | <WRAP alert> |
Very high sample rates > 400Hz can freeze your system! | Very high sample rates > 400Hz can freeze your system! | ||
- | </note> | + | </WRAP> |
- | <source master/ | + | <code c> |
+ | static int control_set_delay(struct sensors_control_context_t *dev, int32_t ms) | ||
+ | { | ||
+ | int rate_val; | ||
+ | int32_t us = ms * MSEC_TO_USEC; | ||
+ | |||
+ | /* | ||
+ | * The ADXL34x Supports 16 sample rates ranging from 3200Hz-0.098Hz | ||
+ | * Calculate best fit and limit to max 200Hz (rate_val 11) | ||
+ | */ | ||
+ | |||
+ | for (rate_val = 0; rate_val < 16; rate_val++) | ||
+ | if (us >= ((10000 * MSEC_TO_USEC) >> rate_val)) | ||
+ | break; | ||
+ | |||
+ | if (rate_val > ADXL_MAX_SAMPLE_RATE_VAL) { | ||
+ | rate_val = ADXL_MAX_SAMPLE_RATE_VAL; | ||
+ | LOGD(" | ||
+ | ms, rate_val, (3200000 >> (15 - rate_val))); | ||
+ | } else { | ||
+ | LOGD(" | ||
+ | ms, rate_val, (3200000 >> (15 - rate_val))); | ||
+ | } | ||
+ | return write_int(" | ||
+ | } | ||
+ | </code> | ||
==== Platform data configuration ==== | ==== Platform data configuration ==== | ||
Line 136: | Line 158: | ||
Upon start EventHub must emit classes=0x0: | Upon start EventHub must emit classes=0x0: | ||
+ | |||
< | < | ||
- | I/EventHub( 1862): New device: path=/ | + | I/EventHub( 1862): New device: path=/ |
+ | accelerometer id=0x10003 (of 0x4) index=4 fd=50 classes=0x0 | ||
</ | </ | ||
classes=0x4 means that the ADXL34x driver is considered as Touchscreen. | classes=0x4 means that the ADXL34x driver is considered as Touchscreen. | ||
Line 149: | Line 173: | ||
< | < | ||
#echo 0 > / | #echo 0 > / | ||
+ | |||
</ | </ | ||
Line 155: | Line 180: | ||
==== The Sources ==== | ==== The Sources ==== | ||
- | <source master/ | ||
- | <source master/hardware/ | + | === Android.mk === |
+ | <code c> | ||
+ | # Copyright (C) 2008 The Android Open Source Project | ||
+ | # | ||
+ | # Licensed under the Apache License, Version 2.0 (the " | ||
+ | # you may not use this file except in compliance with the License. | ||
+ | # You may obtain a copy of the License at | ||
+ | # | ||
+ | # http://www.apache.org/ | ||
+ | # | ||
+ | # Unless required by applicable law or agreed to in writing, software | ||
+ | # distributed under the License is distributed on an "AS IS" BASIS, | ||
+ | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
+ | # See the License for the specific language governing permissions and | ||
+ | # limitations under the License. | ||
+ | |||
+ | |||
+ | LOCAL_PATH := $(call my-dir) | ||
+ | |||
+ | include $(CLEAR_VARS) | ||
+ | LOCAL_PRELINK_MODULE := false | ||
+ | LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/ | ||
+ | LOCAL_SHARED_LIBRARIES := liblog libcutils | ||
+ | LOCAL_SRC_FILES := sensors_adxl34x.c | ||
+ | LOCAL_MODULE := sensors.default | ||
+ | include $(BUILD_SHARED_LIBRARY) | ||
+ | </code> | ||
+ | |||
+ | === sensors_adxl34x.c | ||
+ | < | ||
+ | /* | ||
+ | * Copyright (C) 2010 Analog Devices Inc. | ||
+ | * Copyright (C) 2008 The Android Open Source Project | ||
+ | * | ||
+ | * Licensed under the Apache License, Version 2.0 (the " | ||
+ | * you may not use this file except in compliance with the License. | ||
+ | * You may obtain a copy of the License at | ||
+ | * | ||
+ | | ||
+ | * | ||
+ | * Unless required by applicable law or agreed to in writing, software | ||
+ | * distributed under the License is distributed on an "AS IS" BASIS, | ||
+ | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
+ | * See the License for the specific language governing permissions and | ||
+ | * limitations under the License. | ||
+ | */ | ||
+ | |||
+ | #define LOG_TAG " | ||
+ | #define SENSORS_SERVICE_NAME " | ||
+ | #define ACCEL_SENSOR_NAME " | ||
+ | |||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | #include < | ||
+ | |||
+ | / | ||
+ | #define ID_BASE SENSORS_HANDLE_BASE | ||
+ | #define ID_ACCELERATION (ID_BASE + 0) | ||
+ | #define MAX_NUM_SENSORS 1 | ||
+ | /* | ||
+ | * This driver assumes the ADXL345/6 set in 13-bit full resolution mode +/-16g. | ||
+ | */ | ||
+ | |||
+ | #define LSG | ||
+ | #define CONVERT | ||
+ | #define CONVERT_X | ||
+ | #define CONVERT_Y | ||
+ | #define CONVERT_Z | ||
+ | |||
+ | #define SENSORS_ACCELERATION | ||
+ | #define ID_A (0) | ||
+ | #define INPUT_DIR | ||
+ | #define SUPPORTED_SENSORS | ||
+ | #define EVENT_MASK_ACCEL_ALL | ||
+ | #define DEFAULT_THRESHOLD 100 | ||
+ | |||
+ | #define ACCELERATION_X (1 << ABS_X) | ||
+ | #define ACCELERATION_Y (1 << ABS_Y) | ||
+ | #define ACCELERATION_Z (1 << ABS_Z) | ||
+ | #define SENSORS_ACCELERATION_ALL (ACCELERATION_X | ACCELERATION_Y | \ | ||
+ | ACCELERATION_Z) | ||
+ | #define SEC_TO_NSEC 1000000000LL | ||
+ | #define USEC_TO_NSEC 1000 | ||
+ | #define MSEC_TO_USEC 1000 | ||
+ | |||
+ | #define ADXL_MAX_SAMPLE_RATE_VAL 11 /* 200 Hz */ | ||
+ | |||
+ | struct sensors_control_context_t { | ||
+ | struct sensors_control_device_t device; | ||
+ | int sensor_fd; | ||
+ | uint32_t active_sensors; | ||
+ | }; | ||
+ | |||
+ | struct sensors_data_context_t { | ||
+ | struct sensors_data_device_t device; | ||
+ | int event_fd; | ||
+ | sensors_data_t sensors[MAX_NUM_SENSORS]; | ||
+ | }; | ||
+ | |||
+ | static char input_name[20]; | ||
+ | static char devname[PATH_MAX]; | ||
+ | |||
+ | static int open_sensors_phy(struct sensors_control_device_t *dev, int keep_open) | ||
+ | { | ||
+ | char *filename; | ||
+ | int fd; | ||
+ | int res; | ||
+ | uint8_t bits[4]; | ||
+ | DIR *dir; | ||
+ | struct dirent *de; | ||
+ | char name[80]; | ||
+ | |||
+ | dir = opendir(INPUT_DIR); | ||
+ | if (dir == NULL) | ||
+ | return -1; | ||
+ | |||
+ | strcpy(devname, | ||
+ | filename = devname + strlen(devname); | ||
+ | *filename++ = '/'; | ||
+ | |||
+ | while ((de = readdir(dir))) { | ||
+ | if (de-> | ||
+ | (de-> | ||
+ | | ||
+ | continue; | ||
+ | strcpy(filename, | ||
+ | fd = open(devname, | ||
+ | if (fd < 0) { | ||
+ | LOGE(" | ||
+ | continue; | ||
+ | } | ||
+ | res = ioctl(fd, EVIOCGBIT(EV_ABS, | ||
+ | if (res <= 0 || bits[0] != EVENT_MASK_ACCEL_ALL) { | ||
+ | close(fd); | ||
+ | continue; | ||
+ | } | ||
+ | |||
+ | if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) { | ||
+ | name[0] = ' | ||
+ | } | ||
+ | |||
+ | if (!strcmp(name, | ||
+ | strcpy(input_name, | ||
+ | LOGD(" | ||
+ | } else { | ||
+ | close(fd); | ||
+ | continue; | ||
+ | } | ||
+ | closedir(dir); | ||
+ | if (keep_open) { | ||
+ | return fd; | ||
+ | } else { | ||
+ | close(fd); | ||
+ | return 0; | ||
+ | } | ||
+ | } | ||
+ | closedir(dir); | ||
+ | |||
+ | return -1; | ||
+ | } | ||
+ | |||
+ | static int write_int(char const *item, int value) | ||
+ | { | ||
+ | int fd; | ||
+ | static int already_warned = 0; | ||
+ | char path[80]; | ||
+ | |||
+ | if (input_name[0] == 0) | ||
+ | open_sensors_phy(NULL, | ||
+ | |||
+ | sprintf(path, | ||
+ | |||
+ | fd = open(path, O_RDWR); | ||
+ | if (fd >= 0) { | ||
+ | char buffer[20]; | ||
+ | int bytes = sprintf(buffer, | ||
+ | int amt = write(fd, buffer, bytes); | ||
+ | close(fd); | ||
+ | return amt == -1 ? -errno : 0; | ||
+ | } else { | ||
+ | if (already_warned == 0) { | ||
+ | LOGE(" | ||
+ | already_warned = 1; | ||
+ | } | ||
+ | return -errno; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /* | ||
+ | * the following is the list of all supported sensors | ||
+ | */ | ||
+ | static const struct sensor_t device_sensor_list[] = { | ||
+ | { | ||
+ | .name = " | ||
+ | .vendor = " | ||
+ | .version = 1, | ||
+ | .handle = ID_ACCELERATION, | ||
+ | .type = SENSOR_TYPE_ACCELEROMETER, | ||
+ | .maxRange = (GRAVITY_EARTH * 16.0f), | ||
+ | .resolution = (GRAVITY_EARTH * 16.0f) / 4096.0f, | ||
+ | .power = 0.145f, | ||
+ | .reserved = {}, | ||
+ | }, | ||
+ | }; | ||
+ | |||
+ | static int sensors_get_list(struct sensors_module_t *module, | ||
+ | struct sensor_t const **list) | ||
+ | { | ||
+ | *list = device_sensor_list; | ||
+ | return sizeof(device_sensor_list) / sizeof(device_sensor_list[0]); | ||
+ | } | ||
+ | |||
+ | /** Close the sensors device */ | ||
+ | static int sensors__common_close(struct hw_device_t *dev) | ||
+ | { | ||
+ | struct sensors_data_context_t *device_data = | ||
+ | (struct sensors_data_context_t *)dev; | ||
+ | |||
+ | if (device_data) { | ||
+ | if (device_data-> | ||
+ | close(device_data-> | ||
+ | |||
+ | free(device_data); | ||
+ | } | ||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | static native_handle_t* control_open_data_source(struct sensors_control_device_t *dev) | ||
+ | { | ||
+ | native_handle_t* handle; | ||
+ | int fd = open_sensors_phy(dev, | ||
+ | if (fd < 0) { | ||
+ | return NULL; | ||
+ | } | ||
+ | |||
+ | handle = native_handle_create(1, | ||
+ | handle-> | ||
+ | |||
+ | return handle; | ||
+ | } | ||
+ | |||
+ | static int control_activate(struct sensors_control_context_t *dev, | ||
+ | int handle, int enabled) | ||
+ | { | ||
+ | uint32_t mask = (1 << handle); | ||
+ | uint32_t sensors; | ||
+ | uint32_t new_sensors, | ||
+ | int value; | ||
+ | |||
+ | sensors = enabled ? mask : 0; | ||
+ | active = dev-> | ||
+ | new_sensors = (active & ~mask) | (sensors & mask); | ||
+ | changed = active ^ new_sensors; | ||
+ | if (!changed) | ||
+ | return 0; | ||
+ | |||
+ | dev-> | ||
+ | |||
+ | if (enabled) { | ||
+ | LOGD(" | ||
+ | value = 0; | ||
+ | } else { | ||
+ | LOGD(" | ||
+ | value = 1; | ||
+ | } | ||
+ | |||
+ | return write_int(" | ||
+ | } | ||
+ | |||
+ | static int control_set_delay(struct sensors_control_context_t *dev, int32_t ms) | ||
+ | { | ||
+ | int rate_val; | ||
+ | int32_t us = ms * MSEC_TO_USEC; | ||
+ | |||
+ | /* | ||
+ | * The ADXL34x Supports 16 sample rates ranging from 3200Hz-0.098Hz | ||
+ | * Calculate best fit and limit to max 200Hz (rate_val 11) | ||
+ | */ | ||
+ | |||
+ | for (rate_val = 0; rate_val < 16; rate_val++) | ||
+ | if (us >= ((10000 * MSEC_TO_USEC) >> rate_val)) | ||
+ | break; | ||
+ | |||
+ | if (rate_val > ADXL_MAX_SAMPLE_RATE_VAL) { | ||
+ | rate_val = ADXL_MAX_SAMPLE_RATE_VAL; | ||
+ | LOGD(" | ||
+ | ms, rate_val, (3200000 >> (15 - rate_val))); | ||
+ | } else { | ||
+ | LOGD(" | ||
+ | ms, rate_val, (3200000 >> (15 - rate_val))); | ||
+ | } | ||
+ | return write_int(" | ||
+ | } | ||
+ | |||
+ | static int control_wake(struct sensors_control_context_t *dev) | ||
+ | { | ||
+ | int err = 0; | ||
+ | int fd = open(devname, | ||
+ | if (fd > 0) { | ||
+ | struct input_event event[1]; | ||
+ | event[0].type = EV_SYN; | ||
+ | event[0].code = SYN_CONFIG; | ||
+ | event[0].value = 0; | ||
+ | err = write(fd, event, sizeof(event)); | ||
+ | LOGD_IF(err < 0, " | ||
+ | close(fd); | ||
+ | } | ||
+ | return err; | ||
+ | } | ||
+ | |||
+ | static int control_close(struct hw_device_t *dev) | ||
+ | { | ||
+ | struct sensors_control_context_t *device_control = (void *)dev; | ||
+ | |||
+ | if (device_control) { | ||
+ | if (device_control-> | ||
+ | close(device_control-> | ||
+ | free(device_control); | ||
+ | } | ||
+ | |||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | static int sensors__data_open(struct sensors_data_context_t *dev, native_handle_t* handle) | ||
+ | { | ||
+ | int i; | ||
+ | memset(& | ||
+ | |||
+ | for (i = 0; i < MAX_NUM_SENSORS; | ||
+ | dev-> | ||
+ | } | ||
+ | dev-> | ||
+ | /* native_handle_close(handle); | ||
+ | native_handle_delete(handle); | ||
+ | return 0; | ||
+ | |||
+ | } | ||
+ | |||
+ | static int sensors__data_close(struct sensors_data_device_t *dev) | ||
+ | { | ||
+ | struct sensors_data_context_t *data_device = | ||
+ | (struct sensors_data_context_t *)dev; | ||
+ | |||
+ | if (data_device-> | ||
+ | close(data_device-> | ||
+ | } | ||
+ | |||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | static int sensors__data_poll(struct sensors_data_context_t *dev, sensors_data_t * values) | ||
+ | { | ||
+ | struct input_event ev; | ||
+ | int ret; | ||
+ | uint32_t new_sensors = 0; | ||
+ | int fd = dev-> | ||
+ | |||
+ | while (1) { | ||
+ | ret = read(fd, &ev, sizeof(ev)); | ||
+ | |||
+ | if (ret < (int)sizeof(ev)) | ||
+ | break; | ||
+ | |||
+ | if (ev.type == EV_ABS) { | ||
+ | /* Orientation or acceleration event */ | ||
+ | switch (ev.code) { | ||
+ | case ABS_X: | ||
+ | new_sensors |= ACCELERATION_X; | ||
+ | dev-> | ||
+ | break; | ||
+ | case ABS_Y: | ||
+ | new_sensors |= ACCELERATION_Y; | ||
+ | dev-> | ||
+ | break; | ||
+ | case ABS_Z: | ||
+ | new_sensors |= ACCELERATION_Z; | ||
+ | dev-> | ||
+ | break; | ||
+ | } | ||
+ | } else if (ev.type == EV_SYN) { | ||
+ | |||
+ | if (ev.code == SYN_CONFIG) { | ||
+ | /* Injected event by control_wake | ||
+ | * return immediately | ||
+ | */ | ||
+ | return 0x7FFFFFFF; | ||
+ | } | ||
+ | |||
+ | /* | ||
+ | * Linux Input suppresses identical events, so if | ||
+ | * only ABS_Z changes and ABS_X,Y stays constant | ||
+ | * between events we need to report the cached values. | ||
+ | * Many other drivers start to scramble events by | ||
+ | * waiting for a full triplet to arrive. | ||
+ | * Other events on the ADXL345/6 such as TAP | ||
+ | * should be turned off. | ||
+ | */ | ||
+ | if (new_sensors) { | ||
+ | int64_t t = | ||
+ | ev.time.tv_sec * SEC_TO_NSEC + | ||
+ | ev.time.tv_usec * USEC_TO_NSEC; | ||
+ | new_sensors = 0; | ||
+ | |||
+ | dev-> | ||
+ | *values = dev-> | ||
+ | values-> | ||
+ | return ID_ACCELERATION; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | / | ||
+ | |||
+ | /** | ||
+ | * module methods | ||
+ | */ | ||
+ | |||
+ | /** Open a new instance of a sensor device using name */ | ||
+ | static int open_sensors(const struct hw_module_t *module, const char *name, | ||
+ | struct hw_device_t **device) | ||
+ | { | ||
+ | int status = -EINVAL; | ||
+ | if (!strcmp(name, | ||
+ | struct sensors_control_context_t *dev; | ||
+ | dev = malloc(sizeof(*dev)); | ||
+ | memset(dev, | ||
+ | dev-> | ||
+ | dev-> | ||
+ | dev-> | ||
+ | dev-> | ||
+ | dev-> | ||
+ | dev-> | ||
+ | dev-> | ||
+ | dev-> | ||
+ | dev-> | ||
+ | *device = & | ||
+ | } else if (!strcmp(name, | ||
+ | struct sensors_data_context_t *dev; | ||
+ | dev = malloc(sizeof(*dev)); | ||
+ | memset(dev, | ||
+ | dev-> | ||
+ | dev-> | ||
+ | dev-> | ||
+ | dev-> | ||
+ | dev-> | ||
+ | dev-> | ||
+ | dev-> | ||
+ | dev-> | ||
+ | *device = & | ||
+ | } | ||
+ | return status; | ||
+ | } | ||
+ | |||
+ | static struct hw_module_methods_t sensors_module_methods = { | ||
+ | .open = open_sensors, | ||
+ | }; | ||
+ | |||
+ | /* | ||
+ | * The Sensors Hardware Module | ||
+ | */ | ||
+ | const struct sensors_module_t HAL_MODULE_INFO_SYM = { | ||
+ | .common = { | ||
+ | .tag = HARDWARE_MODULE_TAG, | ||
+ | | ||
+ | | ||
+ | .id = SENSORS_HARDWARE_MODULE_ID, | ||
+ | .name = " | ||
+ | | ||
+ | | ||
+ | }, | ||
+ | .get_sensors_list = sensors_get_list, | ||
+ | }; | ||
+ | |||
+ | </code> |