diff options
author | Jimmy Huang <jimmy.huang@linux.intel.com> | 2017-03-31 10:10:21 -0700 |
---|---|---|
committer | Geoff Gustafson <geoff@linux.intel.com> | 2017-03-31 10:10:21 -0700 |
commit | 62856bdb22d376738d49b55ddb8338134cd31afe (patch) | |
tree | 46fc9fc85876fcacf8c9d1afeb2b476d8813293f | |
parent | 380261afbceb46c5b6ca27ca00b491871ef18104 (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.c | 63 | ||||
-rw-r--r-- | docs/sensors.md | 51 | ||||
-rw-r--r-- | samples/BMI160Temperature.js | 28 | ||||
-rwxr-xr-x | scripts/analyze.sh | 4 | ||||
-rwxr-xr-x | scripts/trlite | 2 | ||||
-rw-r--r-- | src/zjs_sensor.c | 40 |
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); } |