Description
I am trying to implement round scale with needle-line (aka Speedometer) inside C++ class and function that run animation of moving needle to some value. When i am passing class object pointer to callback function, that invokes lv_scale_set_line_needle_value, my data corrupts and lv_scale_set_line_needle_value retruns nothing becourse scale->mode is random numbers (should be 8)
What MCU/Processor/Board and compiler are you using?
G++5 Linux Ubuntu 16.04 SDL simulator
What LVGL version are you using?
9.1 master
What do you want to achieve?
Class function called by class object run animation of moving needle line to set value.
What have you tried so far?
- Lambda for lv_anim_set_custom_exec_cb / lv_anim_set_exec_cb
- Passing objects with lv_anim user_data
3.Passing objects with void * obj to callack function
Code to reproduce
/**
* @file main
*
*/
/*********************
* INCLUDES
*********************/
#define _DEFAULT_SOURCE /* needed for usleep() */
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include "lvgl/lvgl.h"
//#include "lvgl/examples/lv_examples.h"
#include "lvgl/demos/lv_demos.h"
#include "main.h"
#include <sys/time.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdint.h>
#include <signal.h>
#include <functional>
/*********************
* DEFINES
*********************/
pthread_mutex_t lock;
timer_t timer_id;
// Обработчик сигнала таймера
void timer_handler(int signum) {
//pthread_mutex_lock(&lock);
// Увеличить таймер LVGL
lv_tick_inc(5);
// pthread_mutex_unlock(&lock);
}
// Создать и запустить таймер LVGL
void lvgl_timer_init() {
// Создать таймер
struct sigevent sev;
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIGRTMIN;
sev.sigev_value.sival_ptr = &timer_id;
timer_create(CLOCK_REALTIME, &sev, &timer_id);
// Установить интервал таймера
struct itimerspec its;
its.it_interval.tv_sec = 0;
its.it_interval.tv_nsec = 5 * 1000 * 1000; // 5 миллисекунд
its.it_value.tv_sec = 0;
its.it_value.tv_nsec = 5 * 1000 * 1000; // 5 миллисекунд
timer_settime(timer_id, 0, &its, NULL);
// Установить обработчик сигнала таймера
signal(SIGRTMIN, timer_handler);
}
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static lv_display_t * hal_init(int32_t w, int32_t h);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* VARIABLES
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
class Meter {
public:
Meter(lv_obj_t * parent, const char * title, const char * text1, int pos_x, int pos_y, int min_value, int max_value, int start, int end);
~Meter();
static void setValue(lv_anim_t * obj, int32_t val);
static void anim_ready_cb(lv_anim_t * a);
void runAnim(int32_t val);
void getScale() {this->scale;};
void getNeedle() {this->needle_line;};
int32_t value = 0;
int32_t ticks_count = 40 + 1;
lv_obj_t * scale;
lv_obj_t * needle_line;
lv_anim_t * anim_scale_line2;
void invalidateScale() {lv_obj_invalidate(this->needle_line);};
void sett(int32_t val);
private:
};
Meter::Meter(lv_obj_t * parent, const char * title, const char * text1, int pos_x, int pos_y, int min_value, int max_value, int start, int end) {
printf("Creating meter!\n");
int32_t ticks_count = 40 + 1;
lv_obj_t * scale = lv_scale_create(parent);
lv_scale_set_mode(scale, LV_SCALE_MODE_ROUND_INNER);
lv_scale_set_post_draw(scale, true);
lv_obj_set_width(scale, LV_PCT(100));
lv_obj_set_pos(scale, pos_x, pos_y);
lv_scale_set_angle_range(scale, 220);
lv_scale_set_rotation(scale, 160);
lv_obj_set_size(scale, 150, 150);
lv_scale_set_range(scale, min_value, max_value);
lv_scale_set_total_tick_count(scale, ticks_count);
lv_scale_set_major_tick_every(scale, (ticks_count / 4)); // big ticks count - 1
lv_scale_set_label_show(scale, true);
lv_obj_set_style_radius(scale, LV_RADIUS_CIRCLE, 0);
lv_obj_set_style_length(scale, 10, LV_PART_INDICATOR | LV_STATE_DEFAULT);
lv_obj_set_style_length(scale, 100, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_length(scale, 5, LV_PART_ITEMS | LV_STATE_DEFAULT);
lv_obj_t * needle_line = lv_line_create(scale);
lv_obj_set_style_line_width(needle_line, 6, LV_PART_MAIN);
lv_obj_set_style_line_rounded(needle_line, true, LV_PART_MAIN);
lv_obj_set_pos(needle_line, 0, 0);
lv_scale_set_line_needle_value(scale, needle_line, 60, value);
lv_obj_t * text = lv_label_create(scale);
lv_obj_set_pos(text, 0, 102);
lv_obj_set_size(text, LV_PCT(100), LV_PCT(30));
lv_label_set_text(text, text1);
lv_obj_set_style_bg_color(text, lv_color_hex(0xff000000), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_text_color(text, lv_color_hex(0xffffffff), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_bg_opa(text, LV_OPA_MAX, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_text_align(text, LV_TEXT_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT);
printf("global %d\n", value);
}
void Meter::setValue(lv_anim_t * obj, int32_t val) {
printf("Executing animation %d\n", val);
Meter *self = static_cast<Meter *>(lv_anim_get_user_data(obj));
lv_scale_t *j = (lv_scale_t*)(self->scale);
lv_obj_t *scale = static_cast<lv_obj_t *>(lv_anim_get_user_data(obj));
lv_scale_set_line_needle_value((static_cast<Meter *>(lv_anim_get_user_data(obj)))->scale, (static_cast<Meter *>(lv_anim_get_user_data(obj)))->needle_line, 60, val);
self->value = val;
}
void Meter::runAnim(int32_t val) {
printf("Prepearing animation!\n");
lv_anim_t anim_scale_line2;
lv_anim_init(&anim_scale_line2);
lv_anim_set_var(&anim_scale_line2, this->scale);
lv_anim_set_completed_cb(&anim_scale_line2, anim_ready_cb);
lv_anim_set_user_data(&anim_scale_line2, this);
lv_anim_set_custom_exec_cb(&anim_scale_line2, setValue);
lv_anim_set_duration(&anim_scale_line2, 2000);
lv_anim_set_repeat_count(&anim_scale_line2, 0);
lv_anim_set_values(&anim_scale_line2, 0, val);
lv_anim_start(&anim_scale_line2);
printf("Scale pointer is %");
}
void Meter::anim_ready_cb(lv_anim_t * a) {
printf("Animation Completed!\n");
Meter *value = static_cast<Meter *>(lv_anim_get_user_data(a));
printf("global %d\n", value->value);
}
Meter::~Meter() {};
/**********************
* GLOBAL FUNCTIONS
**********************/
int main(int argc, char **argv)
{
(void)argc; /*Unused*/
(void)argv; /*Unused*/
//lv_tick_set_cb(get_milliseconds);
/*Initialize LVGL*/
lv_init();
/*Initialize the HAL (display, input devices, tick) for LVGL*/
hal_init(1024, 768);
//lv_demo_widgets();
//create_screen_main();
//lv_example_scale_6();
lvgl_timer_init();
Meter Meter1(lv_screen_active(), "1", "1", 140, 201, 0, 120, 90, 120);
Meter1.runAnim(80);
while(1) {
/* Periodically call the lv_task handler.
* It could be done in a timer interrupt or an OS task too.*/
lv_refr_now(NULL);
usleep(5 * 1000);
lv_timer_handler();
}
return 0;
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Initialize the Hardware Abstraction Layer (HAL) for the LVGL graphics
* library
*/
static lv_display_t * hal_init(int32_t w, int32_t h)
{
lv_group_set_default(lv_group_create());
lv_display_t * disp = lv_sdl_window_create(w, h);
lv_indev_t * mouse = lv_sdl_mouse_create();
lv_indev_set_group(mouse, lv_group_get_default());
lv_indev_set_display(mouse, disp);
lv_display_set_default(disp);
lv_indev_t * mousewheel = lv_sdl_mousewheel_create();
lv_indev_set_display(mousewheel, disp);
lv_indev_set_group(mousewheel, lv_group_get_default());
lv_indev_t * kb = lv_sdl_keyboard_create();
lv_indev_set_display(kb, disp);
lv_indev_set_group(kb, lv_group_get_default());
return disp;
}