/** * @brief Analog Devices ADXL345Z accelerometer driver initialization. * * This is the main initialization function for the ADXL345Z device. * * @param sensor Address of a sensor device descriptor. * @param reserved Reserved value. * * @return bool true if the call succeeds, else false is returned. */ bool adxl345z_init(sensor_t *sensor, int reserved) { bool status = false; sensor_hal_t *const hal = sensor->hal; if (0xe5 == sensor_bus_get(hal, ADXL345Z_DEVID)) { /* Set the driver function table and capabilities pointer. */ static const sensor_device_t adxl345z_device = { .func.read = adxl345z_read, .func.ioctl = adxl345z_ioctl, .func.selftest = adxl345_selftest, .func.event = adxl345_event, .caps.feature = SENSOR_CAPS_3_AXIS | SENSOR_CAPS_SELFTEST | SENSOR_CAPS_TAP_EVENT | SENSOR_CAPS_DROP_EVENT, .caps.vendor = SENSOR_VENDOR_ADI, .caps.range_table = range_table, .caps.band_table = band_table, .caps.range_count = ARRAYSIZE(range_table), .caps.band_count = ARRAYSIZE(band_table), .caps.units = SENSOR_UNITS_g0, .caps.scale = SENSOR_SCALE_milli, .caps.name = "ADXL345Z Digital, triaxial acceleration sensor" }; sensor->drv = &adxl345z_device; /* Set the driver (device) default range, bandwidth, & * resolution. * Per the ADXL345Z Datasheet the default range and bandwidth * after device reset are +/- 2g and 100Hz respectively. */ hal->range = 2000; hal->bandwidth = 100; hal->resolution = 10; hal->burst_addr = ADXL345Z_DATAX0; /* After power is applied the device enters standby mode, where * power consumption is minimized and the device waits for the * command to enter measurement mode. While in standby mode, any * register can be read or written to configure the part. * Configure the part in standby mode prior to enabling * measurement mode. */ sensor_reg_bitset(hal, ADXL345Z_POWER_CTL, POWER_CTL_MEASURE); /* Install an interrupt handler. */ if ((STATUS_OK == hal->bus.status) && sensor_irq_connect(hal->mcu_sigint, adxl345z_isr, hal)) { status = true; } } return status; }
/** * @brief InvenSense ITG-3200 gyroscope driver initialization. * * This is the main initialization function for the ITG-3200 device. * * @param sensor Address of a sensor device descriptor. * @param resvd Reserved value. * @return bool true if the sensor is ready for use, else false. */ bool itg3200_init(sensor_t *sensor, int resvd) { sensor_hal_t *const hal = sensor->hal; bool status = false; /* Set the driver function table and capabilities pointer. */ static const sensor_device_t itg3200_device = { .func.read = itg3200_read, .func.ioctl = itg3200_ioctl, .func.event = itg3200_event, .caps.feature = SENSOR_CAPS_3_AXIS | SENSOR_CAPS_AUX_TEMP, .caps.vendor = SENSOR_VENDOR_INVENSENSE, .caps.band_table = band_table, .caps.band_count = ARRAYSIZE(band_table), .caps.units = SENSOR_UNITS_deg_per_sec, .caps.name = "InvenSense ITG-3200 3-axis angular rate sensor" }; sensor->drv = &itg3200_device; /* Set the driver default, range, bandwidth, resolution, etc. */ hal->range = ITG3200_FS_RANGE; hal->bandwidth = 256; /* Hertz */ hal->sample_rate = 100; /* Hertz */ hal->resolution = ITG3200_RESOLUTION; hal->burst_addr = ITG3200_INT_STATUS; /* Apply default device settings & connect an interrupt handler. */ if (itg3200_default_init(hal) && sensor_irq_connect (hal->mcu_sigint, itg3200_isr, hal)) { status = true; } return status; } /** * @brief Invensense ITG3200 driver interrupt service routine. * * This is the interrupt service routine for enabled ITG3200 interrupt events. * Only the new data ("raw data ready") interrupt is supported. * * @param arg The address of the driver sensor_hal_t descriptor. * @return Nothing. */ static void itg3200_isr(volatile void *arg) { sensor_hal_t *const hal = (sensor_hal_t *)arg; int16_t input[3]; hal->bus.no_wait = true; itg3200_event_t regs; sensor_bus_read(hal, hal->burst_addr, ®s, sizeof(regs)); hal->bus.no_wait = false; if (STATUS_OK == hal->bus.status) { /* Assume new data to avoid an apparent race condition. The * interrupt status register sometimes has the new data flag * cleared before it is read above. If this happens, the sensor will * not generate any further new data interrupts until the device is * independently accessed. */ static sensor_event_data_t event_data = {.data.scaled = true}; event_data.data.timestamp = sensor_timestamp(); event_data.event = SENSOR_EVENT_NEW_DATA; input[0] = (regs.x_hi << 8) | regs.x_lo; input[1] = (regs.y_hi << 8) | regs.y_lo; input[2] = (regs.z_hi << 8) | regs.z_lo; event_data.data.axis.x = hal->orientation.x.sign * input[hal->orientation.x.axis]; event_data.data.axis.y = hal->orientation.y.sign * input[hal->orientation.y.axis]; event_data.data.axis.z = hal->orientation.z.sign * input[hal->orientation.z.axis]; event_data.data.axis.x /= SCALE_LSB_PER_DPS; event_data.data.axis.y /= SCALE_LSB_PER_DPS; event_data.data.axis.z /= SCALE_LSB_PER_DPS; /* Call application-supplied handler routine */ (event_cb.handler)(&event_data, event_cb.arg); } } /** * @brief Read gyroscope angular rate axis data. * * This function reads angular rate data for all 3 axes of an ITG-3200 * gyroscope. * * @param sensor Address of an initialized sensor device descriptor. * @param data The address of a vector storing sensor axis data. * @return bool true if the call succeeds, else false is returned. */ static bool itg3200_get_rotation(sensor_hal_t *hal, sensor_data_t *data) { struct { uint8_t msb; uint8_t lsb; } input[3]; size_t const count = sensor_bus_read(hal, ITG3200_GYRO_XOUT_H, input, sizeof(input)); /* Copy data values based on device orientation and signs. */ data->axis.x = hal->orientation.x.sign * ((int16_t)((input[hal->orientation.x.axis].msb << 8) | input[hal->orientation.x.axis].lsb)); data->axis.y = hal->orientation.y.sign * ((int16_t)((input[hal->orientation.y.axis].msb << 8) | input[hal->orientation.y.axis].lsb)); data->axis.z = hal->orientation.z.sign * ((int16_t)((input[hal->orientation.z.axis].msb << 8) | input[hal->orientation.z.axis].lsb)); /* Convert raw sensor samples to engineering units if requested. */ if (data->scaled) { data->axis.x /= SCALE_LSB_PER_DPS; data->axis.y /= SCALE_LSB_PER_DPS; data->axis.z /= SCALE_LSB_PER_DPS; } return (count == sizeof(input)); } /** * @brief Read gyroscope integrated temperature sensor data * * This function reads ITG-3200 integrated temperature sensor data. * The temperature is always returned in scaled engineering units * (degrees Celsius). * * @param sensor Address of an initialized sensor device descriptor. * @param data The address where temperature samples are returned. * @return bool true if the call succeeds, else false is returned. */ static bool itg3200_get_temperature(sensor_hal_t *hal, sensor_data_t *data) { int16_t temp_data; size_t const count = sensor_bus_read(hal, ITG3200_TEMP_OUT_H, &temp_data, sizeof(temp_data)); data->temperature.value = (int16_t)be16_to_cpu(temp_data); if (data->scaled) { data->temperature.value -= TEMP_OFFSET; data->temperature.value /= TEMP_COUNTS_PER_DEG_C; data->temperature.value += TEMP_REF_DEG; } return (count == sizeof(temp_data)); }
/** * @brief InvenSense IMU-3000 motion processor driver initialization. * * This is the main initialization function for the IMU-3000 device. * * @param sensor Address of a sensor device descriptor. * @param resvd Reserved value. * @return bool true if the sensor is ready for use, else false. */ bool imu3000_init(sensor_t *sensor, int resvd) { sensor_hal_t *const hal = sensor->hal; sensor_hal_t *const aux = (sensor_hal_t *)sensor->aux; bool status = false; /* Set the driver function table and capabilities pointer. */ static const sensor_device_t imu3000_device = { .func.read = imu3000_read, .func.ioctl = imu3000_ioctl, .func.event = imu3000_event, .caps.feature = SENSOR_CAPS_3_AXIS | SENSOR_CAPS_AUX_TEMP | SENSOR_CAPS_AUX_ACCEL, .caps.vendor = SENSOR_VENDOR_INVENSENSE, .caps.range_table = range_table, .caps.band_table = band_table, .caps.range_count = ARRAYSIZE(range_table), .caps.band_count = ARRAYSIZE(band_table), .caps.units = SENSOR_UNITS_deg_per_sec, .caps.name = "InvenSense IMU-3000 Motion Processing Unit" }; sensor->drv = &imu3000_device; /* Set the driver default, range, bandwidth, resolution, etc. */ hal->range = range_table [sensor_fs_sel].range_units; hal->bandwidth = band_table [sensor_dlpf_cfg].bandwidth_Hz; hal->sample_rate = 100; hal->resolution = IMU3000_RESOLUTION; /* Apply default device settings */ if (imu3000_default_init(hal, aux) != true) { return status; /* return error */ } /* Set start addr for burst read (used during interrupt). */ hal->burst_addr = IMU3000_INT_STATUS; /* Connect interrupt event handler. */ if (sensor_irq_connect(hal->mcu_sigint, imu3000_isr, hal)) { status = true; } return status; } /** * @brief Invensense IMU3000 driver interrupt service routine. * * This is the interrupt service routine for enabled IMU3000 interrupt events. * Only the new data ("raw data ready") interrupt is supported. * * @param arg The address of the driver sensor_hal_t descriptor. * @return Nothing. */ static void imu3000_isr(volatile void *arg) { sensor_hal_t *const hal = (sensor_hal_t *)arg; int16_t input[3]; hal->bus.no_wait = true; imu3000_event_t regs; sensor_bus_read(hal, hal->burst_addr, ®s, sizeof(regs)); hal->bus.no_wait = false; if (STATUS_OK == hal->bus.status) { /* Assume new data to avoid an apparent race condition. The * interupt status register sometimes has the new data flag * cleared before it is read above. If this happens, the sensor will * not generate any further new data interrupts until the device is * independently accessed. */ static sensor_event_data_t event_data = {.data.scaled = true}; event_data.data.timestamp = sensor_timestamp(); event_data.event = SENSOR_EVENT_NEW_DATA; input[0] = (regs.x_hi << 8) | regs.x_lo; input[1] = (regs.y_hi << 8) | regs.y_lo; input[2] = (regs.z_hi << 8) | regs.z_lo; event_data.data.axis.x = hal->orientation.x.sign * input[hal->orientation.x.axis]; event_data.data.axis.y = hal->orientation.y.sign * input[hal->orientation.y.axis]; event_data.data.axis.z = hal->orientation.z.sign * input[hal->orientation.z.axis]; const int32_t scaling = (int32_t)scale_lsb_per_dps[sensor_fs_sel]; event_data.data.axis.x /= scaling; event_data.data.axis.y /= scaling; event_data.data.axis.z /= scaling; /* Call application-supplied handler routine */ (event_cb.handler)(&event_data, event_cb.arg); } } /** * @brief Enable/disable IMU3000 sensor event * * @param sensor Address of an initialized sensor device descriptor * @param callback Application-defined event callback handler descriptor * @param enable Enable flag: true = enable event, false = disable event * @return bool true if the call succeeds, else false is returned */ static bool imu3000_event(sensor_t *sensor, sensor_event_t sensor_event, sensor_event_callback_t *callback, bool enable) { sensor_hal_t *const hal = sensor->hal; bool status = false; if (sensor_event & SENSOR_EVENT_NEW_DATA) { if (callback) { event_cb = *callback; } if (enable) { /* Enable new data int, latch until any reg is read, * active high */ sensor_bus_put(hal, IMU3000_INT_CFG, INT_CFG_RAW_RDY_EN | INT_CFG_ANYRD_2CLEAR); } else { /* Disable new data int */ sensor_reg_bitclear(hal, IMU3000_INT_CFG, INT_CFG_LATCH_INT_EN); } status = true; } return status; }
/** * @brief Bosch BMA250 accelerometer driver initialization. * * This is the main initialization function for the BMA250 device. * * @param sensor Address of a sensor device descriptor. * @param resvd Reserved value. * @return bool true if the call succeeds, else false is returned. */ bool bma250_init(sensor_t *sensor, int resvd) { bool status = false; sensor_hal_t *const hal = sensor->hal; if (BMA250_ID_VAL == sensor_bus_get(hal, BMA250_CHIP_ID)) { /* Set the driver function table and capabilities pointer. */ static const sensor_device_t bma250_device = { /* Bosch BMA250 Driver Entry Points & Capabilities */ .func.read = bma250_read, .func.ioctl = bma250_ioctl, .func.selftest = bma250_selftest, .func.event = bma250_event, .caps.feature = SENSOR_CAPS_3_AXIS | SENSOR_CAPS_SELFTEST | SENSOR_CAPS_HI_G_EVENT | SENSOR_CAPS_LO_G_EVENT | SENSOR_CAPS_TAP_EVENT | SENSOR_CAPS_TILT_EVENT | SENSOR_CAPS_AUX_TEMP, .caps.vendor = SENSOR_VENDOR_BOSCH, .caps.range_table = range_table, .caps.band_table = band_table, .caps.range_count = ARRAYSIZE(range_table), .caps.band_count = ARRAYSIZE(band_table), .caps.units = SENSOR_UNITS_g0, .caps.scale = SENSOR_SCALE_milli, .caps.name = "BMA250 Digital, triaxial acceleration sensor" }; sensor->drv = &bma250_device; /* Set the driver (device) default range, bandwidth, & * resolution. * * \internal * Per the BMA250 Datasheet the default range and bandwidth * after device reset are +/- 2g and 1kHz respectively. */ bma250_set_state(sensor, SENSOR_STATE_RESET); hal->range = 2000; hal->bandwidth = 1000; hal->resolution = BMA250_DATA_RESOLUTION; hal->burst_addr = BMA250_NEW_DATA_X; /* Install an interrupt handler. */ if ((STATUS_OK == hal->bus.status) && sensor_irq_connect(hal->mcu_sigint, bma250_isr, hal)) { status = true; } } return status; } /** * @brief Bosch BMA250 driver interrupt service routine. * * This is the common interrupt service routine for all enabled BMA250 interrupt * events. Five different types of interrupts can be programmed. All interrupt * criteria are combined and drive the interrupt pad with a Boolean \c OR * condition. * * Interrupt criteria are tested against values from the BMA250 digital filter * output. All thresholds are scaled using the current device range. Timings * for high and low acceleration are absolute values (1 LSB of HG_dur and LG_dur * registers corresponds to 1 millisecond, +/- 10%). Timing for the any-motion * interrupt and alert detection are proportional to the bandwidth setting. * * This routine handles interrupts generated when low-g, high-g, any-motion, * alert, and new data criteria are satisfied and the corresponding event * notification is enabled in the device. * * The BMA250 device does not provide any way to definitively identify an * any-motion interrupt once it has occurred. So, if a handler has been * installed for that event, it will always be called by this routine, * and the SENSOR_EVENT_MOTION indicator will be set in the event type field. * * @param arg The address of the driver sensor_hal_t descriptor. * @return Nothing. */ static void bma250_isr(volatile void *arg) { sensor_hal_t *const hal = (sensor_hal_t *)arg; hal->bus.no_wait = true; sensor_bus_read(hal, hal->burst_addr, &event_regs, sizeof(event_regs)); hal->bus.no_wait = false; if (STATUS_OK == hal->bus.status) { sensor_event_data_t event_data = {.data.scaled = true}; event_data.data.timestamp = sensor_timestamp(); event_data.event = SENSOR_EVENT_UNKNOWN; format_axis_data(hal, event_regs.acc, &(event_data.data)); if (event_regs.status_field.data_int) { event_data.event |= SENSOR_EVENT_NEW_DATA; (event_cb[0].handler)(&event_data, event_cb[0].arg); } if (event_regs.status_field.slope_int) { event_data.event |= SENSOR_EVENT_MOTION; (event_cb[1].handler)(&event_data, event_cb[1].arg); } if (event_regs.status_field.low_int) { event_data.event |= SENSOR_EVENT_LOW_G; (event_cb[2].handler)(&event_data, event_cb[2].arg); } if (event_regs.status_field.high_int) { event_data.event |= SENSOR_EVENT_HIGH_G; (event_cb[3].handler)(&event_data, event_cb[3].arg); } if (event_regs.status_field.s_tap_int) { event_data.event |= SENSOR_EVENT_S_TAP; (event_cb[4].handler)(&event_data, event_cb[4].arg); } if (event_regs.status_field.d_tap_int) { event_data.event |= SENSOR_EVENT_D_TAP; (event_cb[4].handler)(&event_data, event_cb[4].arg); } } }
/** * @brief Bosch BMA150 accelerometer driver initialization. * * This is the main initialization function for the BMA150 device. * * @param sensor Address of a sensor device descriptor. * @param resvd Reserved value. * @return bool true if the call succeeds, else false is returned. */ bool bma150_init(sensor_t *sensor, int resvd) { bool status = false; sensor_hal_t *const hal = sensor->hal; if (BMA150_ID_VAL == sensor_bus_get(hal, BMA150_CHIP_ID)) { /* Set the driver function table and capabilities pointer. */ static const sensor_device_t bma150_device = { .func.read = bma150_read, .func.ioctl = bma150_ioctl, .func.selftest = bma150_selftest, .func.event = bma150_event, .caps.feature = SENSOR_CAPS_3_AXIS | SENSOR_CAPS_SELFTEST | SENSOR_CAPS_HI_G_EVENT | SENSOR_CAPS_LO_G_EVENT | SENSOR_CAPS_AUX_TEMP, .caps.vendor = SENSOR_VENDOR_BOSCH, .caps.range_table = range_table, .caps.band_table = band_table, .caps.range_count = ARRAYSIZE(range_table), .caps.band_count = ARRAYSIZE(band_table), .caps.units = SENSOR_UNITS_g0, .caps.scale = SENSOR_SCALE_milli, .caps.name = "BMA150 Digital, triaxial acceleration sensor" }; sensor->drv = &bma150_device; /* Set the driver (device) default range, bandwidth, & * resolution. * * Per the BMA150 Datasheet the default range and bandwidth * after device reset are +/- 4g and 1500 Hz. respectively. So, * if that's the desired initialization state for this device, *then * don't use software to set these values in the driver _init() * routine. */ hal->range = 4000; hal->bandwidth = 1500; hal->resolution = BMA150_DATA_RESOLUTION; /* Set the device burst read base address. */ hal->burst_addr = BMA150_ACC_X_LSB; /* Initialize the control registers. */ sensor_bus_put(hal, BMA150_CTRL1, 0); sensor_bus_put(hal, BMA150_CTRL2, 0); sensor_bus_put(hal, BMA150_CTRL5, 0); /* Set the interrupt handler. */ if ((STATUS_OK == hal->bus.status) && sensor_irq_connect(hal->mcu_sigint, bma150_isr, hal)) { status = true; } } return status; } /** * @brief Bosch BMA150 driver interrupt service routine. * * This is the common interrupt service routine for all enabled BMA150 interrupt * events. Five different types of interrupts can be programmed. All interrupt * criteria are combined and drive the interrupt pad with a Boolean \c OR * condition. * * Interrupt events may be set to an inconsistent state by device EEPROM * changes. BMA150 interrupts should be disabled at the host microcontroller * when device EEPROM writes are performed. * * Interrupt criteria are tested against values from the BMA150 digital filter * output. All thresholds are scaled using the current device range. Timings * for high and low acceleration are absolute values (1 LSB of HG_dur and LG_dur * registers corresponds to 1 millisecond, +/- 10%). Timing for the any-motion * interrupt and alert detection are proportional to the bandwidth setting. * * This routine handles interrupts generated when low-g, high-g, any-motion, * alert, and new data criteria are satisfied and the corresponding event * notification is enabled in the device. * * The BMA150 device does not provide any way to definitively identify an * any-motion interrupt once it has occurred. So, if a handler has been * installed for that event, it will always be called by this routine, * and the SENSOR_EVENT_MOTION indicator will be set in the event type field. * * @param arg The address of the driver sensor_hal_t descriptor. * @return Nothing. */ static void bma150_isr(volatile void *arg) { sensor_hal_t *const hal = (sensor_hal_t *)arg; hal->bus.no_wait = true; sensor_bus_read(hal, hal->burst_addr, &event_regs, sizeof(event_regs)); hal->bus.no_wait = false; if (STATUS_OK == hal->bus.status) { static sensor_event_data_t event_data = {.data.scaled = true}; event_data.data.timestamp = sensor_timestamp(); event_data.event = SENSOR_EVENT_MOTION; /* * Test the "new data" bit in the sample outputs prior to * converting axis data to sign extended 10-bit values and * buffering the result. */ bool const new_data = event_regs.acc[2].field.new_data; format_axis_data(hal, event_regs.acc, &(event_data.data)); if (event_regs.status_field.LG_issued) { event_data.event = SENSOR_EVENT_LOW_G; (event_cb[2].handler)(&event_data, event_cb[2].arg); } else if (event_regs.status_field.HG_issued) { event_data.event = SENSOR_EVENT_HIGH_G; (event_cb[3].handler)(&event_data, event_cb[3].arg); } else if (new_data) { event_data.event = SENSOR_EVENT_NEW_DATA; (event_cb[0].handler)(&event_data, event_cb[0].arg); } else { /* Assume the any-motion event triggered the interrupt. */ (event_cb[1].handler)(&event_data, event_cb[1].arg); } } } /** * @brief Read BMA150 device ID and revision numbers. * * This function reads the accelerometer hardware identification registers * and returns these values in the specified data structure. * * @param hal Address of an initialized sensor hardware descriptor. * @param data Address of sensor_data_t structure to return values. * @return bool true if the call succeeds, else false is returned. */ static bool bma150_device_id(sensor_hal_t *hal, sensor_data_t *data) { data->device.id = sensor_bus_get(hal, BMA150_CHIP_ID); data->device.version = sensor_bus_get(hal, BMA150_CHIP_VERSION); return true; }
/** * @brief Osram SFH7770 light & proximity sensor driver initialization. * * This is the main initialization function for the SFH7770 device. * * @param sensor Address of a sensor device descriptor. * @param resvd Reserved value. * @return bool true if the call succeeds, else false is returned. */ bool sfh7770_init(sensor_t *sensor, int resvd) { bool status = false; sensor_hal_t *const hal = sensor->hal; /* Proximity threshold values from NVRAM */ struct { uint8_t ps_thr_led1; uint8_t ps_thr_led2; uint8_t ps_thr_led3; } prox_thresholds; /* Read and check part ID register */ uint8_t part_id = sensor_bus_get(hal, SFH7770_PART_ID); if (part_id == (SFH7770_PART_ID_VAL | SFH7770_PART_REV_VAL)) { /* Set the driver function table and capabilities pointer. */ static const sensor_device_t sfh7770_device = { .func.read = sfh7770_read, .func.ioctl = sfh7770_ioctl, .func.calibrate = sfh7770_calibrate, .func.event = sfh7770_event, #if 0 .caps.feature = XXX #endif .caps.vendor = SENSOR_VENDOR_OSRAM, .caps.units = SENSOR_UNITS_lux, .caps.scale = SENSOR_SCALE_one, .caps.name = "SFH7770 Ambient Light & Proximity Sensor" }; sensor->drv = &sfh7770_device; hal->resolution = SFH7770_DATA_RESOLUTION; /* Set the device burst read starting register address. */ hal->burst_addr = SFH7770_ALS_DATA_LSB; /* Reset device during first init call */ if (!sfh7770_initialized) { sensor_bus_put(hal, SFH7770_ALS_CONTROL, ALS_CONTROL_SW_RESET); } /* Init light sensor functions if specified */ if (sensor->type & SENSOR_TYPE_LIGHT) { /* Set light sensor mode & interval */ sensor_bus_put(hal, SFH7770_ALS_CONTROL, ALS_MODE_FREE_RUNNING); sensor_bus_put(hal, SFH7770_ALS_INTERVAL, ALS_INTERVAL_500MS); } /* Init proximity sensor functions if specified */ if (sensor->type & SENSOR_TYPE_PROXIMITY) { /* Set proximity sensor mode & interval */ sensor_bus_put(hal, SFH7770_PS_CONTROL, PS_MODE_FREE_RUNNING); sensor_bus_put(hal, SFH7770_PS_INTERVAL, PS_INTERVAL_100MS); /* Specify which LEDs are active */ uint8_t const active_leds = LED_ACTIVE_ALL; /* XXX one of: */ /* XXX LED_ACTIVE_1 - LED1 only (default) */ /* XXX LED_ACTIVE_1_2 - LED1 & LED2 */ /* XXX LED_ACTIVE_1_3 - LED1 & LED3 */ /* XXX LED_ACTIVE_ALL - all LEDs */ /* Set LED current levels */ uint8_t const led1_curr = I_LED_50MA; /* LED1 current */ uint8_t const led2_curr = I_LED_50MA; /* LED2 current */ uint8_t const led3_curr = I_LED_50MA; /* LED3 current */ sensor_bus_put(hal, SFH7770_I_LED_1_2, (active_leds | (led2_curr << I_LED2_SHIFT) | led1_curr)); sensor_bus_put(hal, SFH7770_I_LED_3, led3_curr); /* Apply stored proximity thresholds from nvram */ nvram_read(SFH7770_NVRAM_OFFSET, &prox_thresholds, sizeof(prox_thresholds)); sensor_bus_write(hal, (SFH7770_PS_THR_LED1), &prox_thresholds, sizeof(prox_thresholds)); } if (!sfh7770_initialized) { /* Set interrupt output polarity & mode(active-low, * latched). */ sensor_bus_put(hal, SFH7770_INT_SET, 0); /* Set up interrupt handler */ if (STATUS_OK == hal->bus.status) { sensor_irq_connect(hal->mcu_sigint, sfh7770_isr, hal); } } sfh7770_initialized = true; status = true; } return status; } /** * @brief Osram SFH7770 driver interrupt service routine. * * This is the common interrupt service routine for all enabled SFH7770 * interrupt events. Three different types of interrupts can be programmed: * high light level, low light level, and near proximity. All share the * same interrupt pin and therefore the same ISR entry. * * @param arg The address of the driver sensor_hal_t descriptor. * @return Nothing. */ static void sfh7770_isr(volatile void *arg) { sensor_hal_t *const hal = (sensor_hal_t *)arg; struct { /* Interrupt register data */ uint8_t als_data_lsb; /* light meas data - least signif byte */ uint8_t als_data_msb; /* light meas data - most signif byte */ uint8_t als_ps_status; /* light & prox sensor status */ uint8_t ps_data_led1; /* proximity meas data - LED 1 */ uint8_t ps_data_led2; /* proximity meas data - LED 2 */ uint8_t ps_data_led3; /* proximity meas data - LED 3 */ uint8_t int_set; /* interrupt status */ } regs; /* Do not wait for a busy bus when reading data. */ hal->bus.no_wait = true; sensor_bus_read(hal, hal->burst_addr, (uint8_t *)®s, sizeof(regs)); hal->bus.no_wait = false; if (STATUS_OK == hal->bus.status) { static sensor_event_data_t event_data = {.data.scaled = true}; event_data.data.timestamp = sensor_timestamp(); event_data.event = SENSOR_EVENT_UNKNOWN; /* * Determine the interrupt source then combine measurement * register values into a single 16-bit measurement value. */ uint8_t const int_source = (regs.int_set & INT_SOURCE_MASK); uint16_t const light_level = ((regs.als_data_msb << 8) | regs.als_data_lsb); switch (int_source) { case INT_SOURCE_ALS: /* Determine if low or high light interrupt */ if (light_level >= high_light_threshold) { event_data.event = SENSOR_EVENT_HIGH_LIGHT; event_data.data.light.value = light_level; (event_cb[2].handler)(&event_data, event_cb[2].arg); } else if (light_level <= low_light_threshold) { event_data.event = SENSOR_EVENT_LOW_LIGHT; event_data.data.light.value = light_level; (event_cb[1].handler)(&event_data, event_cb[1].arg); } return; case INT_SOURCE_LED1: case INT_SOURCE_LED2: case INT_SOURCE_LED3: event_data.event = SENSOR_EVENT_NEAR_PROXIMITY; if (int_source == INT_SOURCE_LED1) { event_data.channel = 1; } else if (int_source == INT_SOURCE_LED2) { event_data.channel = 2; } else { /* INT_SOURCE_LED3 */ event_data.channel = 3; } /* Use internal device threshold status to * determine scaled values. */ event_data.data.proximity.value[0] = (regs.als_ps_status & PS_LED1_THRESH) ? PROXIMITY_NEAR : PROXIMITY_NONE; event_data.data.proximity.value[1] = (regs.als_ps_status & PS_LED2_THRESH) ? PROXIMITY_NEAR : PROXIMITY_NONE; event_data.data.proximity.value[2] = (regs.als_ps_status & PS_LED3_THRESH) ? PROXIMITY_NEAR : PROXIMITY_NONE; (event_cb[0].handler)(&event_data, event_cb[0].arg); } } } /** * @brief Read SFH7770 device ID and revision numbers. * * This function reads the sensor hardware identification registers * and returns these values in the specified data structure. * * @param hal Address of an initialized sensor hardware descriptor. * @param data Address of sensor_data_t structure to return values. * @return bool true if the call succeeds, else false is returned. */ static bool sfh7770_device_id(sensor_hal_t *hal, sensor_data_t *data) { uint8_t const part_id = sensor_bus_get(hal, SFH7770_PART_ID); data->device.id = (uint32_t)(part_id & PART_ID_MASK) >> PART_ID_SHIFT; data->device.version = (uint32_t)(part_id & PART_REV_MASK); return true; }