Initial commit

IMU and bubble level working
This commit is contained in:
Brent Perteet
2025-06-14 16:38:53 -05:00
commit f59eb660cf
21 changed files with 6704 additions and 0 deletions

132
main/bubble.c Normal file
View File

@@ -0,0 +1,132 @@
#include "bubble.h"
typedef struct {
float min_val;
float max_val;
float cur_val;
} bubble_level_dsc_t;
static void bubble_draw_cb(lv_event_t * e)
{
lvgl_port_lock(0);
lv_obj_t * obj = lv_event_get_target(e);
bubble_level_dsc_t * d = lv_obj_get_user_data(obj);
if(!d) return;
// 1) Get the LVGL draw layer (clipping is automatic)
lv_layer_t * layer = lv_event_get_layer(e);
// 2) Figure out the object's inner rectangle
lv_area_t coords;
lv_obj_get_coords(obj, &coords);
lv_area_t inner = {
.x1 = coords.x1 + 2, .y1 = coords.y1 + 2,
.x2 = coords.x2 - 2, .y2 = coords.y2 - 2
};
// 3) Draw the border
lv_draw_rect_dsc_t rect_dsc;
lv_draw_rect_dsc_init(&rect_dsc);
rect_dsc.border_color = lv_color_hex(0xAAAAAA);
rect_dsc.border_width = 2;
rect_dsc.bg_opa = LV_OPA_TRANSP;
lv_draw_rect(layer, &rect_dsc, &inner);
// 4) Draw guide lines at the center
lv_coord_t mid_x = (inner.x1 + inner.x2) / 2;
lv_coord_t mid_y = (inner.y1 + inner.y2) / 2;
lv_draw_line_dsc_t line_dsc;
lv_draw_line_dsc_init(&line_dsc);
line_dsc.color = lv_color_hex(0x444444);
line_dsc.width = 1;
// Set up points and convert to 'precise' type
lv_point_t tl = { inner.x1 + 10, mid_y };
lv_point_t tr = { inner.x2 - 10, mid_y };
line_dsc.p1 = lv_point_to_precise(&tl);
line_dsc.p2 = lv_point_to_precise(&tr);
lv_draw_line(layer, &line_dsc);
lv_point_t tt = { mid_x, inner.y1 + 10 };
lv_point_t tb = { mid_x, inner.y2 - 10 };
line_dsc.p1 = lv_point_to_precise(&tt);
line_dsc.p2 = lv_point_to_precise(&tb);
lv_draw_line(layer, &line_dsc);
// 5) Compute bubble position (normalized between min_val → max_val)
float norm = (d->cur_val - d->min_val) / (d->max_val - d->min_val);
norm = norm < 0 ? 0 : (norm > 1 ? 1 : norm);
const lv_coord_t bubble_d = 16;
lv_coord_t avail_w = (inner.x2 - inner.x1 + 1) - bubble_d;
lv_coord_t bx = inner.x1 + (lv_coord_t)(norm * avail_w);
lv_coord_t by = mid_y - (bubble_d / 2);
// 6) Draw the bubble as a filled circle (rounded rect)
lv_draw_rect_dsc_t circ_dsc;
lv_draw_rect_dsc_init(&circ_dsc);
circ_dsc.bg_color = lv_color_hex(0x00CC00);
circ_dsc.bg_opa = LV_OPA_COVER;
circ_dsc.radius = bubble_d / 2;
circ_dsc.border_opa = LV_OPA_TRANSP;
lv_area_t circ_area = {
.x1 = bx,
.y1 = by,
.x2 = bx + bubble_d - 1,
.y2 = by + bubble_d - 1
};
lv_draw_rect(layer, &circ_dsc, &circ_area);
lvgl_port_unlock();
}
lv_obj_t * bubble_create(lv_obj_t * parent,
lv_coord_t width, lv_coord_t height,
float min_val, float max_val, float initial)
{
// 1) Create a container object (no special style)
lv_obj_t * obj = lv_obj_create(parent);
lv_obj_set_size(obj, width, height);
// (Optional) center it or let the caller position it:
// lv_obj_center(obj);
// 2) Allocate or attach our descriptor
// In LVGL v9 you can use USER_DATA: need to enable LV_USE_USER_DATA = 1
bubble_level_dsc_t * dsc = lv_malloc(sizeof(bubble_level_dsc_t));
if(!dsc) return NULL; /* handle out-of-memory */
dsc->min_val = min_val;
dsc->max_val = max_val;
dsc->cur_val = initial;
lv_obj_set_user_data(obj, dsc);
// 3) Register our draw callback
lv_obj_add_event_cb(obj, bubble_draw_cb, LV_EVENT_DRAW_MAIN, NULL);
// 4) Make sure the object does NOT get a default background fill
lv_obj_set_style_bg_opa(obj, LV_OPA_TRANSP, 0);
return obj;
}
void bubble_setValue(lv_obj_t * bubble, float v)
{
lvgl_port_lock(0);
// 1) Retrieve the descriptor
bubble_level_dsc_t * d = lv_obj_get_user_data(bubble);
if(!d) return;
// 2) Update the stored value
d->cur_val = v;
// 3) Tell LVGL that object must be redrawn
lv_obj_invalidate(bubble);
lvgl_port_unlock();
}