mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-10-17 02:45:05 +00:00
IMU Updates (#694)
* IMU Updates Updated BMI270 and MPU6886 with the mount-matrix. Updated devices i can test with the mount-matrix. papers3, stackchan (cores3), sticks3, tab5, waveshare-s3-lcd-13, waveshare-s3-lcd-128 Devices not changed and not tested because i don't own them are: MPU6886 - core2, stickc-plus2. BMI270 - cardputer-adv * Update device.properties * No USB here! CH343P
This commit is contained in:
parent
6a3c549324
commit
d0ad1b014c
@ -65,7 +65,9 @@
|
||||
bmi270 {
|
||||
compatible = "bosch,bmi270";
|
||||
reg = <0x69>;
|
||||
invert-x;
|
||||
mount-matrix = <1 0 0
|
||||
0 1 0
|
||||
0 0 1>;
|
||||
};
|
||||
|
||||
bm8563 {
|
||||
|
||||
@ -44,6 +44,9 @@
|
||||
bmi270 {
|
||||
compatible = "bosch,bmi270";
|
||||
reg = <0x68>;
|
||||
mount-matrix = <0 1 0
|
||||
1 0 0
|
||||
0 0 -1>;
|
||||
};
|
||||
|
||||
bm8563 {
|
||||
|
||||
@ -70,7 +70,9 @@
|
||||
bmi270 {
|
||||
compatible = "bosch,bmi270";
|
||||
reg = <0x69>;
|
||||
invert-x;
|
||||
mount-matrix = <1 0 0
|
||||
0 1 0
|
||||
0 0 1>;
|
||||
};
|
||||
|
||||
bm8563 {
|
||||
|
||||
@ -63,6 +63,9 @@
|
||||
bmi270 {
|
||||
compatible = "bosch,bmi270";
|
||||
reg = <0x68>;
|
||||
mount-matrix = <0 1 0
|
||||
-1 0 0
|
||||
0 0 1>;
|
||||
};
|
||||
|
||||
es8311 {
|
||||
|
||||
@ -83,6 +83,9 @@
|
||||
bmi270 {
|
||||
compatible = "bosch,bmi270";
|
||||
reg = <0x68>;
|
||||
mount-matrix = <-1 0 0
|
||||
0 1 0
|
||||
0 0 -1>;
|
||||
};
|
||||
|
||||
es8388 {
|
||||
|
||||
@ -8,7 +8,6 @@ hardware.flashSize=16MB
|
||||
hardware.spiRam=true
|
||||
hardware.spiRamMode=OCT
|
||||
hardware.spiRamSpeed=120M
|
||||
hardware.tinyUsbMsc=true
|
||||
hardware.esptoolFlashFreq=120M
|
||||
hardware.bluetooth=true
|
||||
|
||||
|
||||
@ -9,7 +9,6 @@
|
||||
#include <bindings/qmi8658.h>
|
||||
#include <tactility/bindings/esp32_sdspi.h>
|
||||
#include <tactility/bindings/esp32_pwm_ledc.h>
|
||||
#include <tactility/bindings/esp32_usbdevice.h>
|
||||
#include <tactility/bindings/pwm_backlight.h>
|
||||
#include <bindings/st7789.h>
|
||||
|
||||
@ -41,6 +40,9 @@
|
||||
qmi8658 {
|
||||
compatible = "qst,qmi8658";
|
||||
reg = <0x6B>;
|
||||
mount-matrix = <-1 0 0
|
||||
0 -1 0
|
||||
0 0 -1>;
|
||||
};
|
||||
};
|
||||
|
||||
@ -89,12 +91,4 @@
|
||||
frequency-khz = <20000>;
|
||||
};
|
||||
};
|
||||
|
||||
usbdevice0 {
|
||||
compatible = "espressif,esp32-usbdevice";
|
||||
|
||||
usbdevicemsc0 {
|
||||
compatible = "espressif,esp32-usbdevice-msc";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@ -9,7 +9,6 @@ hardware.spiRam=true
|
||||
hardware.spiRamMode=QUAD
|
||||
hardware.spiRamSpeed=120M
|
||||
hardware.spiRamXipDisabled=true
|
||||
hardware.tinyUsbMsc=true
|
||||
hardware.esptoolFlashFreq=120M
|
||||
hardware.bluetooth=true
|
||||
|
||||
|
||||
@ -9,7 +9,6 @@
|
||||
#include <bindings/qmi8658.h>
|
||||
#include <tactility/bindings/esp32_sdspi.h>
|
||||
#include <tactility/bindings/esp32_pwm_ledc.h>
|
||||
#include <tactility/bindings/esp32_usbdevice.h>
|
||||
#include <tactility/bindings/pwm_backlight.h>
|
||||
#include <bindings/cst816t.h>
|
||||
#include <bindings/gc9a01.h>
|
||||
@ -42,6 +41,9 @@
|
||||
qmi8658 {
|
||||
compatible = "qst,qmi8658";
|
||||
reg = <0x6B>;
|
||||
mount-matrix = <0 1 0
|
||||
1 0 0
|
||||
0 0 1>;
|
||||
};
|
||||
|
||||
touch0 {
|
||||
@ -93,12 +95,4 @@
|
||||
backlight = <&display_backlight>;
|
||||
};
|
||||
};
|
||||
|
||||
usbdevice0 {
|
||||
compatible = "espressif,esp32-usbdevice";
|
||||
|
||||
usbdevicemsc0 {
|
||||
compatible = "espressif,esp32-usbdevice-msc";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@ -5,27 +5,11 @@ include: [ "i2c-device.yaml" ]
|
||||
compatible: "bosch,bmi270"
|
||||
|
||||
properties:
|
||||
swap-xy:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Swap the X and Y axes
|
||||
swap-xz:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Swap the X and Z axes
|
||||
swap-yz:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Swap the Y and Z axes
|
||||
invert-x:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Invert the X axis
|
||||
invert-y:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Invert the Y axis
|
||||
invert-z:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Invert the Z axis
|
||||
mount-matrix:
|
||||
type: values
|
||||
default: [1, 0, 0, 0, 1, 0, 0, 0, 1]
|
||||
description: >
|
||||
Row-major 3x3 rotation matrix that maps the sensor frame onto the device frame, following the
|
||||
Linux IIO "mount-matrix" convention (x' = m[0]*x + m[1]*y + m[2]*z, and so on). It is applied
|
||||
to the accelerometer and gyroscope readings so consumers always see the device frame,
|
||||
regardless of how the IMU is physically oriented on the PCB. Defaults to the identity matrix.
|
||||
|
||||
@ -14,12 +14,12 @@ extern "C" {
|
||||
struct Bmi270Config {
|
||||
/** Address on bus */
|
||||
uint8_t address;
|
||||
bool swap_xy;
|
||||
bool swap_xz;
|
||||
bool swap_yz;
|
||||
bool invert_x;
|
||||
bool invert_y;
|
||||
bool invert_z;
|
||||
/**
|
||||
* Row-major 3x3 rotation matrix mapping the sensor frame onto the device frame (Linux IIO
|
||||
* "mount-matrix" convention: `out[i] = m[i * 3] * x + m[i * 3 + 1] * y + m[i * 3 + 2] * z`).
|
||||
* Identity means the sensor frame already matches the device frame.
|
||||
*/
|
||||
int32_t mount_matrix[9];
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -5,8 +5,6 @@
|
||||
#include <tactility/drivers/i2c_controller.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#define TAG "BMI270"
|
||||
|
||||
static constexpr uint8_t REG_CHIP_ID = 0x00; // read: expect 0x24
|
||||
@ -90,6 +88,18 @@ static bool configure(Device* i2c_controller, uint8_t address) {
|
||||
|
||||
// region Driver lifecycle
|
||||
|
||||
// Applies the devicetree mount matrix (sensor frame -> device frame) to a 3-axis reading.
|
||||
// Flat row-major [9]: x' = m0*x + m1*y + m2*z, y' = m3*x + m4*y + m5*z, z' = m6*x + m7*y + m8*z.
|
||||
static void applyMountMatrix(const Bmi270Config& config, float& x, float& y, float& z) {
|
||||
const int32_t* m = config.mount_matrix;
|
||||
const float rx = m[0] * x + m[1] * y + m[2] * z;
|
||||
const float ry = m[3] * x + m[4] * y + m[5] * z;
|
||||
const float rz = m[6] * x + m[7] * y + m[8] * z;
|
||||
x = rx;
|
||||
y = ry;
|
||||
z = rz;
|
||||
}
|
||||
|
||||
static error_t start(Device* device) {
|
||||
auto* i2c_controller = device_get_parent(device);
|
||||
if (device_get_type(i2c_controller) != &I2C_CONTROLLER_TYPE) {
|
||||
@ -171,13 +181,7 @@ error_t bmi270_read_accel(Device* device, ImuAccelData* data) {
|
||||
toI16(buffer[2], buffer[3]) * ACCEL_SCALE,
|
||||
toI16(buffer[4], buffer[5]) * ACCEL_SCALE,
|
||||
};
|
||||
const auto& config = *GET_CONFIG(device);
|
||||
if (config.swap_xy) std::swap(axes[0], axes[1]);
|
||||
if (config.swap_xz) std::swap(axes[0], axes[2]);
|
||||
if (config.swap_yz) std::swap(axes[1], axes[2]);
|
||||
if (config.invert_x) axes[0] = -axes[0];
|
||||
if (config.invert_y) axes[1] = -axes[1];
|
||||
if (config.invert_z) axes[2] = -axes[2];
|
||||
applyMountMatrix(*GET_CONFIG(device), axes[0], axes[1], axes[2]);
|
||||
data->ax = axes[0];
|
||||
data->ay = axes[1];
|
||||
data->az = axes[2];
|
||||
@ -197,9 +201,13 @@ error_t bmi270_read_gyro(Device* device, ImuGyroData* data) {
|
||||
return static_cast<int16_t>(static_cast<uint16_t>(hi) << 8 | lo);
|
||||
};
|
||||
|
||||
data->gx = toI16(buffer[0], buffer[1]) * GYRO_SCALE;
|
||||
data->gy = toI16(buffer[2], buffer[3]) * GYRO_SCALE;
|
||||
data->gz = toI16(buffer[4], buffer[5]) * GYRO_SCALE;
|
||||
float gx = toI16(buffer[0], buffer[1]) * GYRO_SCALE;
|
||||
float gy = toI16(buffer[2], buffer[3]) * GYRO_SCALE;
|
||||
float gz = toI16(buffer[4], buffer[5]) * GYRO_SCALE;
|
||||
applyMountMatrix(*GET_CONFIG(device), gx, gy, gz);
|
||||
data->gx = gx;
|
||||
data->gy = gy;
|
||||
data->gz = gz;
|
||||
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
@ -5,27 +5,11 @@ include: [ "i2c-device.yaml" ]
|
||||
compatible: "invensense,mpu6886"
|
||||
|
||||
properties:
|
||||
swap-xy:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Swap the X and Y axes
|
||||
swap-xz:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Swap the X and Z axes
|
||||
swap-yz:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Swap the Y and Z axes
|
||||
invert-x:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Invert the X axis
|
||||
invert-y:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Invert the Y axis
|
||||
invert-z:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Invert the Z axis
|
||||
mount-matrix:
|
||||
type: values
|
||||
default: [1, 0, 0, 0, 1, 0, 0, 0, 1]
|
||||
description: >
|
||||
Row-major 3x3 rotation matrix that maps the sensor frame onto the device frame, following the
|
||||
Linux IIO "mount-matrix" convention (x' = m[0]*x + m[1]*y + m[2]*z, and so on). It is applied
|
||||
to the accelerometer and gyroscope readings so consumers always see the device frame,
|
||||
regardless of how the IMU is physically oriented on the PCB. Defaults to the identity matrix.
|
||||
|
||||
@ -14,12 +14,12 @@ extern "C" {
|
||||
struct Mpu6886Config {
|
||||
/** Address on bus */
|
||||
uint8_t address;
|
||||
bool swap_xy;
|
||||
bool swap_xz;
|
||||
bool swap_yz;
|
||||
bool invert_x;
|
||||
bool invert_y;
|
||||
bool invert_z;
|
||||
/**
|
||||
* Row-major 3x3 rotation matrix mapping the sensor frame onto the device frame (Linux IIO
|
||||
* "mount-matrix" convention: `out[i] = m[i * 3] * x + m[i * 3 + 1] * y + m[i * 3 + 2] * z`).
|
||||
* Identity means the sensor frame already matches the device frame.
|
||||
*/
|
||||
int32_t mount_matrix[9];
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -4,8 +4,6 @@
|
||||
#include <tactility/drivers/i2c_controller.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#define TAG "MPU6886"
|
||||
|
||||
// Register map
|
||||
@ -48,6 +46,18 @@ static constexpr TickType_t I2C_TIMEOUT_TICKS = pdMS_TO_TICKS(10);
|
||||
|
||||
// region Driver lifecycle
|
||||
|
||||
// Applies the devicetree mount matrix (sensor frame -> device frame) to a 3-axis reading.
|
||||
// Flat row-major [9]: x' = m0*x + m1*y + m2*z, y' = m3*x + m4*y + m5*z, z' = m6*x + m7*y + m8*z.
|
||||
static void applyMountMatrix(const Mpu6886Config& config, float& x, float& y, float& z) {
|
||||
const int32_t* m = config.mount_matrix;
|
||||
const float rx = m[0] * x + m[1] * y + m[2] * z;
|
||||
const float ry = m[3] * x + m[4] * y + m[5] * z;
|
||||
const float rz = m[6] * x + m[7] * y + m[8] * z;
|
||||
x = rx;
|
||||
y = ry;
|
||||
z = rz;
|
||||
}
|
||||
|
||||
static error_t start(Device* device) {
|
||||
auto* i2c_controller = device_get_parent(device);
|
||||
if (device_get_type(i2c_controller) != &I2C_CONTROLLER_TYPE) {
|
||||
@ -145,13 +155,7 @@ error_t mpu6886_read_accel(Device* device, ImuAccelData* data) {
|
||||
toI16(buf[2], buf[3]) * ACCEL_SCALE,
|
||||
toI16(buf[4], buf[5]) * ACCEL_SCALE,
|
||||
};
|
||||
const auto& config = *GET_CONFIG(device);
|
||||
if (config.swap_xy) std::swap(axes[0], axes[1]);
|
||||
if (config.swap_xz) std::swap(axes[0], axes[2]);
|
||||
if (config.swap_yz) std::swap(axes[1], axes[2]);
|
||||
if (config.invert_x) axes[0] = -axes[0];
|
||||
if (config.invert_y) axes[1] = -axes[1];
|
||||
if (config.invert_z) axes[2] = -axes[2];
|
||||
applyMountMatrix(*GET_CONFIG(device), axes[0], axes[1], axes[2]);
|
||||
data->ax = axes[0];
|
||||
data->ay = axes[1];
|
||||
data->az = axes[2];
|
||||
@ -171,9 +175,13 @@ error_t mpu6886_read_gyro(Device* device, ImuGyroData* data) {
|
||||
error_t error = i2c_controller_read_register(i2c_controller, address, REG_GYRO_XOUT_H, buf, sizeof(buf), I2C_TIMEOUT_TICKS);
|
||||
if (error != ERROR_NONE) return error;
|
||||
|
||||
data->gx = toI16(buf[0], buf[1]) * GYRO_SCALE;
|
||||
data->gy = toI16(buf[2], buf[3]) * GYRO_SCALE;
|
||||
data->gz = toI16(buf[4], buf[5]) * GYRO_SCALE;
|
||||
float gx = toI16(buf[0], buf[1]) * GYRO_SCALE;
|
||||
float gy = toI16(buf[2], buf[3]) * GYRO_SCALE;
|
||||
float gz = toI16(buf[4], buf[5]) * GYRO_SCALE;
|
||||
applyMountMatrix(*GET_CONFIG(device), gx, gy, gz);
|
||||
data->gx = gx;
|
||||
data->gy = gy;
|
||||
data->gz = gz;
|
||||
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
@ -343,6 +343,10 @@ const struct ModuleSymbol lvgl_module_symbols[] = {
|
||||
DEFINE_MODULE_SYMBOL(lv_obj_set_style_height),
|
||||
DEFINE_MODULE_SYMBOL(lv_obj_set_style_clip_corner),
|
||||
DEFINE_MODULE_SYMBOL(lv_obj_set_style_shadow_color),
|
||||
DEFINE_MODULE_SYMBOL(lv_obj_set_parent),
|
||||
DEFINE_MODULE_SYMBOL(lv_obj_set_style_bg_image_tiled),
|
||||
DEFINE_MODULE_SYMBOL(lv_obj_set_style_image_recolor),
|
||||
DEFINE_MODULE_SYMBOL(lv_obj_set_style_image_opa),
|
||||
// lv_font
|
||||
DEFINE_MODULE_SYMBOL(lv_font_get_bitmap_fmt_txt),
|
||||
DEFINE_MODULE_SYMBOL(lv_font_get_default),
|
||||
|
||||
@ -84,7 +84,7 @@ struct Context {
|
||||
lv_obj_t* timeoutValueLabel = nullptr;
|
||||
lv_obj_t* screensaverValueLabel = nullptr;
|
||||
// Shown when auto-rotate is off or unavailable: the orientation label and chips
|
||||
lv_obj_t* orientationGroup = nullptr;
|
||||
lv_obj_t* orientationCard = nullptr;
|
||||
lv_obj_t* orientationChips = nullptr;
|
||||
lv_obj_t* autoRotateSwitch = nullptr;
|
||||
};
|
||||
@ -151,10 +151,10 @@ void setCheckedChip(lv_obj_t* chips, settings::display::Orientation orientation)
|
||||
});
|
||||
}
|
||||
|
||||
/** Shows or hides the manual orientation chips, depending on whether auto-rotate is on */
|
||||
/** Shows or hides the manual orientation card, depending on whether auto-rotate is on */
|
||||
void updateOrientationVisibility(Context* ctx) {
|
||||
const bool auto_rotate = ctx->autoRotateSwitch != nullptr && ctx->displaySettings.autoRotateEnabled;
|
||||
lv_obj_set_hidden(ctx->orientationGroup, auto_rotate);
|
||||
lv_obj_set_hidden(ctx->orientationCard, auto_rotate);
|
||||
}
|
||||
|
||||
void onOrientationChipPressed(lv_event_t* event) {
|
||||
@ -396,12 +396,12 @@ void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
}
|
||||
|
||||
// The card shows the manual orientation; auto-rotate hides it while it drives the rotation
|
||||
auto* orientation_card = lvgl_card_create(main_wrapper);
|
||||
lv_obj_set_size(orientation_card, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_flex_flow(orientation_card, LV_FLEX_FLOW_COLUMN);
|
||||
ctx->orientationCard = lvgl_card_create(main_wrapper);
|
||||
lv_obj_set_size(ctx->orientationCard, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lv_obj_set_flex_flow(ctx->orientationCard, LV_FLEX_FLOW_COLUMN);
|
||||
|
||||
ctx->orientationGroup = createCardGroup(orientation_card, "Orientation");
|
||||
ctx->orientationChips = createOrientationChips(ctx->orientationGroup, ctx->displaySettings.orientation, onOrientationChipPressed, ctx);
|
||||
auto* orientation_group = createCardGroup(ctx->orientationCard, "Orientation");
|
||||
ctx->orientationChips = createOrientationChips(orientation_group, ctx->displaySettings.orientation, onOrientationChipPressed, ctx);
|
||||
|
||||
updateOrientationVisibility(ctx);
|
||||
|
||||
@ -447,7 +447,7 @@ void destroyWidgets(void* userData) {
|
||||
ctx->timeoutCard = nullptr;
|
||||
ctx->timeoutValueLabel = nullptr;
|
||||
ctx->screensaverValueLabel = nullptr;
|
||||
ctx->orientationGroup = nullptr;
|
||||
ctx->orientationCard = nullptr;
|
||||
ctx->orientationChips = nullptr;
|
||||
ctx->autoRotateSwitch = nullptr;
|
||||
}
|
||||
|
||||
@ -7,7 +7,10 @@ namespace tt::service::autorotate {
|
||||
constexpr float FLAT_THRESHOLD = 0.45F; // gravity in the screen plane below this = lying flat
|
||||
constexpr int DEBOUNCE = 5; // consecutive readings before switching
|
||||
|
||||
// gx toward +Y -> rotation 0; each +90 degrees of gx/gy angle is one more quarter-turn.
|
||||
// ax/ay is the accelerometer support-force vector (points up, opposite gravity).
|
||||
// The UI top should point along (ax,ay): +Y -> rotation 0.
|
||||
// LVGL ROT90 is 90 deg counter-clockwise (UI top -> device left, -X), ROT270 is
|
||||
// 90 deg clockwise (UI top -> device right, +X), so +X maps to 270, not 90.
|
||||
static lv_display_rotation_t gravityToRotation(float gx, float gy, lv_display_rotation_t fallback) {
|
||||
float plane = sqrtf((gx * gx) + (gy * gy));
|
||||
if (plane < FLAT_THRESHOLD) {
|
||||
@ -22,9 +25,9 @@ static lv_display_rotation_t gravityToRotation(float gx, float gy, lv_display_ro
|
||||
int idx = (int)((ang + 45.0F) / 90.0F) % 4;
|
||||
static constexpr lv_display_rotation_t map[4] = {
|
||||
LV_DISPLAY_ROTATION_0,
|
||||
LV_DISPLAY_ROTATION_90,
|
||||
LV_DISPLAY_ROTATION_180,
|
||||
LV_DISPLAY_ROTATION_270,
|
||||
LV_DISPLAY_ROTATION_180,
|
||||
LV_DISPLAY_ROTATION_90,
|
||||
};
|
||||
return map[idx];
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ TEST_CASE("a flat reading below the threshold keeps the current rotation") {
|
||||
CHECK_EQ(math.update(0.1F, 0.1F), LV_DISPLAY_ROTATION_0);
|
||||
}
|
||||
|
||||
TEST_CASE("gravity toward +X classifies as rotation 90 when no debounce is needed yet") {
|
||||
TEST_CASE("accel toward +X classifies as rotation 270 when no debounce is needed yet") {
|
||||
OrientationMath math;
|
||||
math.reset(LV_DISPLAY_ROTATION_0);
|
||||
// A single reading only sets the debounce target - the previous rotation is still returned.
|
||||
@ -27,32 +27,34 @@ TEST_CASE("a new rotation is only applied after enough consecutive stable readin
|
||||
CHECK_EQ(last, LV_DISPLAY_ROTATION_0); // not yet debounced
|
||||
}
|
||||
last = math.update(1.0F, 0.0F);
|
||||
CHECK_EQ(last, LV_DISPLAY_ROTATION_90); // 6th call (5th consecutive stable reading) switches
|
||||
CHECK_EQ(last, LV_DISPLAY_ROTATION_270); // 6th call (5th consecutive stable reading) switches
|
||||
}
|
||||
|
||||
TEST_CASE("all four gravity directions map to the expected rotation") {
|
||||
TEST_CASE("all four accel directions map to the expected rotation") {
|
||||
OrientationMath math;
|
||||
math.reset(LV_DISPLAY_ROTATION_0);
|
||||
|
||||
auto settle = [&](float gx, float gy) {
|
||||
auto settle = [&](float ax, float ay) {
|
||||
lv_display_rotation_t result = LV_DISPLAY_ROTATION_0;
|
||||
for (int i = 0; i < 6; i++) {
|
||||
result = math.update(gx, gy);
|
||||
result = math.update(ax, ay);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
// Accel points up (opposite gravity); UI top follows it.
|
||||
// LVGL ROT90 is CCW (top -> -X), ROT270 is CW (top -> +X).
|
||||
CHECK_EQ(settle(0.0F, 1.0F), LV_DISPLAY_ROTATION_0);
|
||||
CHECK_EQ(settle(1.0F, 0.0F), LV_DISPLAY_ROTATION_90);
|
||||
CHECK_EQ(settle(1.0F, 0.0F), LV_DISPLAY_ROTATION_270);
|
||||
CHECK_EQ(settle(0.0F, -1.0F), LV_DISPLAY_ROTATION_180);
|
||||
CHECK_EQ(settle(-1.0F, 0.0F), LV_DISPLAY_ROTATION_270);
|
||||
CHECK_EQ(settle(-1.0F, 0.0F), LV_DISPLAY_ROTATION_90);
|
||||
}
|
||||
|
||||
TEST_CASE("an unstable target resets the debounce counter") {
|
||||
OrientationMath math;
|
||||
math.reset(LV_DISPLAY_ROTATION_0);
|
||||
|
||||
// Get close to switching to rotation 90...
|
||||
// Get close to switching to rotation 270...
|
||||
for (int i = 0; i < 4; i++) {
|
||||
math.update(1.0F, 0.0F);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user