diff --git a/arc/src/main.c b/arc/src/main.c index 681e99d8b..903173bfc 100644 --- a/arc/src/main.c +++ b/arc/src/main.c @@ -26,18 +26,12 @@ #define SLEEP_TICKS 1 // 10ms sleep time in cpu ticks #define UPDATE_INTERVAL 200 // 2sec interval in between notifications -#ifdef BUILD_MODULE_AIO #define ADC_DEVICE_NAME "ADC_0" #define ADC_BUFFER_SIZE 2 -#endif -#ifdef BUILD_MODULE_I2C #define MAX_I2C_BUS 1 -#endif -#ifdef BUILD_MODULE_GROVE_LCD #define MAX_BUFFER_SIZE 256 -#endif static struct nano_sem arc_sem; static struct zjs_ipm_message msg_queue[QUEUE_SIZE]; @@ -63,8 +57,8 @@ static char str[MAX_BUFFER_SIZE]; #ifdef BUILD_MODULE_SENSOR static struct device *bmi160 = NULL; -static bool accel_poll = false; -static bool gyro_poll = false; +static bool accel_trigger = false; +static bool gyro_trigger = false; static double accel_last_value[3]; static double gyro_last_value[3]; #endif @@ -428,7 +422,7 @@ static void handle_glcd(struct zjs_ipm_message* msg) } #endif -#ifdef BUILD_MODULE_SENSOR +#ifdef BUILD_MODULE_SENSOR #ifdef DEBUG_BUILD static inline int sensor_value_snprintf(char *buf, size_t len, const struct sensor_value *val) @@ -533,7 +527,7 @@ static void process_accel_data(struct device *dev) double dval[3]; if (sensor_channel_get(dev, SENSOR_CHAN_ACCEL_ANY, val) < 0) { - ZJS_PRINT("Cannot read accelerometer channels.\n"); + ZJS_PRINT("failed to read accelerometer channels\n"); return; } @@ -541,11 +535,6 @@ static void process_accel_data(struct device *dev) dval[1] = convert_sensor_value(&val[1]); dval[2] = convert_sensor_value(&val[2]); - if (dval[0] == 0 && dval[1] == 0 && dval[2] == 0) { - // FIXME: BUG? why sometimes it reports 0, 0, 0 on all axes - return; - } - // set slope threshold to 0.1G (0.1 * 9.80665 = 4.903325 m/s^2) double threshold = 0.980665; if (ABS(dval[0] - accel_last_value[0]) > threshold || @@ -574,7 +563,7 @@ static void process_gyro_data(struct device *dev) double dval[3]; if (sensor_channel_get(dev, SENSOR_CHAN_GYRO_ANY, val) < 0) { - ZJS_PRINT("Cannot read gyroscope channels.\n"); + ZJS_PRINT("failed to read gyroscope channels\n"); return; } @@ -598,20 +587,26 @@ static void process_gyro_data(struct device *dev) sensor_value_snprintf(buf_x, sizeof(buf_x), &val[0]); sensor_value_snprintf(buf_y, sizeof(buf_y), &val[1]); sensor_value_snprintf(buf_z, sizeof(buf_z), &val[2]); - ZJS_PRINT("Sending gyro : X=%s, Y=%s, Z=%s\n", buf_x, buf_y, buf_z); + ZJS_PRINT("sending gyro: X=%s, Y=%s, Z=%s\n", buf_x, buf_y, buf_z); #endif } -static void fetch_sensor(struct device *dev) { +static void trigger_hdlr(struct device *dev, + struct sensor_trigger *trigger) +{ + if (trigger->type != SENSOR_TRIG_DELTA && + trigger->type != SENSOR_TRIG_DATA_READY) { + return; + } + if (sensor_sample_fetch(dev) < 0) { ZJS_PRINT("failed to fetch sensor data\n"); return; } - if (accel_poll) { + if (trigger->chan == SENSOR_CHAN_ACCEL_ANY) { process_accel_data(dev); - } - if (gyro_poll) { + } else if (trigger->chan == SENSOR_CHAN_GYRO_ANY) { process_gyro_data(dev); } } @@ -627,12 +622,12 @@ struct sensor_value acc_calib[] = { {SENSOR_VALUE_TYPE_INT_PLUS_MICRO, { {9, 806650} } }, /* Z */ }; -static bool auto_calibration(struct device *dev) +static int auto_calibration(struct device *dev) { /* calibrate accelerometer */ if (sensor_attr_set(dev, SENSOR_CHAN_ACCEL_ANY, SENSOR_ATTR_CALIB_TARGET, acc_calib) < 0) { - return false; + return -1; } /* @@ -642,10 +637,129 @@ static bool auto_calibration(struct device *dev) */ if (sensor_attr_set(dev, SENSOR_CHAN_GYRO_ANY, SENSOR_ATTR_CALIB_TARGET, NULL) < 0) { - return false; + return -1; } - return true; + return 0; +} + +static int start_accel_trigger(struct device *dev) +{ + struct sensor_value attr; + struct sensor_trigger trig; + + // set accelerometer range to +/- 16G. Since the sensor API needs SI + // units, convert the range to m/s^2. + sensor_g_to_ms2(16, &attr); + + if (sensor_attr_set(dev, SENSOR_CHAN_ACCEL_ANY, + SENSOR_ATTR_FULL_SCALE, &attr) < 0) { + ZJS_PRINT("failed to set accelerometer range\n"); + return -1; + } + + // set sampling frequency to 50Hz for accelerometer + attr.type = SENSOR_VALUE_TYPE_INT_PLUS_MICRO; + attr.val1 = 50; + attr.val2 = 0; + + if (sensor_attr_set(dev, SENSOR_CHAN_ACCEL_ANY, + SENSOR_ATTR_SAMPLING_FREQUENCY, &attr) < 0) { + ZJS_PRINT("failed to set accelerometer sampling frequency\n"); + return -1; + } + + // set slope threshold to 0.1G (0.1 * 9.80665 = 4.903325 m/s^2). + attr.type = SENSOR_VALUE_TYPE_INT_PLUS_MICRO; + attr.val1 = 0; + attr.val2 = 980665; + if (sensor_attr_set(dev, SENSOR_CHAN_ACCEL_ANY, + SENSOR_ATTR_SLOPE_TH, &attr) < 0) { + ZJS_PRINT("failed set slope threshold\n"); + return -1; + } + + // set slope duration to 2 consecutive samples + attr.type = SENSOR_VALUE_TYPE_INT; + attr.val1 = 2; + if (sensor_attr_set(dev, SENSOR_CHAN_ACCEL_ANY, + SENSOR_ATTR_SLOPE_DUR, &attr) < 0) { + ZJS_PRINT("failed to set slope duration\n"); + return -1; + } + + // set data ready trigger handler + trig.type = SENSOR_TRIG_DATA_READY; + trig.chan = SENSOR_CHAN_ACCEL_ANY; + + if (sensor_trigger_set(dev, &trig, trigger_hdlr) < 0) { + ZJS_PRINT("failed to enable accelerometer trigger\n"); + return -1; + } + + accel_trigger = true; + return 0; +} + +static int stop_accel_trigger(struct device *dev) +{ + struct sensor_trigger trig; + + trig.type = SENSOR_TRIG_DATA_READY; + trig.chan = SENSOR_CHAN_ACCEL_ANY; + + if (sensor_trigger_set(bmi160, &trig, NULL) < 0) { + ZJS_PRINT("failed to disable accelerometer trigger\n"); + return -1; + } + + accel_trigger = false; + return 0; +} + +static int start_gyro_trigger(struct device *dev) +{ + struct sensor_value attr; + struct sensor_trigger trig; + + // set sampling frequency to 50Hz for gyroscope + attr.type = SENSOR_VALUE_TYPE_INT_PLUS_MICRO; + attr.val1 = 50; + attr.val2 = 0; + + if (sensor_attr_set(bmi160, SENSOR_CHAN_GYRO_ANY, + SENSOR_ATTR_SAMPLING_FREQUENCY, &attr) < 0) { + ZJS_PRINT("failed to set sampling frequency for gyroscope.\n"); + return -1; + } + + // set data ready trigger handler + trig.type = SENSOR_TRIG_DATA_READY; + trig.chan = SENSOR_CHAN_GYRO_ANY; + + if (sensor_trigger_set(bmi160, &trig, trigger_hdlr) < 0) { + ZJS_PRINT("failed to enable gyroscope trigger.\n"); + return -1; + } + + gyro_trigger = true; + return 0; +} + +static int stop_gyro_trigger(struct device *dev) +{ + struct sensor_trigger trig; + + trig.type = SENSOR_TRIG_DATA_READY; + trig.chan = SENSOR_CHAN_GYRO_ANY; + + if (sensor_trigger_set(bmi160, &trig, NULL) < 0) { + ZJS_PRINT("failed to disable gyroscope trigger\n"); + return -1; + } + + gyro_trigger = false; + return 0; } static void handle_sensor(struct zjs_ipm_message* msg) @@ -653,7 +767,7 @@ static void handle_sensor(struct zjs_ipm_message* msg) uint32_t error_code = ERROR_IPM_NONE; if (msg->type != TYPE_SENSOR_INIT && !bmi160) { - ZJS_PRINT("Grove LCD device not found.\n"); + ZJS_PRINT("BMI160 sensor not found.\n"); ipm_send_error_reply(msg, ERROR_IPM_OPERATION_FAILED); return; } @@ -667,20 +781,22 @@ static void handle_sensor(struct zjs_ipm_message* msg) error_code = ERROR_IPM_OPERATION_FAILED; ZJS_PRINT("failed to initialize BMI160 sensor\n"); } else { - if (!auto_calibration(bmi160)) { + if (auto_calibration(bmi160)) { ZJS_PRINT("failed to perform auto calibration\n"); } - - accel_poll = gyro_poll = false; DBG_PRINT("BMI160 sensor initialized\n"); } } break; case TYPE_SENSOR_START: if (msg->data.sensor.channel == SENSOR_CHAN_ACCEL_ANY) { - accel_poll = true; + if (!accel_trigger && start_accel_trigger(bmi160) != 0) { + error_code = ERROR_IPM_OPERATION_FAILED; + } } else if (msg->data.sensor.channel == SENSOR_CHAN_GYRO_ANY) { - gyro_poll = true; + if (!gyro_trigger && start_gyro_trigger(bmi160) != 0) { + error_code = ERROR_IPM_OPERATION_FAILED; + } } else { ZJS_PRINT("invalid sensor channel\n"); error_code = ERROR_IPM_NOT_SUPPORTED; @@ -688,9 +804,13 @@ static void handle_sensor(struct zjs_ipm_message* msg) break; case TYPE_SENSOR_STOP: if (msg->data.sensor.channel == SENSOR_CHAN_ACCEL_ANY) { - accel_poll = false; + if (accel_trigger && stop_accel_trigger(bmi160) != 0) { + error_code = ERROR_IPM_OPERATION_FAILED; + } } else if (msg->data.sensor.channel == SENSOR_CHAN_GYRO_ANY) { - gyro_poll = false; + if (gyro_trigger && stop_gyro_trigger(bmi160) != 0) { + error_code = ERROR_IPM_OPERATION_FAILED; + } } else { ZJS_PRINT("invalid sensor channel\n"); error_code = ERROR_IPM_NOT_SUPPORTED; @@ -776,11 +896,6 @@ void main(void) tick_count = 0; } tick_count += SLEEP_TICKS; -#endif -#ifdef BUILD_MODULE_SENSOR - if (accel_poll || gyro_poll) { - fetch_sensor(bmi160); - } #endif task_sleep(SLEEP_TICKS); } diff --git a/samples/Gyroscope.js b/samples/Gyroscope.js index e1b02e966..63f5a947c 100644 --- a/samples/Gyroscope.js +++ b/samples/Gyroscope.js @@ -6,7 +6,9 @@ console.log("Gyroscope test..."); -var sensor = new Gyroscope(); +var sensor = new Gyroscope({ + frequency: 50 +}); sensor.onchange = function(event) { console.log("rotation (rad/s): " + diff --git a/scripts/analyze.sh b/scripts/analyze.sh index 644bd260e..530314bb5 100755 --- a/scripts/analyze.sh +++ b/scripts/analyze.sh @@ -187,18 +187,31 @@ if [ $? -eq 0 ] && [[ $MODULE != *"BUILD_MODULE_BUFFER"* ]]; then >&2 echo Using module: Buffer MODULES+=" -DBUILD_MODULE_BUFFER" fi -sensor=$(grep -E Accelerometer\|Gyroscope $SCRIPT) +sensor=$(grep -E Accelerometer\|Gyroscope $SCRIPT) if [ $? -eq 0 ]; then >&2 echo Using module: Sensor MODULES+=" -DBUILD_MODULE_SENSOR" - echo "CONFIG_SPI=y" >> arc/prj.conf.tmp - echo "CONFIG_SENSOR=y" >> arc/prj.conf.tmp - echo "CONFIG_BMI160=y" >> arc/prj.conf.tmp - echo "CONFIG_BMI160_INIT_PRIORITY=80" >> arc/prj.conf.tmp - echo "CONFIG_BMI160_NAME=\"bmi160\"" >> arc/prj.conf.tmp - echo "CONFIG_BMI160_SPI_PORT_NAME=\"SPI_1\"" >> arc/prj.conf.tmp - echo "CONFIG_BMI160_SLAVE=1" >> arc/prj.conf.tmp - echo "CONFIG_BMI160_SPI_BUS_FREQ=88" >> arc/prj.conf.tmp + if [ $BOARD = "arduino_101" ]; then + MODULES+=" -DBUILD_MODULE_SENSOR_TRIGGER" + echo "CONFIG_SENSOR=y" >> arc/prj.conf.tmp + echo "CONFIG_GPIO=y" >> prj.conf.tmp + echo "CONFIG_GPIO_QMSI=y" >> prj.conf.tmp + echo "CONFIG_GPIO_QMSI_0_PRI=2" >> prj.conf.tmp + echo "CONFIG_GPIO_QMSI_1=y" >> prj.conf.tmp + echo "CONFIG_GPIO_QMSI_1_NAME=\"GPIO_1\"" >> prj.conf.tmp + echo "CONFIG_GPIO_QMSI_1_PRI=2" >> prj.conf.tmp + echo "CONFIG_SPI=y" >> arc/prj.conf.tmp + echo "CONFIG_SPI_DW_ARC_AUX_REGS=y" >> arc/prj.conf.tmp + echo "CONFIG_SPI_DW_INTERRUPT_SEPARATED_LINES=y" >> arc/prj.conf.tmp + echo "CONFIG_BMI160=y" >> arc/prj.conf.tmp + echo "CONFIG_BMI160_INIT_PRIORITY=80" >> arc/prj.conf.tmp + echo "CONFIG_BMI160_NAME=\"bmi160\"" >> arc/prj.conf.tmp + echo "CONFIG_BMI160_SPI_PORT_NAME=\"SPI_1\"" >> arc/prj.conf.tmp + echo "CONFIG_BMI160_SLAVE=1" >> arc/prj.conf.tmp + echo "CONFIG_BMI160_SPI_BUS_FREQ=88" >> arc/prj.conf.tmp + echo "CONFIG_BMI160_TRIGGER=y" >> arc/prj.conf.tmp + echo "CONFIG_BMI160_TRIGGER_OWN_FIBER=y" >> arc/prj.conf.tmp + fi fi console=$(grep console $SCRIPT) diff --git a/src/zjs_ipm.h b/src/zjs_ipm.h index 1cf21cc92..0cd734911 100644 --- a/src/zjs_ipm.h +++ b/src/zjs_ipm.h @@ -109,7 +109,6 @@ typedef struct zjs_ipm_message { struct sensor_data { enum sensor_channel channel; uint32_t frequency; - double value[3]; union sensor_reading { // x y z axis for Accelerometer and Gyroscope struct { diff --git a/src/zjs_sensor.c b/src/zjs_sensor.c index b4619f68f..4c1c3652b 100644 --- a/src/zjs_sensor.c +++ b/src/zjs_sensor.c @@ -4,6 +4,11 @@ #ifndef ZJS_LINUX_BUILD // Zephyr includes #include +#ifdef BUILD_MODULE_SENSOR_TRIGGER +#include +#include +#include +#endif #endif #include @@ -14,6 +19,14 @@ #include "zjs_ipm.h" #include "zjs_util.h" +#ifdef BUILD_MODULE_SENSOR_TRIGGER +QUARK_SE_IPM_DEFINE(bmi160_ipm, 0, QUARK_SE_IPM_OUTBOUND); +#define BMI160_INTERRUPT_PIN 4 + +struct device *trigger_ipm; +struct gpio_callback cb; +#endif + #define ZJS_SENSOR_TIMEOUT_TICKS 500 static struct nano_sem sensor_sem; @@ -77,6 +90,15 @@ static void zjs_sensor_free_handles(sensor_handle_t *handle) } } +#ifdef BUILD_MODULE_SENSOR_TRIGGER +static void gpio_callback(struct device *port, + struct gpio_callback *cb, uint32_t pins) +{ + // trigger interrupt over to the ARC + ipm_send(trigger_ipm, 0, 0, NULL, 0); +} +#endif + static bool zjs_sensor_ipm_send_sync(zjs_ipm_message_t* send, zjs_ipm_message_t* result) { @@ -105,11 +127,7 @@ static int zjs_sensor_call_remote_function(zjs_ipm_message_t* send) { zjs_ipm_message_t reply; if (!zjs_sensor_ipm_send_sync(send, &reply)) { - return zjs_error("zjs_sensor_call_remote_function: ipm message failed or timed out!"); - } - if (reply.error_code != ERROR_IPM_NONE) { - ZJS_PRINT("zjs_sensor_call_remote_function: error code: %lu\n", - reply.error_code); + return ERROR_IPM_OPERATION_FAILED; } return reply.error_code; } @@ -259,11 +277,9 @@ static void zjs_sensor_onchange_c_callback(void *h, void *argv) return; } - if (zjs_sensor_get_state(handle->sensor_obj) == SENSOR_STATE_ACTIVATED) { - zjs_sensor_update_reading(handle->sensor_obj, - handle->channel, - handle->reading); - } + zjs_sensor_update_reading(handle->sensor_obj, + handle->channel, + handle->reading); } static void zjs_sensor_signal_callbacks(sensor_handle_t *handle, @@ -271,8 +287,10 @@ static void zjs_sensor_signal_callbacks(sensor_handle_t *handle, { // iterate all sensor instances to update readings and trigger event for (sensor_handle_t *h = handle; h; h = h->next) { - memcpy(&h->reading, &reading, sizeof(reading)); - zjs_signal_callback(h->id, NULL, 0); + if (zjs_sensor_get_state(h->sensor_obj) == SENSOR_STATE_ACTIVATED) { + memcpy(&h->reading, &reading, sizeof(reading)); + zjs_signal_callback(h->id, NULL, 0); + } } } @@ -403,17 +421,15 @@ 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)) { // TODO: figure out a list of frequencies we can support - // and have Zephyr trigger value changes instead of - // polling on the ARC. - // For now, frequency is ignored, we just report new event - // as soon as we detect a value change. - if (option_freq <= 0) { - ZJS_PRINT("zjs_sensor_create: invalid frequency, defaulting to 50hz\n"); + // For now, frequency is always set to 50Hz, + // other frequency values are not supported + if (option_freq != 50) { + ZJS_PRINT("zjs_sensor_create: unsupported frequency, defaulting to 50Hz\n"); } else { frequency = option_freq; } } else { - ZJS_PRINT("zjs_sensor_create: frequency not found, defaulting to 50hz\n"); + DBG_PRINT("zjs_sensor_create: frequency not found, defaulting to 50Hz\n"); } if (channel == SENSOR_CHAN_ACCEL_ANY) { @@ -428,9 +444,9 @@ static jerry_value_t zjs_sensor_create(const jerry_value_t function_obj, zjs_ipm_message_t send; send.type = TYPE_SENSOR_INIT; - jerry_value_t result = zjs_sensor_call_remote_function(&send); - if (jerry_value_has_error_flag(result)) { - return result; + int error = zjs_sensor_call_remote_function(&send); + if (error != ERROR_IPM_NONE) { + return zjs_error("zjs_sensor_create failed to init\n"); } // initialize object and default values @@ -498,6 +514,31 @@ void zjs_sensor_init() nano_sem_init(&sensor_sem); +#ifdef BUILD_MODULE_SENSOR_TRIGGER + // setting up trigger interrupt + struct device *gpio = device_get_binding("GPIO_1"); + if (!gpio) { + ZJS_PRINT("gpio device not found.\n"); + return; + } + + trigger_ipm = device_get_binding("bmi160_ipm"); + if (!trigger_ipm) { + ZJS_PRINT("bmi160_ipm device not found.\n"); + return; + } + + gpio_init_callback(&cb, gpio_callback, BIT(BMI160_INTERRUPT_PIN)); + gpio_add_callback(gpio, &cb); + + gpio_pin_configure(gpio, BMI160_INTERRUPT_PIN, + GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE | + GPIO_INT_ACTIVE_LOW | GPIO_INT_DEBOUNCE); + + gpio_pin_enable_callback(gpio, BMI160_INTERRUPT_PIN); +#endif + + // create global objects jerry_value_t global_obj = jerry_get_global_object(); zjs_obj_add_function(global_obj, zjs_accel_create, "Accelerometer"); zjs_obj_add_function(global_obj, zjs_gyro_create, "Gyroscope");