motion_lid: Rewrite lid angle calculation based on chromium code
Use code from ash/wm/tablet_mode/tablet_mode_controller.cc, in particular TabletModeController::HandleHingeRotation() to calculate lid angle. Add unit tests based on ash/wm/tablet_mode/tablet_mode_controller_unittest.cc and the data file accelerometer_test_data_literals.cc. BUG=b:120346412 BRANCH=none TEST=Check unit tests pass, check it compile on FPU based EC, EC without FPU and no 64 bit support (ampton). Check lid calculation is correct on eve: - with "while true ; do ectool motionsense lid_angle ; sleep 1 ; done" Check when hinge is almost vertical lid angle is close to constant or marked are unrieliable. Check when shaking device, lid angle is also unreliable Check with evtest SW_TABLET_MODE event is trigger when lid angle is available and cross 180 region. Change-Id: I545f7333ed9b53accedb75f238f747f66bae1f5d Signed-off-by: Gwendal Grignou <gwendal@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1388844 Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com> Reviewed-by: Jett Rink <jettrink@chromium.org>
This commit is contained in:
parent
4a48404aee
commit
40f9e2fc0f
|
@ -38,7 +38,7 @@ static fp_t last_lid_angle_fp = FLOAT_TO_FP(-1);
|
|||
* measurements when the lid is physically closed. This will be used in
|
||||
* reliability calculations.
|
||||
*/
|
||||
#define SMALL_LID_ANGLE_RANGE 15
|
||||
#define SMALL_LID_ANGLE_RANGE (FLOAT_TO_FP(15))
|
||||
#endif
|
||||
|
||||
/* Current acceleration vectors and current lid angle. */
|
||||
|
@ -46,15 +46,15 @@ static int lid_angle_deg;
|
|||
|
||||
static int lid_angle_is_reliable;
|
||||
|
||||
/*
|
||||
* Angle threshold for how close the hinge aligns with gravity before
|
||||
* considering the lid angle calculation unreliable. For computational
|
||||
* efficiency, value is given unit-less, so if you want the threshold to be
|
||||
* at 15 degrees, the value would be cos(15 deg) = 0.96593.
|
||||
*
|
||||
* Here we're using cos(27.5 deg) = 0.88701.
|
||||
*/
|
||||
#define HINGE_ALIGNED_WITH_GRAVITY_THRESHOLD FLOAT_TO_FP(0.88701)
|
||||
/* Smoothed vectors to increase accurency. */
|
||||
static intv3_t smoothed_base, smoothed_lid;
|
||||
|
||||
/* 8.7 m/s^2 is the the maximum acceleration parallel to the hinge */
|
||||
#define SCALED_HINGE_VERTICAL_MAXIMUM \
|
||||
((int)((8.7f * MOTION_SCALING_FACTOR) / MOTION_ONE_G))
|
||||
|
||||
#define SCALED_HINGE_VERTICAL_SMOOTHING_START \
|
||||
((int)((7.0f * MOTION_SCALING_FACTOR) / MOTION_ONE_G))
|
||||
|
||||
/*
|
||||
* Constant to debounce lid angle changes around 360 - 0:
|
||||
|
@ -67,9 +67,20 @@ static int lid_angle_is_reliable;
|
|||
* under the same acceleration. This constant, which mirrors
|
||||
* kNoisyMagnitudeDeviation used in Chromium, is an integer which defines the
|
||||
* maximum deviation in magnitude between the base and lid vectors. The units
|
||||
* are in m/s^2.
|
||||
* are in g. Currently set at 1m/s^2.
|
||||
*/
|
||||
#define NOISY_MAGNITUDE_DEVIATION 1
|
||||
#define NOISY_MAGNITUDE_DEVIATION ((int)(MOTION_SCALING_FACTOR / MOTION_ONE_G))
|
||||
|
||||
/*
|
||||
* Even with noise, any measurement greater than 1g on any axis is not suitable
|
||||
* for lid calculation. It means the device is moving.
|
||||
* To avoid using 64bits arithmetic, we need to be sure that square of magnitude
|
||||
* is less than 1<<31, so magnitude is less sqrt(2)*(1<<15), less than ~40% over
|
||||
* 1g. This is way above any usable noise. Assume noise is less than 10%.
|
||||
*/
|
||||
#define MOTION_SCALING_AXIS_MAX (MOTION_SCALING_FACTOR * 110)
|
||||
|
||||
#define MOTION_SCALING_FACTOR2 (MOTION_SCALING_FACTOR * MOTION_SCALING_FACTOR)
|
||||
|
||||
/*
|
||||
* Define the accelerometer orientation matrices based on the standard
|
||||
|
@ -77,43 +88,16 @@ static int lid_angle_is_reliable;
|
|||
* frame before calculating lid angle).
|
||||
*/
|
||||
#ifdef CONFIG_ACCEL_STD_REF_FRAME_OLD
|
||||
const struct accel_orientation acc_orient = {
|
||||
/* Hinge aligns with y axis. */
|
||||
.rot_hinge_90 = {
|
||||
{ 0, 0, FLOAT_TO_FP(1)},
|
||||
{ 0, FLOAT_TO_FP(1), 0},
|
||||
{ FLOAT_TO_FP(-1), 0, 0}
|
||||
},
|
||||
.rot_hinge_180 = {
|
||||
{ FLOAT_TO_FP(-1), 0, 0},
|
||||
{ 0, FLOAT_TO_FP(1), 0},
|
||||
{ 0, 0, FLOAT_TO_FP(-1)}
|
||||
},
|
||||
.hinge_axis = {0, 1, 0},
|
||||
};
|
||||
static const intv3_t hinge_axis = { 0, 1, 0};
|
||||
#define HINGE_AXIS Y
|
||||
#else
|
||||
const struct accel_orientation acc_orient = {
|
||||
/* Hinge aligns with x axis. */
|
||||
.rot_hinge_90 = {
|
||||
{ FLOAT_TO_FP(1), 0, 0},
|
||||
{ 0, 0, FLOAT_TO_FP(1)},
|
||||
{ 0, FLOAT_TO_FP(-1), 0}
|
||||
},
|
||||
.rot_hinge_180 = {
|
||||
{ FLOAT_TO_FP(1), 0, 0},
|
||||
{ 0, FLOAT_TO_FP(-1), 0},
|
||||
{ 0, 0, FLOAT_TO_FP(-1)}
|
||||
},
|
||||
.hinge_axis = {1, 0, 0},
|
||||
};
|
||||
static const intv3_t hinge_axis = { 1, 0, 0};
|
||||
#define HINGE_AXIS X
|
||||
#endif
|
||||
|
||||
/* Pointer to constant acceleration orientation data. */
|
||||
const struct accel_orientation * const p_acc_orient = &acc_orient;
|
||||
|
||||
const struct motion_sensor_t * const accel_base =
|
||||
static const struct motion_sensor_t * const accel_base =
|
||||
&motion_sensors[CONFIG_LID_ANGLE_SENSOR_BASE];
|
||||
const struct motion_sensor_t * const accel_lid =
|
||||
static const struct motion_sensor_t * const accel_lid =
|
||||
&motion_sensors[CONFIG_LID_ANGLE_SENSOR_LID];
|
||||
|
||||
#ifdef CONFIG_TABLET_MODE
|
||||
|
@ -165,16 +149,6 @@ static fp_t laptop_zone_lid_angle =
|
|||
static int tablet_mode_lid_angle = DEFAULT_TABLET_MODE_ANGLE;
|
||||
static int tablet_mode_hys_degree = DEFAULT_TABLET_MODE_HYS;
|
||||
|
||||
/*
|
||||
* We will change our tablet mode status when we are "convinced" that it has
|
||||
* changed. This means we will have to consecutively calculate our new tablet
|
||||
* mode while the angle is stable and come to the same conclusion. The number
|
||||
* of consecutive calculations is the debounce count with an interval between
|
||||
* readings set by the motion_sense task. This should avoid spurious forces
|
||||
* that may trigger false transitions of the tablet mode switch.
|
||||
*/
|
||||
#define TABLET_MODE_DEBOUNCE_COUNT 3
|
||||
|
||||
static void motion_lid_set_tablet_mode(int reliable)
|
||||
{
|
||||
static int tablet_mode_debounce_cnt = TABLET_MODE_DEBOUNCE_COUNT;
|
||||
|
@ -305,109 +279,41 @@ static void motion_lid_set_dptf_profile(int reliable)
|
|||
static int calculate_lid_angle(const intv3_t base, const intv3_t lid,
|
||||
int *lid_angle)
|
||||
{
|
||||
intv3_t v;
|
||||
fp_t lid_to_base_fp, cos_lid_90, cos_lid_270;
|
||||
fp_t lid_to_base, base_to_hinge;
|
||||
fp_t denominator;
|
||||
int reliable = 1;
|
||||
int base_magnitude2, lid_magnitude2;
|
||||
int base_range, lid_range, i;
|
||||
intv3_t scaled_base, scaled_lid;
|
||||
intv3_t cross, proj_lid, proj_base, scaled_base, scaled_lid;
|
||||
fp_t lid_to_base_fp, smoothed_ratio;
|
||||
int base_magnitude2, lid_magnitude2, largest_hinge_accel;
|
||||
int reliable = 1, i;
|
||||
|
||||
/*
|
||||
* The angle between lid and base is:
|
||||
* acos((cad(base, lid) - cad(base, hinge)^2) /(1 - cad(base, hinge)^2))
|
||||
* where cad() is the cosine_of_angle_diff() function.
|
||||
*
|
||||
* Make sure to check for divide by 0.
|
||||
* Scale the vectors by their range, to be able to compare them.
|
||||
* If a single measurement is greated than 1g, we may overflow fixed
|
||||
* point calculation. However, we can exclude such a measurement, it
|
||||
* means the device is in movement and lid angle calculation is not
|
||||
* possible.
|
||||
*/
|
||||
lid_to_base = cosine_of_angle_diff(base, lid);
|
||||
base_to_hinge = cosine_of_angle_diff(base, p_acc_orient->hinge_axis);
|
||||
|
||||
/*
|
||||
* If hinge aligns too closely with gravity, then result may be
|
||||
* unreliable.
|
||||
*/
|
||||
if (fp_abs(base_to_hinge) > HINGE_ALIGNED_WITH_GRAVITY_THRESHOLD)
|
||||
reliable = 0;
|
||||
|
||||
base_to_hinge = fp_sq(base_to_hinge);
|
||||
|
||||
/* Check divide by 0. */
|
||||
denominator = FLOAT_TO_FP(1.0) - base_to_hinge;
|
||||
if (fp_abs(denominator) < FLOAT_TO_FP(0.01)) {
|
||||
*lid_angle = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
lid_to_base_fp = arc_cos(fp_div(lid_to_base - base_to_hinge,
|
||||
denominator));
|
||||
|
||||
/*
|
||||
* The previous calculation actually has two solutions, a positive and
|
||||
* a negative solution. To figure out the sign of the answer, calculate
|
||||
* the cosine of the angle between the actual lid angle and the
|
||||
* estimated vector if the lid were open to 90 deg, cos_lid_90. Also
|
||||
* calculate the cosine of the angle between the actual lid angle and
|
||||
* the estimated vector if the lid were open to 270 deg,
|
||||
* cos_lid_270. The smaller of the two angles represents which one is
|
||||
* closer. If the lid is closer to the estimated 270 degree vector then
|
||||
* the result is negative, otherwise it is positive.
|
||||
*/
|
||||
rotate(base, p_acc_orient->rot_hinge_90, v);
|
||||
cos_lid_90 = cosine_of_angle_diff(v, lid);
|
||||
rotate(v, p_acc_orient->rot_hinge_180, v);
|
||||
cos_lid_270 = cosine_of_angle_diff(v, lid);
|
||||
|
||||
/*
|
||||
* Note that cos_lid_90 and cos_lid_270 are not in degrees, because
|
||||
* the arc_cos() was never performed. But, since arc_cos() is
|
||||
* monotonically decreasing, we can do this comparison without ever
|
||||
* taking arc_cos(). But, since the function is monotonically
|
||||
* decreasing, the logic of this comparison is reversed.
|
||||
*/
|
||||
if (cos_lid_270 > cos_lid_90)
|
||||
lid_to_base_fp = -lid_to_base_fp;
|
||||
|
||||
/* Place lid angle between 0 and 360 degrees. */
|
||||
if (lid_to_base_fp < 0)
|
||||
lid_to_base_fp += FLOAT_TO_FP(360);
|
||||
|
||||
/*
|
||||
* Perform some additional reliability checks.
|
||||
*
|
||||
* If the magnitude of the two vectors differ too greatly, then the
|
||||
* readings are unreliable and we can't use them to calculate the lid
|
||||
* angle.
|
||||
*/
|
||||
|
||||
/* Scale the vectors by their range. */
|
||||
base_range = accel_base->drv->get_range(accel_base);
|
||||
lid_range = accel_lid->drv->get_range(accel_lid);
|
||||
|
||||
for (i = X; i <= Z; i++) {
|
||||
/*
|
||||
* To increase precision, we'll use 8x the sensor data in the
|
||||
* intermediate calculation. We would normally divide by 2^15.
|
||||
*
|
||||
* This is safe because even at a range of 8g, calculating the
|
||||
* magnitude squared should still be less than the max of a
|
||||
* 32-bit signed integer.
|
||||
*
|
||||
* The max that base[i] could be is 32768, resulting in a max
|
||||
* value for scaled_base[i] of 640 @ 8g range and force.
|
||||
* Typically our range is set to 2g.
|
||||
*/
|
||||
scaled_base[i] = base[i] * base_range * 10 >> 12;
|
||||
scaled_lid[i] = lid[i] * lid_range * 10 >> 12;
|
||||
scaled_base[i] = base[i] *
|
||||
accel_base->drv->get_range(accel_base);
|
||||
scaled_lid[i] = lid[i] *
|
||||
accel_lid->drv->get_range(accel_lid);
|
||||
if (ABS(scaled_base[i]) > MOTION_SCALING_AXIS_MAX ||
|
||||
ABS(scaled_lid[i]) > MOTION_SCALING_AXIS_MAX) {
|
||||
reliable = 0;
|
||||
goto end_calculate_lid_angle;
|
||||
}
|
||||
}
|
||||
|
||||
base_magnitude2 = (scaled_base[X] * scaled_base[X] +
|
||||
scaled_base[Y] * scaled_base[Y] +
|
||||
scaled_base[Z] * scaled_base[Z]) >> 6;
|
||||
lid_magnitude2 = (scaled_lid[X] * scaled_lid[X] +
|
||||
scaled_lid[Y] * scaled_lid[Y] +
|
||||
scaled_lid[Z] * scaled_lid[Z]) >> 6;
|
||||
/*
|
||||
* Calculate square of vector magnitude in g.
|
||||
* Each entry is guaranteed to be up to +/- 1<<15, so the square will be
|
||||
* less than 1<<30.
|
||||
*/
|
||||
base_magnitude2 = scaled_base[X] * scaled_base[X] +
|
||||
scaled_base[Y] * scaled_base[Y] +
|
||||
scaled_base[Z] * scaled_base[Z];
|
||||
lid_magnitude2 = scaled_lid[X] * scaled_lid[X] +
|
||||
scaled_lid[Y] * scaled_lid[Y] +
|
||||
scaled_lid[Z] * scaled_lid[Z];
|
||||
|
||||
/*
|
||||
* Check to see if they differ than more than NOISY_MAGNITUDE_DEVIATION.
|
||||
|
@ -417,27 +323,93 @@ static int calculate_lid_angle(const intv3_t base, const intv3_t lid,
|
|||
* magnitude, but we can work with the magnitudes squared directly as
|
||||
* shown below:
|
||||
*
|
||||
* If A and B are the base and lid magnitudes, and x is the noisy
|
||||
* magnitude deviation:
|
||||
* If A is a magnitudes, and x is the noisy magnitude deviation:
|
||||
*
|
||||
* A - B < x
|
||||
* A^2 - B^2 < x * (A + B)
|
||||
* A^2 - B^2 < 2 * x * avg(A, B)
|
||||
* 0 < 1g - A < x
|
||||
* 0 < 1g^2 - A^2 < x * (A + B)
|
||||
* 0 < 1g^2 - A^2 < 2 * x * avg(A, B)
|
||||
*
|
||||
* If we assume that the average acceleration should be about 1g, then
|
||||
* we have:
|
||||
*
|
||||
* (A^2 - B^2) < 2 * 1g * NOISY_MAGNITUDE_DEVIATION
|
||||
* 0 < 1g^2 - A^2 < 2 * 1g * NOISY_MAGNITUDE_DEVIATION
|
||||
*/
|
||||
if (ABS(base_magnitude2 - lid_magnitude2) >
|
||||
(2 * 10 * NOISY_MAGNITUDE_DEVIATION))
|
||||
if (MOTION_SCALING_FACTOR2 - base_magnitude2 >
|
||||
2 * MOTION_SCALING_FACTOR * NOISY_MAGNITUDE_DEVIATION) {
|
||||
reliable = 0;
|
||||
goto end_calculate_lid_angle;
|
||||
}
|
||||
if (MOTION_SCALING_FACTOR2 - lid_magnitude2 >
|
||||
2 * MOTION_SCALING_FACTOR * NOISY_MAGNITUDE_DEVIATION) {
|
||||
reliable = 0;
|
||||
goto end_calculate_lid_angle;
|
||||
}
|
||||
|
||||
largest_hinge_accel = MAX(ABS(scaled_base[HINGE_AXIS]),
|
||||
ABS(scaled_lid[HINGE_AXIS]));
|
||||
|
||||
smoothed_ratio = MAX(INT_TO_FP(0), MIN(INT_TO_FP(1),
|
||||
fp_div(INT_TO_FP(largest_hinge_accel -
|
||||
SCALED_HINGE_VERTICAL_SMOOTHING_START),
|
||||
INT_TO_FP(SCALED_HINGE_VERTICAL_MAXIMUM -
|
||||
SCALED_HINGE_VERTICAL_SMOOTHING_START))));
|
||||
|
||||
/* Check hinge is not too vertical */
|
||||
if (largest_hinge_accel > SCALED_HINGE_VERTICAL_MAXIMUM) {
|
||||
reliable = 0;
|
||||
goto end_calculate_lid_angle;
|
||||
}
|
||||
|
||||
/* Smooth input to reduce calculation error due to noise. */
|
||||
vector_scale(smoothed_base, smoothed_ratio);
|
||||
vector_scale(smoothed_lid, smoothed_ratio);
|
||||
vector_scale(scaled_base, INT_TO_FP(1) - smoothed_ratio);
|
||||
vector_scale(scaled_lid, INT_TO_FP(1) - smoothed_ratio);
|
||||
for (i = X; i <= Z; i++) {
|
||||
smoothed_base[i] += scaled_base[i];
|
||||
smoothed_lid[i] += scaled_lid[i];
|
||||
}
|
||||
|
||||
/* Project vectors on the hinge hyperplan, putting smooth ones aside. */
|
||||
memcpy(proj_base, smoothed_base, sizeof(intv3_t));
|
||||
memcpy(proj_lid, smoothed_lid, sizeof(intv3_t));
|
||||
proj_base[HINGE_AXIS] = 0;
|
||||
proj_lid[HINGE_AXIS] = 0;
|
||||
|
||||
/* Calculate the clockwise angle */
|
||||
lid_to_base_fp = arc_cos(cosine_of_angle_diff(proj_base, proj_lid));
|
||||
cross_product(proj_base, proj_lid, cross);
|
||||
|
||||
/*
|
||||
* If the dot product of this cross product is normal, it means that
|
||||
* the shortest angle between |base| and |lid| was counterclockwise
|
||||
* with respect to the surface represented by |hinge_axis| and this
|
||||
* angle must be reversed.
|
||||
*/
|
||||
if (dot_product(cross, hinge_axis) > 0)
|
||||
lid_to_base_fp = FLOAT_TO_FP(360) - lid_to_base_fp;
|
||||
|
||||
#ifndef CONFIG_ACCEL_STD_REF_FRAME_OLD
|
||||
/*
|
||||
* Angle is between the keyboard and the front of screen: we need to
|
||||
* anlge between keyboard and back of screen:
|
||||
* 180 instead of 0 when lid and base are flat on surface.
|
||||
* 0 instead of 180 when lid is closed on keyboard.
|
||||
*/
|
||||
lid_to_base_fp = FLOAT_TO_FP(180) - lid_to_base_fp;
|
||||
#endif
|
||||
|
||||
/* Place lid angle between 0 and 360 degrees. */
|
||||
if (lid_to_base_fp < 0)
|
||||
lid_to_base_fp += FLOAT_TO_FP(360);
|
||||
|
||||
#ifdef CONFIG_TABLET_MODE
|
||||
/* Ignore large angles when the lid is closed. */
|
||||
if (!lid_is_open() &&
|
||||
(lid_to_base_fp > FLOAT_TO_FP(SMALL_LID_ANGLE_RANGE)))
|
||||
(lid_to_base_fp > SMALL_LID_ANGLE_RANGE)) {
|
||||
reliable = 0;
|
||||
goto end_calculate_lid_angle;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ignore small angles when the lid is open.
|
||||
|
@ -451,33 +423,31 @@ static int calculate_lid_angle(const intv3_t base, const intv3_t lid,
|
|||
* reliable readings over a threshold to disable key scanning.
|
||||
*/
|
||||
if (lid_is_open() &&
|
||||
(lid_to_base_fp <= FLOAT_TO_FP(SMALL_LID_ANGLE_RANGE)))
|
||||
(lid_to_base_fp <= SMALL_LID_ANGLE_RANGE)) {
|
||||
reliable = 0;
|
||||
|
||||
if (reliable) {
|
||||
/*
|
||||
* Seed the lid angle now that we have a reliable
|
||||
* measurement.
|
||||
*/
|
||||
if (last_lid_angle_fp == FLOAT_TO_FP(-1))
|
||||
last_lid_angle_fp = lid_to_base_fp;
|
||||
|
||||
/*
|
||||
* If the angle was last seen as really large and now it's quite
|
||||
* small, we may be rotating around from 360->0 so correct it to
|
||||
* be large. But in case that the lid switch is closed, we can
|
||||
* prove the small angle we see is correct so we take the angle
|
||||
* as is.
|
||||
*/
|
||||
if ((last_lid_angle_fp >=
|
||||
FLOAT_TO_FP(360) - DEBOUNCE_ANGLE_DELTA) &&
|
||||
(lid_to_base_fp <= DEBOUNCE_ANGLE_DELTA) &&
|
||||
(lid_is_open()))
|
||||
last_lid_angle_fp = FLOAT_TO_FP(360) - lid_to_base_fp;
|
||||
else
|
||||
last_lid_angle_fp = lid_to_base_fp;
|
||||
goto end_calculate_lid_angle;
|
||||
}
|
||||
|
||||
/* Seed the lid angle now that we have a reliable measurement. */
|
||||
if (last_lid_angle_fp == FLOAT_TO_FP(-1))
|
||||
last_lid_angle_fp = lid_to_base_fp;
|
||||
|
||||
/*
|
||||
* If the angle was last seen as really large and now it's quite
|
||||
* small, we may be rotating around from 360->0 so correct it to
|
||||
* be large. But in case that the lid switch is closed, we can
|
||||
* prove the small angle we see is correct so we take the angle
|
||||
* as is.
|
||||
*/
|
||||
if ((last_lid_angle_fp >=
|
||||
FLOAT_TO_FP(360) - DEBOUNCE_ANGLE_DELTA) &&
|
||||
(lid_to_base_fp <= DEBOUNCE_ANGLE_DELTA) &&
|
||||
(lid_is_open()))
|
||||
last_lid_angle_fp = FLOAT_TO_FP(360) - lid_to_base_fp;
|
||||
else
|
||||
last_lid_angle_fp = lid_to_base_fp;
|
||||
|
||||
end_calculate_lid_angle:
|
||||
/*
|
||||
* Round to nearest int by adding 0.5. Note, only works because lid
|
||||
* angle is known to be positive.
|
||||
|
@ -493,7 +463,9 @@ static int calculate_lid_angle(const intv3_t base, const intv3_t lid,
|
|||
#endif /* CONFIG_DPTF_MULTI_PROFILE && CONFIG_DPTF_MOTION_LID_NO_HALL_SENSOR */
|
||||
|
||||
#else /* CONFIG_TABLET_MODE */
|
||||
*lid_angle = FP_TO_INT(lid_to_base_fp + FLOAT_TO_FP(0.5));
|
||||
end_calculate_lid_angle:
|
||||
if (reliable)
|
||||
*lid_angle = FP_TO_INT(lid_to_base_fp + FLOAT_TO_FP(0.5));
|
||||
#endif
|
||||
return reliable;
|
||||
}
|
||||
|
@ -511,25 +483,10 @@ int motion_lid_get_angle(void)
|
|||
*/
|
||||
void motion_lid_calc(void)
|
||||
{
|
||||
#ifndef CONFIG_ACCEL_STD_REF_FRAME_OLD
|
||||
/*
|
||||
* rotate lid vector by 180 deg to be in the right coordinate frame
|
||||
* because calculate_lid_angle assumes when the lid is closed, that
|
||||
* the lid and base accelerometer data matches
|
||||
*/
|
||||
intv3_t lid = { accel_lid->xyz[X],
|
||||
accel_lid->xyz[Y] * -1,
|
||||
accel_lid->xyz[Z] * -1};
|
||||
/* Calculate angle of lid accel. */
|
||||
lid_angle_is_reliable = calculate_lid_angle(
|
||||
accel_base->xyz, lid,
|
||||
&lid_angle_deg);
|
||||
#else
|
||||
/* Calculate angle of lid accel. */
|
||||
lid_angle_is_reliable = calculate_lid_angle(
|
||||
accel_base->xyz, accel_lid->xyz,
|
||||
&lid_angle_deg);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_LID_ANGLE_UPDATE
|
||||
lid_angle_update(motion_lid_get_angle());
|
||||
|
|
|
@ -10,6 +10,14 @@
|
|||
|
||||
/* Header file for accelerometer / gyro drivers. */
|
||||
|
||||
/*
|
||||
* EC reports sensor data on 16 bits. For accel/gyro/mag.. the MSB is the sign.
|
||||
* For instance, for gravity,
|
||||
* real_value[in g] = measured_value * range >> 15
|
||||
*/
|
||||
#define MOTION_SCALING_FACTOR (1 << 15)
|
||||
#define MOTION_ONE_G (9.80665f)
|
||||
|
||||
struct accelgyro_drv {
|
||||
/**
|
||||
* Initialize accelerometers.
|
||||
|
|
|
@ -11,27 +11,15 @@
|
|||
#include "host_command.h"
|
||||
#include "math_util.h"
|
||||
|
||||
/**
|
||||
* This structure defines all of the data needed to specify the orientation
|
||||
* of the base and lid accelerometers in order to calculate the lid angle.
|
||||
/*
|
||||
* We will change our tablet mode status when we are "convinced" that it has
|
||||
* changed. This means we will have to consecutively calculate our new tablet
|
||||
* mode while the angle is stable and come to the same conclusion. The number
|
||||
* of consecutive calculations is the debounce count with an interval between
|
||||
* readings set by the motion_sense task. This should avoid spurious forces
|
||||
* that may trigger false transitions of the tablet mode switch.
|
||||
*/
|
||||
struct accel_orientation {
|
||||
/* Rotation matrix to rotate positive 90 degrees around the hinge. */
|
||||
mat33_fp_t rot_hinge_90;
|
||||
|
||||
/*
|
||||
* Rotation matrix to rotate 180 degrees around the hinge. The value
|
||||
* here should be rot_hinge_90 ^ 2.
|
||||
*/
|
||||
mat33_fp_t rot_hinge_180;
|
||||
|
||||
/* Vector pointing along hinge axis. */
|
||||
intv3_t hinge_axis;
|
||||
};
|
||||
|
||||
/* Link global structure for orientation. This must be defined in board.c. */
|
||||
extern const struct accel_orientation acc_orient;
|
||||
|
||||
#define TABLET_MODE_DEBOUNCE_COUNT 3
|
||||
|
||||
/**
|
||||
* Get last calculated lid angle. Note, the lid angle calculated by the EC
|
||||
|
|
|
@ -41,6 +41,8 @@ test-list-host += kb_scan
|
|||
test-list-host += lid_sw
|
||||
test-list-host += lightbar
|
||||
test-list-host += math_util
|
||||
test-list-host += motion_angle
|
||||
test-list-host += motion_angle_tablet
|
||||
test-list-host += motion_lid
|
||||
test-list-host += mutex
|
||||
test-list-host += nvmem
|
||||
|
@ -97,6 +99,8 @@ kb_scan-y=kb_scan.o
|
|||
lid_sw-y=lid_sw.o
|
||||
lightbar-y=lightbar.o
|
||||
math_util-y=math_util.o
|
||||
motion_angle-y=motion_angle.o motion_angle_data_literals.o motion_common.o
|
||||
motion_angle_tablet-y=motion_angle_tablet.o motion_angle_data_literals_tablet.o motion_common.o
|
||||
motion_lid-y=motion_lid.o
|
||||
mutex-y=mutex.o
|
||||
nvmem-y=nvmem.o
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
/* Copyright 2019 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
* Test motion sense code: Check lid angle calculation and tablet mode
|
||||
* transition.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "accelgyro.h"
|
||||
#include "common.h"
|
||||
#include "gpio.h"
|
||||
#include "hooks.h"
|
||||
#include "motion_common.h"
|
||||
#include "motion_lid.h"
|
||||
#include "motion_sense.h"
|
||||
#include "tablet_mode.h"
|
||||
#include "test_util.h"
|
||||
#include "util.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Test utilities */
|
||||
|
||||
/* Array units is in m/s^2 - old matrix format. */
|
||||
int filler(const struct motion_sensor_t *s, const float v)
|
||||
{
|
||||
return (v * MOTION_SCALING_FACTOR) / s->drv->get_range(s);
|
||||
}
|
||||
|
||||
static int test_lid_angle_less180(void)
|
||||
{
|
||||
int index = 0, lid_angle;
|
||||
struct motion_sensor_t *lid = &motion_sensors[
|
||||
CONFIG_LID_ANGLE_SENSOR_LID];
|
||||
struct motion_sensor_t *base = &motion_sensors[
|
||||
CONFIG_LID_ANGLE_SENSOR_BASE];
|
||||
|
||||
/* We don't have TASK_CHIP so simulate init ourselves */
|
||||
hook_notify(HOOK_CHIPSET_SHUTDOWN);
|
||||
TEST_ASSERT(sensor_active == SENSOR_ACTIVE_S5);
|
||||
TEST_ASSERT(lid->drv->get_data_rate(lid) == 0);
|
||||
TEST_ASSERT(motion_interval == 0);
|
||||
|
||||
/* Go to S0 state */
|
||||
hook_notify(HOOK_CHIPSET_SUSPEND);
|
||||
hook_notify(HOOK_CHIPSET_RESUME);
|
||||
msleep(1000);
|
||||
TEST_ASSERT(sensor_active == SENSOR_ACTIVE_S0);
|
||||
TEST_ASSERT(lid->drv->get_data_rate(lid) == TEST_LID_FREQUENCY);
|
||||
TEST_ASSERT(motion_interval == TEST_LID_EC_RATE);
|
||||
|
||||
/* Open lid, testing close to 180 degree. */
|
||||
gpio_set_level(GPIO_LID_OPEN, 1);
|
||||
msleep(1000);
|
||||
|
||||
cprints(CC_ACCEL, "start loop");
|
||||
/* Check we will never enter tablet mode. */
|
||||
while (index < kAccelerometerLaptopModeTestDataLength) {
|
||||
feed_accel_data(kAccelerometerLaptopModeTestData,
|
||||
&index, filler);
|
||||
wait_for_valid_sample();
|
||||
lid_angle = motion_lid_get_angle();
|
||||
cprints(CC_ACCEL, "%d : LID(%d, %d, %d)/BASE(%d, %d, %d): %d",
|
||||
index / TEST_LID_SAMPLE_SIZE,
|
||||
lid->xyz[X], lid->xyz[Y], lid->xyz[Z],
|
||||
base->xyz[X], base->xyz[Y], base->xyz[Z],
|
||||
lid_angle);
|
||||
/* We need few sample to debounce and enter laptop mode. */
|
||||
TEST_ASSERT(index < TEST_LID_SAMPLE_SIZE *
|
||||
(TABLET_MODE_DEBOUNCE_COUNT + 2) ||
|
||||
!tablet_get_mode());
|
||||
}
|
||||
|
||||
/* Check we will never exit tablet mode. */
|
||||
index = 0;
|
||||
while (index < kAccelerometerFullyOpenTestDataLength) {
|
||||
feed_accel_data(kAccelerometerFullyOpenTestData,
|
||||
&index, filler);
|
||||
wait_for_valid_sample();
|
||||
lid_angle = motion_lid_get_angle();
|
||||
cprints(CC_ACCEL, "%d : LID(%d, %d, %d)/BASE(%d, %d, %d): %d",
|
||||
index / TEST_LID_SAMPLE_SIZE,
|
||||
lid->xyz[X], lid->xyz[Y], lid->xyz[Z],
|
||||
base->xyz[X], base->xyz[Y], base->xyz[Z],
|
||||
lid_angle);
|
||||
TEST_ASSERT(index < TEST_LID_SAMPLE_SIZE *
|
||||
(TABLET_MODE_DEBOUNCE_COUNT + 2) ||
|
||||
tablet_get_mode());
|
||||
}
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void run_test(void)
|
||||
{
|
||||
test_reset();
|
||||
|
||||
RUN_TEST(test_lid_angle_less180);
|
||||
|
||||
test_print_result();
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
/**
|
||||
* List of enabled tasks in the priority order
|
||||
*
|
||||
* The first one has the lowest priority.
|
||||
*
|
||||
* For each task, use the macro TASK_TEST(n, r, d, s) where :
|
||||
* 'n' in the name of the task
|
||||
* 'r' in the main routine of the task
|
||||
* 'd' in an opaque parameter passed to the routine at startup
|
||||
* 's' is the stack size in bytes; must be a multiple of 8
|
||||
*/
|
||||
#define CONFIG_TEST_TASK_LIST \
|
||||
TASK_TEST(MOTIONSENSE, motion_sense_task, NULL, TASK_STACK_SIZE)
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,111 @@
|
|||
/* Copyright 2018 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
* Test motion sense code, when in tablet mode.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "accelgyro.h"
|
||||
#include "common.h"
|
||||
#include "gpio.h"
|
||||
#include "hooks.h"
|
||||
#include "motion_common.h"
|
||||
#include "motion_lid.h"
|
||||
#include "motion_sense.h"
|
||||
#include "tablet_mode.h"
|
||||
#include "test_util.h"
|
||||
#include "util.h"
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Test utilities */
|
||||
|
||||
/* convert array value from g to m.s^2. */
|
||||
int filler(const struct motion_sensor_t *s, const float v)
|
||||
{
|
||||
return FP_TO_INT( fp_div(
|
||||
FLOAT_TO_FP(v) * MOTION_SCALING_FACTOR,
|
||||
fp_mul(INT_TO_FP(s->drv->get_range(s)), MOTION_ONE_G)));
|
||||
}
|
||||
|
||||
static int test_lid_angle_less180(void)
|
||||
{
|
||||
int index = 0, lid_angle;
|
||||
struct motion_sensor_t *lid = &motion_sensors[
|
||||
CONFIG_LID_ANGLE_SENSOR_LID];
|
||||
struct motion_sensor_t *base = &motion_sensors[
|
||||
CONFIG_LID_ANGLE_SENSOR_BASE];
|
||||
|
||||
/* We don't have TASK_CHIP so simulate init ourselves */
|
||||
hook_notify(HOOK_CHIPSET_SHUTDOWN);
|
||||
TEST_ASSERT(sensor_active == SENSOR_ACTIVE_S5);
|
||||
TEST_ASSERT(lid->drv->get_data_rate(lid) == 0);
|
||||
TEST_ASSERT(motion_interval == 0);
|
||||
|
||||
/* Go to S0 state */
|
||||
hook_notify(HOOK_CHIPSET_SUSPEND);
|
||||
hook_notify(HOOK_CHIPSET_RESUME);
|
||||
msleep(1000);
|
||||
TEST_ASSERT(sensor_active == SENSOR_ACTIVE_S0);
|
||||
TEST_ASSERT(lid->drv->get_data_rate(lid) == TEST_LID_FREQUENCY);
|
||||
TEST_ASSERT(motion_interval == TEST_LID_EC_RATE);
|
||||
|
||||
/* Open lid, testing close to 180 degree. */
|
||||
gpio_set_level(GPIO_LID_OPEN, 1);
|
||||
msleep(1000);
|
||||
|
||||
cprints(CC_ACCEL, "start loop");
|
||||
/* Force clamshell mode, to be sure we go in tablet mode ASAP. */
|
||||
tablet_set_mode(0);
|
||||
|
||||
/* Check we stay in tablet mode, even when hinge is vertical. */
|
||||
while (index < kAccelerometerVerticalHingeTestDataLength) {
|
||||
feed_accel_data(kAccelerometerVerticalHingeTestData,
|
||||
&index, filler);
|
||||
wait_for_valid_sample();
|
||||
lid_angle = motion_lid_get_angle();
|
||||
cprints(CC_ACCEL, "%d : LID(%d, %d, %d)/BASE(%d, %d, %d): %d",
|
||||
index / TEST_LID_SAMPLE_SIZE,
|
||||
lid->xyz[X], lid->xyz[Y], lid->xyz[Z],
|
||||
base->xyz[X], base->xyz[Y], base->xyz[Z],
|
||||
lid_angle);
|
||||
/* We need few sample to debounce and enter laptop mode. */
|
||||
TEST_ASSERT(index < 2 * TEST_LID_SAMPLE_SIZE * \
|
||||
(TABLET_MODE_DEBOUNCE_COUNT + 2) ||
|
||||
tablet_get_mode());
|
||||
}
|
||||
/*
|
||||
* Check we stay in tablet mode, even when hinge is vertical and
|
||||
* shaked.
|
||||
*/
|
||||
tablet_set_mode(0);
|
||||
while (index < kAccelerometerVerticalHingeUnstableTestDataLength) {
|
||||
feed_accel_data(kAccelerometerVerticalHingeUnstableTestData,
|
||||
&index, filler);
|
||||
wait_for_valid_sample();
|
||||
lid_angle = motion_lid_get_angle();
|
||||
cprints(CC_ACCEL, "%d : LID(%d, %d, %d)/BASE(%d, %d, %d): %d",
|
||||
index / TEST_LID_SAMPLE_SIZE,
|
||||
lid->xyz[X], lid->xyz[Y], lid->xyz[Z],
|
||||
base->xyz[X], base->xyz[Y], base->xyz[Z],
|
||||
lid_angle);
|
||||
/* We need few sample to debounce and enter laptop mode. */
|
||||
TEST_ASSERT(index < TEST_LID_SAMPLE_SIZE *
|
||||
(TABLET_MODE_DEBOUNCE_COUNT + 2) ||
|
||||
tablet_get_mode());
|
||||
}
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void run_test(void)
|
||||
{
|
||||
test_reset();
|
||||
|
||||
RUN_TEST(test_lid_angle_less180);
|
||||
|
||||
test_print_result();
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
/**
|
||||
* List of enabled tasks in the priority order
|
||||
*
|
||||
* The first one has the lowest priority.
|
||||
*
|
||||
* For each task, use the macro TASK_TEST(n, r, d, s) where :
|
||||
* 'n' in the name of the task
|
||||
* 'r' in the main routine of the task
|
||||
* 'd' in an opaque parameter passed to the routine at startup
|
||||
* 's' is the stack size in bytes; must be a multiple of 8
|
||||
*/
|
||||
#define CONFIG_TEST_TASK_LIST \
|
||||
TASK_TEST(MOTIONSENSE, motion_sense_task, NULL, TASK_STACK_SIZE)
|
|
@ -0,0 +1,125 @@
|
|||
/* Copyright 2018 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
* Common test code to test lid angle calculation.
|
||||
*/
|
||||
|
||||
#include "accelgyro.h"
|
||||
#include "host_command.h"
|
||||
#include "motion_common.h"
|
||||
#include "motion_sense.h"
|
||||
#include "task.h"
|
||||
#include "timer.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Mock functions */
|
||||
static int accel_init(const struct motion_sensor_t *s)
|
||||
{
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
static int accel_read(const struct motion_sensor_t *s, intv3_t v)
|
||||
{
|
||||
rotate(s->xyz, *s->rot_standard_ref, v);
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
static int accel_get_range(const struct motion_sensor_t *s)
|
||||
{
|
||||
return s->default_range;
|
||||
}
|
||||
|
||||
static int accel_get_resolution(const struct motion_sensor_t *s)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_data_rate[2] = { 0 };
|
||||
|
||||
static int accel_set_data_rate(const struct motion_sensor_t *s,
|
||||
const int rate,
|
||||
const int rnd)
|
||||
{
|
||||
test_data_rate[s - motion_sensors] = rate | (rnd ? ROUND_UP_FLAG : 0);
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
static int accel_get_data_rate(const struct motion_sensor_t *s)
|
||||
{
|
||||
return test_data_rate[s - motion_sensors];
|
||||
}
|
||||
|
||||
const struct accelgyro_drv test_motion_sense = {
|
||||
.init = accel_init,
|
||||
.read = accel_read,
|
||||
.get_range = accel_get_range,
|
||||
.get_resolution = accel_get_resolution,
|
||||
.set_data_rate = accel_set_data_rate,
|
||||
.get_data_rate = accel_get_data_rate,
|
||||
};
|
||||
|
||||
struct motion_sensor_t motion_sensors[] = {
|
||||
{
|
||||
.name = "base",
|
||||
.active_mask = SENSOR_ACTIVE_S0_S3_S5,
|
||||
.chip = MOTIONSENSE_CHIP_LSM6DS0,
|
||||
.type = MOTIONSENSE_TYPE_ACCEL,
|
||||
.location = MOTIONSENSE_LOC_BASE,
|
||||
.drv = &test_motion_sense,
|
||||
.rot_standard_ref = NULL,
|
||||
.default_range = 2, /* g, enough for laptop. */
|
||||
.config = {
|
||||
/* EC use accel for angle detection */
|
||||
[SENSOR_CONFIG_EC_S0] = {
|
||||
.odr = TEST_LID_FREQUENCY,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
.name = "lid",
|
||||
.active_mask = SENSOR_ACTIVE_S0,
|
||||
.chip = MOTIONSENSE_CHIP_KXCJ9,
|
||||
.type = MOTIONSENSE_TYPE_ACCEL,
|
||||
.location = MOTIONSENSE_LOC_LID,
|
||||
.drv = &test_motion_sense,
|
||||
.rot_standard_ref = NULL,
|
||||
.default_range = 2, /* g, enough for laptop. */
|
||||
.config = {
|
||||
/* EC use accel for angle detection */
|
||||
[SENSOR_CONFIG_EC_S0] = {
|
||||
.odr = TEST_LID_FREQUENCY,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const unsigned int motion_sensor_count = ARRAY_SIZE(motion_sensors);
|
||||
|
||||
/* Read 6 samples from array to sensor vectors, convert units if necessary. */
|
||||
void feed_accel_data(const float *array, int *idx,
|
||||
int (filler)(const struct motion_sensor_t*, const float))
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < motion_sensor_count; i++) {
|
||||
struct motion_sensor_t *s = &motion_sensors[i];
|
||||
|
||||
for (j = X; j <= Z; j++)
|
||||
s->xyz[j] = filler(s, array[*idx + i * 3 + j]);
|
||||
}
|
||||
*idx += 6;
|
||||
}
|
||||
|
||||
void wait_for_valid_sample(void)
|
||||
{
|
||||
uint8_t sample;
|
||||
uint8_t *lpc_status = host_get_memmap(EC_MEMMAP_ACC_STATUS);
|
||||
|
||||
sample = *lpc_status & EC_MEMMAP_ACC_STATUS_SAMPLE_ID_MASK;
|
||||
usleep(TEST_LID_EC_RATE);
|
||||
task_wake(TASK_ID_MOTIONSENSE);
|
||||
while ((*lpc_status & EC_MEMMAP_ACC_STATUS_SAMPLE_ID_MASK) == sample)
|
||||
usleep(TEST_LID_SLEEP_RATE);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
/* Copyright 2018 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
* Common test code to test lid angle calculation.
|
||||
*/
|
||||
#ifndef __CROS_EC_MOTION_COMMON_H
|
||||
#define __CROS_EC_MOTION_COMMON_H
|
||||
|
||||
#include "motion_sense.h"
|
||||
/*
|
||||
* Period in us for the motion task period.
|
||||
* The task will read the vectors at that interval
|
||||
*/
|
||||
#define TEST_LID_EC_RATE (1 * MSEC)
|
||||
#define TEST_LID_FREQUENCY (1e9 / TEST_LID_EC_RATE) /* mHz */
|
||||
|
||||
/*
|
||||
* Time in ms to wait for the task to read the vectors.
|
||||
*/
|
||||
#define TEST_LID_SLEEP_RATE (TEST_LID_EC_RATE / 5)
|
||||
|
||||
/* We gather 6 elements [2 vectors of 3 axis] per sample. */
|
||||
#define TEST_LID_SAMPLE_SIZE (2 * 3)
|
||||
|
||||
extern enum chipset_state_mask sensor_active;
|
||||
extern unsigned int motion_interval;
|
||||
|
||||
extern struct motion_sensor_t motion_sensors[];
|
||||
extern const unsigned int motion_sensor_count;
|
||||
|
||||
void wait_for_valid_sample(void);
|
||||
void feed_accel_data(const float *array, int *idx,
|
||||
int (filler)(const struct motion_sensor_t *s, const float f));
|
||||
|
||||
/*
|
||||
* External data - from
|
||||
* chromium/src/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
|
||||
*
|
||||
* Test accelerometer data taken with the lid at less than 180 degrees while
|
||||
* shaking the device around. The data is to be interpreted in groups of 6 where
|
||||
* each 6 values corresponds to the base accelerometer (-y / g, -x / g, -z / g)
|
||||
* followed by the lid accelerometer (-y / g , x / g, z / g).
|
||||
* [ CONFIG_ACCEL_STD_REF_FRAME_OLD must be defined to used this array. ]
|
||||
*/
|
||||
extern const float kAccelerometerLaptopModeTestData[];
|
||||
extern const size_t kAccelerometerLaptopModeTestDataLength;
|
||||
|
||||
/*
|
||||
* Test accelerometer data taken with the lid open 360 degrees while
|
||||
* shaking the device around. The data is to be interpreted in groups of 6 where
|
||||
* each 6 values corresponds to the base accelerometer (-y / g, -x / g, -z / g)
|
||||
* followed by the lid accelerometer (-y / g , x / g, z / g).
|
||||
* [ CONFIG_ACCEL_STD_REF_FRAME_OLD must be defined to used this array. ]
|
||||
*/
|
||||
extern const float kAccelerometerFullyOpenTestData[];
|
||||
extern const size_t kAccelerometerFullyOpenTestDataLength;
|
||||
|
||||
/*
|
||||
* Test accelerometer data taken with the lid open 360 degrees while the device
|
||||
* hinge was nearly vertical, while shaking the device around. The data is to be
|
||||
* interpreted in groups of 6 where each 6 values corresponds to the X, Y, and Z
|
||||
* readings from the base and lid accelerometers in this order.
|
||||
*/
|
||||
extern const float kAccelerometerVerticalHingeTestData[];
|
||||
extern const size_t kAccelerometerVerticalHingeTestDataLength;
|
||||
extern const float kAccelerometerVerticalHingeUnstableTestData[];
|
||||
extern const size_t kAccelerometerVerticalHingeUnstableTestDataLength;
|
||||
#endif /* __CROS_EC_MOTION_COMMON_H */
|
|
@ -33,6 +33,7 @@ extern unsigned motion_interval;
|
|||
* Time in ms to wait for the task to read the vectors.
|
||||
*/
|
||||
#define TEST_LID_SLEEP_RATE (TEST_LID_EC_RATE / 5)
|
||||
#define ONE_G_MEASURED (1 << 14)
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Mock functions */
|
||||
|
@ -56,7 +57,7 @@ static int accel_set_range(const struct motion_sensor_t *s,
|
|||
|
||||
static int accel_get_range(const struct motion_sensor_t *s)
|
||||
{
|
||||
return 0;
|
||||
return s->default_range;
|
||||
}
|
||||
|
||||
static int accel_get_resolution(const struct motion_sensor_t *s)
|
||||
|
@ -97,7 +98,7 @@ struct motion_sensor_t motion_sensors[] = {
|
|||
.location = MOTIONSENSE_LOC_BASE,
|
||||
.drv = &test_motion_sense,
|
||||
.rot_standard_ref = NULL,
|
||||
.default_range = 2, /* g, enough for laptop. */
|
||||
.default_range = MOTION_SCALING_FACTOR / ONE_G_MEASURED,
|
||||
.config = {
|
||||
/* AP: by default shutdown all sensors */
|
||||
[SENSOR_CONFIG_AP] = {
|
||||
|
@ -127,7 +128,7 @@ struct motion_sensor_t motion_sensors[] = {
|
|||
.location = MOTIONSENSE_LOC_LID,
|
||||
.drv = &test_motion_sense,
|
||||
.rot_standard_ref = NULL,
|
||||
.default_range = 2, /* g, enough for laptop. */
|
||||
.default_range = MOTION_SCALING_FACTOR / ONE_G_MEASURED,
|
||||
.config = {
|
||||
/* AP: by default shutdown all sensors */
|
||||
[SENSOR_CONFIG_AP] = {
|
||||
|
@ -174,6 +175,7 @@ static int test_lid_angle(void)
|
|||
CONFIG_LID_ANGLE_SENSOR_BASE];
|
||||
struct motion_sensor_t *lid = &motion_sensors[
|
||||
CONFIG_LID_ANGLE_SENSOR_LID];
|
||||
int lid_angle;
|
||||
|
||||
/* We don't have TASK_CHIP so simulate init ourselves */
|
||||
hook_notify(HOOK_CHIPSET_SHUTDOWN);
|
||||
|
@ -195,10 +197,10 @@ static int test_lid_angle(void)
|
|||
*/
|
||||
base->xyz[X] = 0;
|
||||
base->xyz[Y] = 0;
|
||||
base->xyz[Z] = 1000;
|
||||
base->xyz[Z] = ONE_G_MEASURED;
|
||||
lid->xyz[X] = 0;
|
||||
lid->xyz[Y] = 0;
|
||||
lid->xyz[Z] = -1000;
|
||||
lid->xyz[Z] = -ONE_G_MEASURED;
|
||||
gpio_set_level(GPIO_LID_OPEN, 0);
|
||||
/* Initial wake up, like init does */
|
||||
task_wake(TASK_ID_MOTIONSENSE);
|
||||
|
@ -208,11 +210,16 @@ static int test_lid_angle(void)
|
|||
task_wake(TASK_ID_MOTIONSENSE);
|
||||
|
||||
wait_for_valid_sample();
|
||||
TEST_ASSERT(motion_lid_get_angle() == 0);
|
||||
lid_angle = motion_lid_get_angle();
|
||||
cprints(CC_ACCEL, "LID(%d, %d, %d)/BASE(%d, %d, %d): %d",
|
||||
lid->xyz[X], lid->xyz[Y], lid->xyz[Z],
|
||||
base->xyz[X], base->xyz[Y], base->xyz[Z],
|
||||
lid_angle);
|
||||
TEST_ASSERT(lid_angle == 0);
|
||||
|
||||
/* Set lid open to 90 degrees. */
|
||||
lid->xyz[X] = 0;
|
||||
lid->xyz[Y] = 1000;
|
||||
lid->xyz[Y] = ONE_G_MEASURED;
|
||||
lid->xyz[Z] = 0;
|
||||
gpio_set_level(GPIO_LID_OPEN, 1);
|
||||
msleep(100);
|
||||
|
@ -222,15 +229,15 @@ static int test_lid_angle(void)
|
|||
|
||||
/* Set lid open to 225. */
|
||||
lid->xyz[X] = 0;
|
||||
lid->xyz[Y] = -500;
|
||||
lid->xyz[Z] = 500;
|
||||
lid->xyz[Y] = -1 * ONE_G_MEASURED * 0.707106;
|
||||
lid->xyz[Z] = ONE_G_MEASURED * 0.707106;
|
||||
wait_for_valid_sample();
|
||||
TEST_ASSERT(motion_lid_get_angle() == 225);
|
||||
|
||||
/* Set lid open to 350 */
|
||||
lid->xyz[X] = 0;
|
||||
lid->xyz[Y] = -173;
|
||||
lid->xyz[Z] = -984;
|
||||
lid->xyz[Y] = -1 * ONE_G_MEASURED * 0.1736;
|
||||
lid->xyz[Z] = -1 * ONE_G_MEASURED * 0.9848;
|
||||
wait_for_valid_sample();
|
||||
TEST_ASSERT(motion_lid_get_angle() == 350);
|
||||
|
||||
|
@ -239,15 +246,15 @@ static int test_lid_angle(void)
|
|||
* open, we should be getting an unreliable reading.
|
||||
*/
|
||||
lid->xyz[X] = 0;
|
||||
lid->xyz[Y] = 173;
|
||||
lid->xyz[Z] = -984;
|
||||
lid->xyz[Y] = ONE_G_MEASURED * 0.1736;
|
||||
lid->xyz[Z] = -1 * ONE_G_MEASURED * 0.9848;
|
||||
wait_for_valid_sample();
|
||||
TEST_ASSERT(motion_lid_get_angle() == LID_ANGLE_UNRELIABLE);
|
||||
|
||||
/* Rotate back to 180 and then 10 */
|
||||
lid->xyz[X] = 0;
|
||||
lid->xyz[Y] = 0;
|
||||
lid->xyz[Z] = 1000;
|
||||
lid->xyz[Z] = ONE_G_MEASURED;
|
||||
wait_for_valid_sample();
|
||||
TEST_ASSERT(motion_lid_get_angle() == 180);
|
||||
|
||||
|
@ -256,8 +263,8 @@ static int test_lid_angle(void)
|
|||
* See SMALL_LID_ANGLE_RANGE.
|
||||
*/
|
||||
lid->xyz[X] = 0;
|
||||
lid->xyz[Y] = 173;
|
||||
lid->xyz[Z] = -984;
|
||||
lid->xyz[Y] = ONE_G_MEASURED * 0.1736;
|
||||
lid->xyz[Z] = -1 * ONE_G_MEASURED * 0.9848;
|
||||
wait_for_valid_sample();
|
||||
TEST_ASSERT(motion_lid_get_angle() == LID_ANGLE_UNRELIABLE);
|
||||
|
||||
|
@ -265,7 +272,7 @@ static int test_lid_angle(void)
|
|||
* 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] = 1000;
|
||||
base->xyz[X] = ONE_G_MEASURED;
|
||||
base->xyz[Y] = 0;
|
||||
base->xyz[Z] = 0;
|
||||
wait_for_valid_sample();
|
||||
|
@ -275,12 +282,12 @@ static int test_lid_angle(void)
|
|||
* 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;
|
||||
base->xyz[X] = 5296;
|
||||
base->xyz[Y] = 7856;
|
||||
base->xyz[Z] = 13712;
|
||||
lid->xyz[X] = 5296;
|
||||
lid->xyz[Y] = 7856;
|
||||
lid->xyz[Z] = 13712;
|
||||
wait_for_valid_sample();
|
||||
TEST_ASSERT(motion_lid_get_angle() == 180);
|
||||
|
||||
|
@ -289,10 +296,10 @@ static int test_lid_angle(void)
|
|||
*/
|
||||
base->xyz[X] = 0;
|
||||
base->xyz[Y] = 0;
|
||||
base->xyz[Z] = 1000;
|
||||
base->xyz[Z] = ONE_G_MEASURED;
|
||||
lid->xyz[X] = 0;
|
||||
lid->xyz[Y] = 0;
|
||||
lid->xyz[Z] = -1000;
|
||||
lid->xyz[Z] = -1 * ONE_G_MEASURED;
|
||||
gpio_set_level(GPIO_LID_OPEN, 0);
|
||||
msleep(100);
|
||||
wait_for_valid_sample();
|
||||
|
@ -303,8 +310,8 @@ static int test_lid_angle(void)
|
|||
* be regarded as unreliable.
|
||||
*/
|
||||
lid->xyz[X] = 0;
|
||||
lid->xyz[Y] = -173;
|
||||
lid->xyz[Z] = -984;
|
||||
lid->xyz[Y] = -1 * ONE_G_MEASURED * 0.1736;
|
||||
lid->xyz[Z] = -1 * ONE_G_MEASURED * 0.9848;
|
||||
wait_for_valid_sample();
|
||||
TEST_ASSERT(motion_lid_get_angle() == LID_ANGLE_UNRELIABLE);
|
||||
|
||||
|
@ -317,8 +324,8 @@ static int test_lid_angle(void)
|
|||
gpio_set_level(GPIO_LID_OPEN, 0);
|
||||
msleep(100);
|
||||
lid->xyz[X] = 0;
|
||||
lid->xyz[Y] = 173;
|
||||
lid->xyz[Z] = -984;
|
||||
lid->xyz[Y] = ONE_G_MEASURED * 0.1736;
|
||||
lid->xyz[Z] = -1 * ONE_G_MEASURED * 0.9848;
|
||||
wait_for_valid_sample();
|
||||
TEST_ASSERT(motion_lid_get_angle() == 10);
|
||||
|
||||
|
|
|
@ -66,7 +66,8 @@
|
|||
#define CONFIG_MAG_CALIBRATE
|
||||
#endif
|
||||
|
||||
#ifdef TEST_MOTION_LID
|
||||
#if defined(TEST_MOTION_LID) || defined(TEST_MOTION_ANGLE) || \
|
||||
defined(TEST_MOTION_ANGLE_TABLET)
|
||||
#define CONFIG_LID_ANGLE
|
||||
#define CONFIG_LID_ANGLE_SENSOR_BASE 0
|
||||
#define CONFIG_LID_ANGLE_SENSOR_LID 1
|
||||
|
@ -74,6 +75,19 @@
|
|||
#define CONFIG_MOTION_FILL_LPC_SENSE_DATA
|
||||
#endif
|
||||
|
||||
#if defined(TEST_MOTION_ANGLE)
|
||||
#define CONFIG_ACCEL_FORCE_MODE_MASK \
|
||||
((1 << CONFIG_LID_ANGLE_SENSOR_BASE) | \
|
||||
(1 << CONFIG_LID_ANGLE_SENSOR_LID))
|
||||
#define CONFIG_ACCEL_STD_REF_FRAME_OLD
|
||||
#endif
|
||||
|
||||
#if defined(TEST_MOTION_ANGLE_TABLET)
|
||||
#define CONFIG_ACCEL_FORCE_MODE_MASK \
|
||||
((1 << CONFIG_LID_ANGLE_SENSOR_BASE) | \
|
||||
(1 << CONFIG_LID_ANGLE_SENSOR_LID))
|
||||
#endif
|
||||
|
||||
#ifdef TEST_RMA_AUTH
|
||||
|
||||
/* Test server public and private keys */
|
||||
|
|
Loading…
Reference in New Issue