blob: 628068d79c25b75220000a2a6c3f292873f648a0 [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* 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/licenses/LICENSE-2.0
*
* 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.
*/
/* This file contains an example app that uses sensors NDK.
* It accepts a sensor type as an input argument and reads data from a
* sensor of that type.
*
* For any specified sensor type, there may be multiple such sensors defined
* in the HAL. Some or all of the defined sensors will actually be equipped.
* This test program will scan the HAL for the first equipped sensor of
* the specified sensor type and dump data from that sensor.
*/
#include <getopt.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <android/looper.h>
#include <android/sensor.h>
#include <hardware/sensors.h>
#define DEFAULT_SENSOR_TYPE SENSOR_TYPE_ACCELEROMETER
// Structure to hold the decoded command line options
struct pgm_options {
int sensor_type;
};
// Be sure to keep the options for longopts and shortopts in the same order
// so that Usage() is correct.
static struct option longopts[] = {
{"help", no_argument, NULL, '?'},
{"accel", no_argument, NULL, 'a'},
{"temp", no_argument, NULL, 't'},
{"light", no_argument, NULL, 'l'},
{"orient", no_argument, NULL, 'o'},
{"prox", no_argument, NULL, 'p'},
{"motion", no_argument, NULL, 'm'},
{NULL, 0, NULL, 0}
};
static char shortopts[] = "?atlopm";
// Describes the options for this program.
void Usage(char *pgm_name) {
printf("Usage: %s [options...]\n", pgm_name);
printf("Exercises the sensors NDK by calling into the sensorserver.\n");
printf("Options:\n");
for (int i = 0; longopts[i].name; i++) {
printf(" --%-6s or -%c\n", longopts[i].name, shortopts[i]);
}
}
// Processes all command line options.
// sets the options members for commnd line options
// returns (0) on success, -1 otherwise.
int ReadOpts(int argc, char **argv, struct pgm_options *options) {
int ch = 0;
if (!options) {
fprintf(stderr, "Invalid options pointer\n");
return 1;
}
while ((ch = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
switch (ch) {
case 'a':
options->sensor_type = SENSOR_TYPE_ACCELEROMETER;
break;
case 't':
options->sensor_type = SENSOR_TYPE_TEMPERATURE;
break;
case 'l':
options->sensor_type = SENSOR_TYPE_LIGHT;
break;
case 'o':
options->sensor_type = SENSOR_TYPE_ORIENTATION;
break;
case 'p':
options->sensor_type = SENSOR_TYPE_PROXIMITY;
break;
case 'm':
options->sensor_type = SENSOR_TYPE_SIGNIFICANT_MOTION;
break;
default:
Usage(argv[0]);
return -1;
}
}
argc -= optind;
argv += optind;
return 0;
}
// Prints data associated with each supported sensor type.
// Be sure to provide a case for each sensor type supported in
// the ReadOpts() function.
void DisplaySensorData(int sensor_type, const ASensorEvent *data) {
switch (sensor_type) {
case SENSOR_TYPE_PROXIMITY:
printf("Proximity distance: %f\n", data->distance);
break;
case SENSOR_TYPE_SIGNIFICANT_MOTION:
if (data->data[0] == 1) {
printf("Significant motion detected\n");
}
break;
case SENSOR_TYPE_ACCELEROMETER:
printf("Acceleration: x = %f, y = %f, z = %f\n",
data->acceleration.x, data->acceleration.y, data->acceleration.z);
break;
case SENSOR_TYPE_TEMPERATURE:
printf("Temperature: %f\n", data->temperature);
break;
case SENSOR_TYPE_LIGHT:
printf("Light: %f\n", data->light);
break;
case SENSOR_TYPE_ORIENTATION: {
float heading =
atan2(static_cast<double>(data->magnetic.y),
static_cast<double>(data->magnetic.x)) * 180.0 / M_PI;
if (heading < 0.0)
heading += 360.0;
printf("Heading: %f, Orientation: x = %f, y = %f, z = %f\n",
heading, data->magnetic.x, data->magnetic.y, data->magnetic.z);
}
break;
}
}
int main(int argc, char* argv[]) {
pgm_options options = {DEFAULT_SENSOR_TYPE};
if (ReadOpts(argc, argv, &options) < 0)
return 1;
const char kPackageName[] = "ndk-example-app";
ASensorManager* sensor_manager =
ASensorManager_getInstanceForPackage(kPackageName);
if (!sensor_manager) {
fprintf(stderr, "Failed to get a sensor manager\n");
return 1;
}
ASensorList sensor_list = nullptr;
int sensor_count = ASensorManager_getSensorList(sensor_manager, &sensor_list);
printf("Found %d supported sensors\n", sensor_count);
for (int i = 0; i < sensor_count; i++) {
printf("HAL supports sensor %s\n", ASensor_getName(sensor_list[i]));
}
const int kLooperId = 1;
ASensorEventQueue* queue = ASensorManager_createEventQueue(
sensor_manager,
ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS),
kLooperId,
NULL, /* no callback */
NULL /* no private data for a callback */);
if (!queue) {
fprintf(stderr, "Failed to create a sensor event queue\n");
return 1;
}
// Find the first sensor of the specified type that can be opened
const int kTimeoutMicroSecs = 1000000;
const int kTimeoutMilliSecs = 1000;
ASensorRef sensor = nullptr;
bool sensor_found = false;
for (int i = 0; i < sensor_count; i++) {
sensor = sensor_list[i];
if (ASensor_getType(sensor) != options.sensor_type)
continue;
if (ASensorEventQueue_enableSensor(queue, sensor) < 0)
continue;
if (ASensorEventQueue_setEventRate(queue, sensor, kTimeoutMicroSecs) < 0) {
fprintf(stderr, "Failed to set the %s sample rate\n",
ASensor_getName(sensor));
return 1;
}
// Found an equipped sensor of the specified type.
sensor_found = true;
break;
}
if (!sensor_found) {
fprintf(stderr, "No sensor of the specified type found\n");
int ret = ASensorManager_destroyEventQueue(sensor_manager, queue);
if (ret < 0)
fprintf(stderr, "Failed to destroy event queue: %s\n", strerror(-ret));
return 1;
}
printf("\nSensor %s activated\n", ASensor_getName(sensor));
const int kNumEvents = 1;
const int kNumSamples = 10;
const int kWaitTimeSecs = 1;
for (int i = 0; i < kNumSamples; i++) {
ASensorEvent data[kNumEvents];
memset(data, 0, sizeof(data));
int ident = ALooper_pollAll(
kTimeoutMilliSecs,
NULL /* no output file descriptor */,
NULL /* no output event */,
NULL /* no output data */);
if (ident != kLooperId) {
fprintf(stderr, "Incorrect Looper ident read from poll.\n");
continue;
}
if (ASensorEventQueue_getEvents(queue, data, kNumEvents) <= 0) {
fprintf(stderr, "Failed to read data from the sensor.\n");
continue;
}
DisplaySensorData(options.sensor_type, data);
sleep(kWaitTimeSecs);
}
int ret = ASensorEventQueue_disableSensor(queue, sensor);
if (ret < 0) {
fprintf(stderr, "Failed to disable %s: %s\n",
ASensor_getName(sensor), strerror(-ret));
}
ret = ASensorManager_destroyEventQueue(sensor_manager, queue);
if (ret < 0) {
fprintf(stderr, "Failed to destroy event queue: %s\n", strerror(-ret));
return 1;
}
return 0;
}