Hi,
I’ve made some progress. I followed the instructions in LVGL academy to create an external button that is clicked virtually by the windows random function.
I copied the same code into the PC simulator that I’m running on my RPi 3B+ and it compiled without issues. I modified the code to initiate the WiringPi library and instead of using the random generate number to click the button, I’m reading the state of the physical button.
The code compiles without issues but the button doesn’t get clicked when I press the physical button.
Below is my complete code - I’ve put all the code\functions in the main.c file for testing.
/**
* @file main
*
*/
/*********************
* INCLUDES
*********************/
#define _DEFAULT_SOURCE /* needed for usleep() */
#include <stdlib.h>
#include <unistd.h>
#define SDL_MAIN_HANDLED /*To fix SDL's "undefined reference to WinMain" issue*/
#include <SDL2/SDL.h>
#include "lvgl/lvgl.h"
#include "lvgl/examples/lv_examples.h"
#include "lv_demos/lv_demo.h"
#include "lv_drivers/display/monitor.h"
#include "lv_drivers/display/fbdev.h"
#include "lv_drivers/indev/mouse.h"
#include "lv_drivers/indev/keyboard.h"
#include "lv_drivers/indev/mousewheel.h"
#include <wiringPi.h>//to control raspberry pi GPIO
static void hal_init(void);
static int tick_thread(void *data);
static lv_obj_t * scr1;
static void btn_event_cb(lv_event_t* e);
static lv_led_t* _led;
static lv_btn_t* btn;
int flag;
static void lv_gpio_init(void);
static bool button_read(struct _lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
void external_button_on_screen()
{
lv_gpio_init();//call the GPIO initializing function
//Creating the input device driver and all necessary declarations and functions
static lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_BUTTON;
indev_drv.read_cb = button_read;
lv_indev_t* my_indev = lv_indev_drv_register(&indev_drv);
//connecting the actual physical button press to a specific place on the screen
const lv_point_t points[] = {{400,220}};
lv_indev_set_button_points(my_indev, points);
//dot to check the coordinates of the button on screen only to be used in the above points array
/*
lv_obj_t* dot = lv_obj_create(lv_scr_act());
lv_obj_set_size(dot, 10, 10);
lv_obj_set_pos(dot, 400,220);
*/
//Creating a button on the screen for testing
btn = lv_btn_create(lv_scr_act());
lv_label_t* label = lv_label_create(btn);
lv_label_set_text(label, "click me!");
lv_obj_align(btn, LV_ALIGN_CENTER, 0, 0);
lv_obj_add_event_cb(btn, btn_event_cb, LV_EVENT_ALL, NULL);
//creating an LED on the screen for testing
_led = lv_led_create(lv_scr_act());
lv_obj_align(_led, LV_ALIGN_CENTER, 0, -50);
}
/*------------------------------------------------------*/
/*------------------------------------------------------*/
static void lv_gpio_init(void)
{
wiringPiSetup () ;
pinMode (0, OUTPUT) ;
pinMode (1, INPUT) ;
}
/*------------------------------------------------------*/
/*------------------------------------------------------*/
static bool button_read(struct _lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
//reading GPIO
if(digitalRead(1) == 1)
{
data->state = LV_INDEV_STATE_PR;//Either this
digitalWrite(0, 1);//This will toggle the physical LED ON - works fine
//lv_led_on(_led);//this will toggle the on-screen LED ON - works fine
}
else if(digitalRead(1) == 0)
{
data->state = LV_INDEV_STATE_REL;//OR this
digitalWrite(0, 0);//This will toggle the physical LED OFF - works fine
//lv_led_off(_led);//this will toggle the on-screen LED OFF - works fine
}
return false;
}
/*------------------------------------------------------*/
/*------------------------------------------------------*/
static void btn_event_cb(lv_event_t* e)
{
lv_event_code_t code = lv_event_get_code(e);
if(code == LV_EVENT_PRESSED && flag == 0)
{
lv_led_on(_led);//turn the on-screen LED ON
flag = 1;
}
else if (code == LV_EVENT_RELEASED && flag == 1)
{
lv_led_off(_led);//Turn the on-screen LED OFF
flag = 0;
}
}
/*------------------------------------------------------*/
/*------------------------------------------------------*/
/**********************
* GLOBAL FUNCTIONS
**********************/
int main(int argc, char **argv)
{
(void)argc; /*Unused*/
(void)argv; /*Unused*/
/*Initialize LVGL*/
lv_init();
/*Initialize the HAL (display, input devices, tick) for LVGL*/
hal_init();
// lv_example_switch_1();
// lv_example_calendar_1();
// lv_example_btnmatrix_2();
// lv_example_checkbox_1();
// lv_example_colorwheel_1();
// lv_example_chart_6();
// lv_example_table_2();
// lv_example_scroll_2();
// lv_example_textarea_1();
// lv_example_msgbox_1();
// lv_example_dropdown_2();
// lv_example_btn_1();
// lv_example_scroll_1();
// lv_example_tabview_1();
// lv_example_tabview_1();
// lv_example_flex_3();
// lv_example_label_1();
//lv_demo_widgets();
external_button_on_screen();
//base_obj();
while(1) {
/* Periodically call the lv_task handler.
* It could be done in a timer interrupt or an OS task too.*/
lv_timer_handler();
usleep(5 * 1000);
}
return 0;
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Initialize the Hardware Abstraction Layer (HAL) for the LVGL graphics
* library
*/
static void hal_init(void)
{
/* Use the 'monitor' driver which creates window on PC's monitor to simulate a display*/
monitor_init();
/* Tick init.
* You have to call 'lv_tick_inc()' in periodically to inform LittelvGL about
* how much time were elapsed Create an SDL thread to do this*/
SDL_CreateThread(tick_thread, "tick", NULL);
/*Create a display buffer*/
static lv_disp_draw_buf_t disp_buf1;
static lv_color_t buf1_1[MONITOR_HOR_RES * 100];
static lv_color_t buf1_2[MONITOR_HOR_RES * 100];
lv_disp_draw_buf_init(&disp_buf1, buf1_1, buf1_2, MONITOR_HOR_RES * 100);
/*Create a display*/
static lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv); /*Basic initialization*/
disp_drv.draw_buf = &disp_buf1;
disp_drv.flush_cb = monitor_flush;
disp_drv.hor_res = MONITOR_HOR_RES;
disp_drv.ver_res = MONITOR_VER_RES;
disp_drv.antialiasing = 1;
lv_disp_t * disp = lv_disp_drv_register(&disp_drv);
lv_theme_t * th = lv_theme_default_init(disp, lv_palette_main(LV_PALETTE_BLUE), lv_palette_main(LV_PALETTE_RED), LV_THEME_DEFAULT_DARK, LV_FONT_DEFAULT);
lv_disp_set_theme(disp, th);
lv_group_t * g = lv_group_create();
lv_group_set_default(g);
/* Add the mouse as input device
* Use the 'mouse' driver which reads the PC's mouse*/
mouse_init();
static lv_indev_drv_t indev_drv_1;
lv_indev_drv_init(&indev_drv_1); /*Basic initialization*/
indev_drv_1.type = LV_INDEV_TYPE_POINTER;
/*This function will be called periodically (by the library) to get the mouse position and state*/
indev_drv_1.read_cb = mouse_read;
lv_indev_t *mouse_indev = lv_indev_drv_register(&indev_drv_1);
keyboard_init();
static lv_indev_drv_t indev_drv_2;
lv_indev_drv_init(&indev_drv_2); /*Basic initialization*/
indev_drv_2.type = LV_INDEV_TYPE_KEYPAD;
indev_drv_2.read_cb = keyboard_read;
lv_indev_t *kb_indev = lv_indev_drv_register(&indev_drv_2);
lv_indev_set_group(kb_indev, g);
mousewheel_init();
static lv_indev_drv_t indev_drv_3;
lv_indev_drv_init(&indev_drv_3); /*Basic initialization*/
indev_drv_3.type = LV_INDEV_TYPE_ENCODER;
indev_drv_3.read_cb = mousewheel_read;
lv_indev_t * enc_indev = lv_indev_drv_register(&indev_drv_3);
lv_indev_set_group(enc_indev, g);
/*Set a cursor for the mouse*/
LV_IMG_DECLARE(mouse_cursor_icon); /*Declare the image file.*/
lv_obj_t * cursor_obj = lv_img_create(lv_scr_act()); /*Create an image object for the cursor */
lv_img_set_src(cursor_obj, &mouse_cursor_icon); /*Set the image source*/
lv_indev_set_cursor(mouse_indev, cursor_obj); /*Connect the image object to the driver*/
}
/**
* A task to measure the elapsed time for LVGL
* @param data unused
* @return never return
*/
static int tick_thread(void *data) {
(void)data;
while(1) {
SDL_Delay(5);
lv_tick_inc(5); /*Tell LittelvGL that 5 milliseconds were elapsed*/
}
return 0;
}