aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJimmy Huang <jimmy.huang@linux.intel.com>2017-03-31 10:10:21 -0700
committerGeoff Gustafson <geoff@linux.intel.com>2017-03-31 10:10:21 -0700
commit62856bdb22d376738d49b55ddb8338134cd31afe (patch)
tree46fc9fc85876fcacf8c9d1afeb2b476d8813293f
parent380261afbceb46c5b6ca27ca00b491871ef18104 (diff)
[sensor] Add support for TemperatureSensor (#937)
Refactor ARC code to support temperature sensors, also added new sample BMI160Temperature.js that monitors the BMI160 sensor Signed-off-by: Jimmy Huang <jimmy.huang@intel.com>
-rw-r--r--arc/src/main.c63
-rw-r--r--docs/sensors.md51
-rw-r--r--samples/BMI160Temperature.js28
-rwxr-xr-xscripts/analyze.sh4
-rwxr-xr-xscripts/trlite2
-rw-r--r--src/zjs_sensor.c40
6 files changed, 161 insertions, 27 deletions
diff --git a/arc/src/main.c b/arc/src/main.c
index 55b059c..c2259d5 100644
--- a/arc/src/main.c
+++ b/arc/src/main.c
@@ -25,7 +25,6 @@
#define QUEUE_SIZE 10 // max incoming message can handle
#define SLEEP_TICKS 1 // 10ms sleep time in cpu ticks
#define AIO_UPDATE_INTERVAL 200 // 2sec interval in between notifications
-#define LIGHT_UPDATE_INTERVAL 10 // 0.1sec interval for light or 10Hz
#define MAX_I2C_BUS 2
@@ -65,11 +64,14 @@ static char str[MAX_BUFFER_SIZE];
#endif
#ifdef BUILD_MODULE_SENSOR
+static uint32_t sensor_poll_freq = 20; // default poll frequency
static struct device *bmi160 = NULL;
-static bool accel_trigger = false;
-static bool gyro_trigger = false;
+static bool accel_trigger = false; // trigger mode
+static bool gyro_trigger = false; // trigger mode
+static bool temp_poll = false; // polling mode
static double accel_last_value[3];
static double gyro_last_value[3];
+static double temp_last_value;
#endif
int ipm_send_msg(struct zjs_ipm_message *msg)
@@ -661,6 +663,31 @@ static int stop_gyro_trigger(struct device *dev)
return 0;
}
+static void fetch_sensor()
+{
+ // ToDo: currently only supports BMI160 temperature
+ // add support for other types of sensors
+ if (temp_poll && bmi160) {
+ if (sensor_sample_fetch(bmi160) < 0) {
+ ERR_PRINT("failed to fetch sample from sensor\n");
+ return;
+ }
+
+ struct sensor_value val;
+ if (sensor_channel_get(bmi160, SENSOR_CHAN_TEMP, &val) < 0) {
+ ERR_PRINT("Temperature channel read error.\n");
+ return;
+ }
+
+ union sensor_reading reading;
+ double dval = convert_sensor_value(&val);
+ if (dval != temp_last_value) {
+ reading.dval = temp_last_value = dval;
+ send_sensor_data(SENSOR_CHAN_TEMP, reading);
+ }
+ }
+}
+
#ifdef BUILD_MODULE_SENSOR_LIGHT
static double cube_root_recursive(double num, double low, double high) {
// calculate approximated cube root value of a number recursively
@@ -715,7 +742,7 @@ static void fetch_light()
}
#endif // BUILD_MODULE_SENSOR_LIGHT
-static void handle_sensor_bmi160_motion(struct zjs_ipm_message *msg)
+static void handle_sensor_bmi160(struct zjs_ipm_message *msg)
{
int freq;
uint32_t error_code = ERROR_IPM_NONE;
@@ -748,6 +775,13 @@ static void handle_sensor_bmi160_motion(struct zjs_ipm_message *msg)
start_gyro_trigger(bmi160, freq) != 0)) {
error_code = ERROR_IPM_OPERATION_FAILED;
}
+ } else if (msg->data.sensor.channel == SENSOR_CHAN_TEMP) {
+ if (!bmi160 || temp_poll) {
+ error_code = ERROR_IPM_OPERATION_FAILED;
+ } else {
+ sensor_poll_freq = msg->data.sensor.frequency;
+ temp_poll = true;
+ }
}
break;
case TYPE_SENSOR_STOP:
@@ -761,6 +795,13 @@ static void handle_sensor_bmi160_motion(struct zjs_ipm_message *msg)
stop_gyro_trigger(bmi160) != 0)) {
error_code = ERROR_IPM_OPERATION_FAILED;
}
+ } else if (msg->data.sensor.channel == SENSOR_CHAN_TEMP) {
+ if (!bmi160 || !temp_poll) {
+ error_code = ERROR_IPM_OPERATION_FAILED;
+ } else {
+ sensor_poll_freq = msg->data.sensor.frequency;
+ temp_poll = false;
+ }
}
break;
default:
@@ -824,7 +865,7 @@ static void handle_sensor(struct zjs_ipm_message *msg)
case SENSOR_CHAN_ACCEL_XYZ:
case SENSOR_CHAN_GYRO_XYZ:
if (!strncmp(controller, BMI160_NAME, 6)) {
- handle_sensor_bmi160_motion(msg);
+ handle_sensor_bmi160(msg);
return;
}
break;
@@ -836,6 +877,12 @@ static void handle_sensor(struct zjs_ipm_message *msg)
}
break;
#endif
+ case SENSOR_CHAN_TEMP:
+ if (!strncmp(controller, BMI160_NAME, 6)) {
+ handle_sensor_bmi160(msg);
+ return;
+ }
+ break;
default:
ERR_PRINT("unsupported sensor channel\n");
@@ -913,9 +960,13 @@ void main(void)
process_aio_updates();
}
#endif
+#ifdef BUILD_MODULE_SENSOR
+ if (tick_count % (uint32_t)(CONFIG_SYS_CLOCK_TICKS_PER_SEC /
+ sensor_poll_freq) == 0) {
+ fetch_sensor();
#ifdef BUILD_MODULE_SENSOR_LIGHT
- if (tick_count % LIGHT_UPDATE_INTERVAL == 0) {
fetch_light();
+#endif
}
#endif
tick_count += SLEEP_TICKS;
diff --git a/docs/sensors.md b/docs/sensors.md
index ef198b7..173e926 100644
--- a/docs/sensors.md
+++ b/docs/sensors.md
@@ -12,11 +12,13 @@ ZJS Generic Sensor API implements the W3C Sensor API, and it's intended to
provide a consistent API that allows apps to communicate with sensors like
accelerometer and gyroscope. Since the W3C Sensor API is still a draft spec,
our implementation only provide a subset of the API and the API could be
-slightly different, but we try to follow the latest spec as closely as possible.
+slightly different, but we try to follow the latest spec as closely as
+possible.
-The currently supported hardware are Arduino 101s with its built-in BMI160
-accelerometer and gyroscope, also ambient light sensor that can be connected
-using analog pin.
+Note: The currently supported hardware is Arduino 101 with its built-in
+BMI160 chip with accelerometer, gyroscope, and temperature. The supported
+ambient light sensor is the Grove light sensor that comes with the
+Grove starter kit, that can be connected using an analog pin.
Web IDL
-------
@@ -26,17 +28,18 @@ specific API functions.
####Sensor Interface
```javascript
interface Sensor {
- readonly attribute SensorState state; // The current state of Sensor object
- attribute double frequency; // The frequency set
- void start(); // Starts the sensor
- void stop(); // Stops the sensor
- attribute ChangeCallback onchange; // Callback handler for change events
- attribute ActivateCallback onactivate; // Callback handler for activate events
- attribute ErrorCallback onerror; // Callback handler for error events
+ readonly attribute SensorState state; // current state of Sensor object
+ readonly attribute double timestamp; // timestamp of the latest reading in milliseconds
+ attribute double frequency; // sampling frequency in hertz
+ void start(); // starts the sensor
+ void stop(); // stops the sensor
+ attribute ChangeCallback onchange; // callback handler for change events
+ attribute ActivateCallback onactivate; // callback handler for activate events
+ attribute ErrorCallback onerror; // callback handler for error events
};
dictionary SensorOptions {
- double frequency; // The requested polling frequency, default is 20 if unset
+ double frequency; // desire frequency, default is 20 if unset
};
enum SensorState {
@@ -66,21 +69,22 @@ interface Accelerometer : Sensor {
};
dictionary AccelerometerOptions : SensorOptions {
- boolean includeGravity = true; // not supported, will throw an error if set
+ string controller; // controller name, default to "bmi160"
+ boolean includeGravity; // not supported currently
};
```
####GyroscopeSensor Interface
```javascript
[Constructor(optional SensorOptions sensorOptions)]
interface GyroscopeSensor : Sensor {
- attribute GyroscopeSensorReading reading;
-};
-
-interface GyroscopeSensorReading : SensorReading {
readonly attribute double x;
readonly attribute double y;
readonly attribute double z;
};
+
+dictionary GyroscopeOptions : SensorOptions {
+ string controller; // controller name, default to "bmi160"
+};
```
####AmbientLightSensor Interface
```javascript
@@ -91,9 +95,21 @@ interface AmbientLightSensor : Sensor {
};
dictionary AmbientLightSensorOptions : SensorOptions {
+ string controller; // controller name, default to "ADC_0"
unsigned long pin; // analog pin where the light is connected
};
```
+####TemperatureSensor Interface
+```javascript
+[Constructor(optional SensorOptions sensorOptions)]
+interface TemperatureSensor : Sensor {
+ readonly attribute double celsius;
+};
+
+dictionary TemperatureSensorOptions : SensorOptions {
+ string controller; // controller name, default to "bmi160"
+};
+```
API Documentation
-----------------
@@ -128,3 +144,4 @@ Sample Apps
* [Accelerometer sample](../samples/BMI160Accelerometer.js)
* [Gyroscope sample](../samples/BMI160Gyroscope.js)
* [Ambient Light sample](../samples/AmbientLight.js)
+* [Temperature sample](../samples/BMI160Temperature.js)
diff --git a/samples/BMI160Temperature.js b/samples/BMI160Temperature.js
new file mode 100644
index 0000000..0229a14
--- /dev/null
+++ b/samples/BMI160Temperature.js
@@ -0,0 +1,28 @@
+// Copyright (c) 2017, Intel Corporation.
+
+// Test code to use the TemperatureSensor (subclass of Generic Sensor) API
+// to communicate with the BMI160 inertia sensor on the Arduino 101
+// to monitors the onboard chip temperature
+console.log("BMI160 temperature test...");
+
+var updateFrequency = 20; // maximum is 100Hz, but in ashell maximum is 20Hz
+
+var sensor = new TemperatureSensor({
+ controller: "bmi160",
+ frequency: updateFrequency
+});
+
+sensor.onchange = function() {
+ console.log("BMI160 temperature (celsius): " + sensor.celsius);
+};
+
+sensor.onstatechange = function(event) {
+ console.log("state: " + event);
+};
+
+sensor.onerror = function(event) {
+ console.log("error: " + event.error.name +
+ " - " + event.error.message);
+};
+
+sensor.start();
diff --git a/scripts/analyze.sh b/scripts/analyze.sh
index 14e4d3e..d60e3f6 100755
--- a/scripts/analyze.sh
+++ b/scripts/analyze.sh
@@ -316,13 +316,13 @@ if $buffer && [[ $MODULE != *"BUILD_MODULE_BUFFER"* ]]; then
MODULES+=" -DBUILD_MODULE_BUFFER"
echo "export ZJS_BUFFER=y" >> $CONFFILE
fi
-sensor=$(grep -E Accelerometer\|Gyroscope\|AmbientLightSensor $SCRIPT)
+sensor=$(grep -E Accelerometer\|Gyroscope\|AmbientLightSensor\|TemperatureSensor $SCRIPT)
if [ $? -eq 0 ] || check_config_file ZJS_SENSOR; then
>&2 echo Using module: Sensor
MODULES+=" -DBUILD_MODULE_SENSOR"
echo "export ZJS_SENSOR=y" >> $CONFFILE
if [[ $BOARD = "arduino_101" ]] || [[ $ASHELL = "y" ]]; then
- bmi160=$(grep -E Accelerometer\|Gyroscope $SCRIPT)
+ bmi160=$(grep -E Accelerometer\|Gyroscope\|TemperatureSensor $SCRIPT)
if [[ $? -eq 0 ]] || [[ $ASHELL = "y" ]]; then
echo "CONFIG_SENSOR=y" >> $ARCPRJFILE
echo "CONFIG_GPIO=y" >> $ARCPRJFILE
diff --git a/scripts/trlite b/scripts/trlite
index 848e0aa..d6cc6ef 100755
--- a/scripts/trlite
+++ b/scripts/trlite
@@ -240,7 +240,7 @@ if [ "$RUN" == "all" -o "$RUN" == "1" ]; then
done
# add sensor modules
- SENSORS=(Accelerometer Gyroscope AmbientLightSensor)
+ SENSORS=(Accelerometer Gyroscope AmbientLightSensor TemperatureSensor)
SENSORNUM=0
for index in "${!SENSORS[@]}"; do
SENSORNUM=$((SENSORNUM + 1))
diff --git a/src/zjs_sensor.c b/src/zjs_sensor.c
index 6bd830e..277ebb3 100644
--- a/src/zjs_sensor.c
+++ b/src/zjs_sensor.c
@@ -48,6 +48,7 @@ typedef struct sensor_handle {
static sensor_handle_t *accel_handles = NULL;
static sensor_handle_t *gyro_handles = NULL;
static sensor_handle_t *light_handles = NULL;
+static sensor_handle_t *temp_handles = NULL;
static sensor_handle_t *zjs_sensor_alloc_handle(enum sensor_channel channel)
{
@@ -65,6 +66,8 @@ static sensor_handle_t *zjs_sensor_alloc_handle(enum sensor_channel channel)
head = &gyro_handles;
} else if (channel == SENSOR_CHAN_LIGHT) {
head = &light_handles;
+ } else if (channel == SENSOR_CHAN_TEMP) {
+ head = &temp_handles;
} else {
ERR_PRINT("invalid channel\n");
zjs_free(handle);
@@ -239,6 +242,11 @@ static void zjs_sensor_update_reading(jerry_value_t obj,
d = *((double *)reading);
zjs_obj_add_readonly_number(obj, d, "illuminance");
break;
+ case SENSOR_CHAN_TEMP:
+ // reading is a ptr to double
+ d = *((double *)reading);
+ zjs_obj_add_readonly_number(obj, d, "celsius");
+ break;
default:
ERR_PRINT("unsupported sensor type\n");
@@ -312,6 +320,9 @@ static void zjs_sensor_signal_callbacks(struct sensor_data *data)
case SENSOR_CHAN_LIGHT:
handles = light_handles;
break;
+ case SENSOR_CHAN_TEMP:
+ handles = temp_handles;
+ break;
default:
ERR_PRINT("unsupported sensor type\n");
@@ -426,6 +437,8 @@ static void zjs_sensor_onstop_c_callback(void *h, const void *argv)
break;
case SENSOR_CHAN_LIGHT:
zjs_set_readonly_property(obj, "illuminance", null_val);
+ case SENSOR_CHAN_TEMP:
+ zjs_set_readonly_property(obj, "celsius", null_val);
break;
default:
@@ -551,7 +564,10 @@ static jerry_value_t zjs_sensor_create(const jerry_value_t function_obj,
double option_freq;
if (zjs_obj_get_double(options, "frequency", &option_freq)) {
- if (option_freq < 1) {
+ if (option_freq < 1 || (option_freq > 100 &&
+ channel != SENSOR_CHAN_ACCEL_XYZ &&
+ channel != SENSOR_CHAN_GYRO_XYZ) ) {
+ // limit frequency to 100 max unless it's accel/gyro
ERR_PRINT("unsupported frequency, default to %dHz\n",
DEFAULT_SAMPLING_FREQUENCY);
} else {
@@ -599,7 +615,10 @@ static jerry_value_t zjs_sensor_create(const jerry_value_t function_obj,
zjs_set_readonly_property(sensor_obj, "z", null_val);
} else if (channel == SENSOR_CHAN_LIGHT) {
zjs_set_readonly_property(sensor_obj, "illuminance", null_val);
+ } else if (channel == SENSOR_CHAN_TEMP) {
+ zjs_set_readonly_property(sensor_obj, "celsius", null_val);
}
+
zjs_obj_add_number(sensor_obj, frequency, "frequency");
zjs_obj_add_readonly_string(sensor_obj, "unconnected", "state");
jerry_set_prototype(sensor_obj, zjs_sensor_prototype);
@@ -673,6 +692,21 @@ static jerry_value_t zjs_light_create(const jerry_value_t function_obj,
SENSOR_CHAN_LIGHT);
}
+static jerry_value_t zjs_temp_create(const jerry_value_t function_obj,
+ const jerry_value_t this,
+ const jerry_value_t argv[],
+ const jerry_length_t argc)
+{
+ // requires: arg 0 is an object containing sensor options:
+ // frequency (double) - sampling frequency
+ // effects: Creates a TemperatureSensor object to the local sensor
+ return zjs_sensor_create(function_obj,
+ this,
+ argv,
+ argc,
+ SENSOR_CHAN_TEMP);
+}
+
void zjs_sensor_init()
{
zjs_ipm_init();
@@ -693,6 +727,7 @@ void zjs_sensor_init()
zjs_obj_add_function(global_obj, zjs_accel_create, "Accelerometer");
zjs_obj_add_function(global_obj, zjs_gyro_create, "Gyroscope");
zjs_obj_add_function(global_obj, zjs_light_create, "AmbientLightSensor");
+ zjs_obj_add_function(global_obj, zjs_temp_create, "TemperatureSensor");
}
void zjs_sensor_cleanup()
@@ -706,6 +741,9 @@ void zjs_sensor_cleanup()
if (light_handles) {
zjs_sensor_free_handles(light_handles);
}
+ if (temp_handles) {
+ zjs_sensor_free_handles(temp_handles);
+ }
jerry_release_value(zjs_sensor_prototype);
}