/* * Calculate lid angle and massage the results */ void motion_lid_calc(void) { /* Calculate angle of lid accel. */ lid_angle_is_reliable = calculate_lid_angle( accel_base->xyz, accel_lid->xyz, &lid_angle_deg); #ifdef CONFIG_LID_ANGLE_KEY_SCAN lidangle_keyscan_update(motion_lid_get_angle()); #endif }
/* Update/Write LPC data */ static inline void update_sense_data(uint8_t *lpc_status, uint16_t *lpc_data, int *psample_id) { int i; struct motion_sensor_t *sensor; /* * Set the busy bit before writing the sensor data. Increment * the counter and clear the busy bit after writing the sensor * data. On the host side, the host needs to make sure the busy * bit is not set and that the counter remains the same before * and after reading the data. */ *lpc_status |= EC_MEMMAP_ACC_STATUS_BUSY_BIT; /* * Copy sensor data to shared memory. Note that this code * assumes little endian, which is what the host expects. Also, * note that we share the lid angle calculation with host only * for debugging purposes. The EC lid angle is an approximation * with un-calibrated accels. The AP calculates a separate, * more accurate lid angle. */ #ifdef CONFIG_LID_ANGLE lpc_data[0] = motion_lid_get_angle(); #else lpc_data[0] = LID_ANGLE_UNRELIABLE; #endif /* Assumptions on the list of sensors */ for (i = 0; i < MIN(motion_sensor_count, 3); i++) { sensor = &motion_sensors[i]; lpc_data[1+3*i] = sensor->xyz[X]; lpc_data[2+3*i] = sensor->xyz[Y]; lpc_data[3+3*i] = sensor->xyz[Z]; } /* * Increment sample id and clear busy bit to signal we finished * updating data. */ *psample_id = (*psample_id + 1) & EC_MEMMAP_ACC_STATUS_SAMPLE_ID_MASK; *lpc_status = EC_MEMMAP_ACC_STATUS_PRESENCE_BIT | *psample_id; }
/* * Motion Sense Task * Requirement: motion_sensors[] are defined in board.c file. * Two (minimium) Accelerometers: * 1 in the A/B(lid, display) and 1 in the C/D(base, keyboard) * Gyro Sensor (optional) */ void motion_sense_task(void) { int i, ret, wait_us, fifo_flush_needed = 0; timestamp_t ts_begin_task, ts_end_task; uint32_t event = 0; uint16_t ready_status; struct motion_sensor_t *sensor; #ifdef CONFIG_LID_ANGLE const uint16_t lid_angle_sensors = ((1 << CONFIG_LID_ANGLE_SENSOR_BASE)| (1 << CONFIG_LID_ANGLE_SENSOR_LID)); #endif #ifdef CONFIG_ACCEL_FIFO timestamp_t ts_last_int; #endif #ifdef CONFIG_LPC int sample_id = 0; uint8_t *lpc_status; uint16_t *lpc_data; lpc_status = host_get_memmap(EC_MEMMAP_ACC_STATUS); lpc_data = (uint16_t *)host_get_memmap(EC_MEMMAP_ACC_DATA); set_present(lpc_status); #endif #ifdef CONFIG_ACCEL_FIFO ts_last_int = get_time(); #endif do { ts_begin_task = get_time(); ready_status = 0; for (i = 0; i < motion_sensor_count; ++i) { sensor = &motion_sensors[i]; /* if the sensor is active in the current power state */ if (SENSOR_ACTIVE(sensor)) { if (sensor->state != SENSOR_INITIALIZED) { continue; } ts_begin_task = get_time(); ret = motion_sense_process(sensor, event, &ts_begin_task, &fifo_flush_needed); if (ret != EC_SUCCESS) continue; ready_status |= (1 << i); } } #ifdef CONFIG_GESTURE_DETECTION /* Run gesture recognition engine */ gesture_calc(); #endif #ifdef CONFIG_LID_ANGLE /* * Check to see that the sensors required for lid angle * calculation are ready. */ ready_status &= lid_angle_sensors; if (ready_status == lid_angle_sensors) motion_lid_calc(); #endif #ifdef CONFIG_CMD_ACCEL_INFO if (accel_disp) { CPRINTF("[%T event 0x%08x ", event); for (i = 0; i < motion_sensor_count; ++i) { sensor = &motion_sensors[i]; CPRINTF("%s=%-5d, %-5d, %-5d ", sensor->name, sensor->xyz[X], sensor->xyz[Y], sensor->xyz[Z]); } #ifdef CONFIG_LID_ANGLE CPRINTF("a=%-4d", motion_lid_get_angle()); #endif CPRINTF("]\n"); } #endif #ifdef CONFIG_LPC update_sense_data(lpc_status, lpc_data, &sample_id); #endif ts_end_task = get_time(); #ifdef CONFIG_ACCEL_FIFO /* * Ask the host to flush the queue if * - a flush event has been queued. * - the queue is almost full, * - we haven't done it for a while. */ if (fifo_flush_needed || event & TASK_EVENT_MOTION_ODR_CHANGE || queue_space(&motion_sense_fifo) < CONFIG_ACCEL_FIFO_THRES || (accel_interval > 0 && (ts_end_task.val - ts_last_int.val) > accel_interval)) { if (!fifo_flush_needed) motion_sense_insert_timestamp(); fifo_flush_needed = 0; ts_last_int = ts_end_task; #ifdef CONFIG_MKBP_EVENT /* * We don't currently support wake up sensor. * When we do, add per sensor test to know * when sending the event. */ if (sensor_active == SENSOR_ACTIVE_S0) mkbp_send_event(EC_MKBP_EVENT_SENSOR_FIFO); #endif } #endif if (accel_interval > 0) { /* * Delay appropriately to keep sampling time * consistent. */ wait_us = accel_interval - (ts_end_task.val - ts_begin_task.val); /* * Guarantee some minimum delay to allow other lower * priority tasks to run. */ if (wait_us < MIN_MOTION_SENSE_WAIT_TIME) wait_us = MIN_MOTION_SENSE_WAIT_TIME; } else { wait_us = -1; } } while ((event = task_wait_event(wait_us))); }
/* Test utilities */ static int test_lid_angle(void) { uint8_t *lpc_status = host_get_memmap(EC_MEMMAP_ACC_STATUS); uint8_t sample; struct motion_sensor_t *base = &motion_sensors[0]; struct motion_sensor_t *lid = &motion_sensors[1]; /* Go to S3 state */ hook_notify(HOOK_CHIPSET_STARTUP); /* Go to S0 state */ hook_notify(HOOK_CHIPSET_RESUME); /* * Set the base accelerometer as if it were sitting flat on a desk * and set the lid to closed. */ base->xyz[X] = 0; base->xyz[Y] = 0; base->xyz[Z] = 1000; lid->xyz[X] = 0; lid->xyz[Y] = 0; lid->xyz[Z] = 1000; sample = *lpc_status & EC_MEMMAP_ACC_STATUS_SAMPLE_ID_MASK; task_wake(TASK_ID_MOTIONSENSE); while ((*lpc_status & EC_MEMMAP_ACC_STATUS_SAMPLE_ID_MASK) == sample) msleep(5); TEST_ASSERT(motion_lid_get_angle() == 0); /* Set lid open to 90 degrees. */ lid->xyz[X] = -1000; lid->xyz[Y] = 0; lid->xyz[Z] = 0; sample = *lpc_status & EC_MEMMAP_ACC_STATUS_SAMPLE_ID_MASK; task_wake(TASK_ID_MOTIONSENSE); while ((*lpc_status & EC_MEMMAP_ACC_STATUS_SAMPLE_ID_MASK) == sample) msleep(5); TEST_ASSERT(motion_lid_get_angle() == 90); /* Set lid open to 225. */ lid->xyz[X] = 500; lid->xyz[Y] = 0; lid->xyz[Z] = -500; sample = *lpc_status & EC_MEMMAP_ACC_STATUS_SAMPLE_ID_MASK; task_wake(TASK_ID_MOTIONSENSE); while ((*lpc_status & EC_MEMMAP_ACC_STATUS_SAMPLE_ID_MASK) == sample) msleep(5); TEST_ASSERT(motion_lid_get_angle() == 225); /* * Align base with hinge and make sure it returns unreliable for angle. * In this test it doesn't matter what the lid acceleration vector is. */ base->xyz[X] = 0; base->xyz[Y] = 1000; base->xyz[Z] = 0; sample = *lpc_status & EC_MEMMAP_ACC_STATUS_SAMPLE_ID_MASK; task_wake(TASK_ID_MOTIONSENSE); while ((*lpc_status & EC_MEMMAP_ACC_STATUS_SAMPLE_ID_MASK) == sample) msleep(5); TEST_ASSERT(motion_lid_get_angle() == LID_ANGLE_UNRELIABLE); /* * Use all three axes and set lid to negative base and make sure * angle is 180. */ base->xyz[X] = 500; base->xyz[Y] = 400; base->xyz[Z] = 300; lid->xyz[X] = -500; lid->xyz[Y] = -400; lid->xyz[Z] = -300; sample = *lpc_status & EC_MEMMAP_ACC_STATUS_SAMPLE_ID_MASK; task_wake(TASK_ID_MOTIONSENSE); while ((*lpc_status & EC_MEMMAP_ACC_STATUS_SAMPLE_ID_MASK) == sample) msleep(5); TEST_ASSERT(motion_lid_get_angle() == 180); return EC_SUCCESS; }