feat(rk3588s): blink AP display and package source tree
This commit is contained in:
406
lib/resource/3588s/src/main.c
Executable file
406
lib/resource/3588s/src/main.c
Executable file
@@ -0,0 +1,406 @@
|
||||
#include "lvgl/lvgl.h"
|
||||
#include "lv_drivers/display/fbdev.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <ifaddrs.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
#define DISP_BUF_SIZE (320 * 240)
|
||||
|
||||
LV_IMG_DECLARE(logo);
|
||||
|
||||
/* ===================== UI Objects ===================== */
|
||||
|
||||
static lv_obj_t *hours_label;
|
||||
static lv_obj_t *minutes_label;
|
||||
static lv_obj_t *seconds_label;
|
||||
static lv_obj_t *colon1_label;
|
||||
static lv_obj_t *colon2_label;
|
||||
|
||||
static lv_obj_t *eth_ip_label;
|
||||
static lv_obj_t *wifi_ip_label;
|
||||
static lv_obj_t *custom_text_label;
|
||||
|
||||
static volatile bool show_custom_text = false;
|
||||
static volatile bool custom_text_blink = false;
|
||||
static volatile bool custom_text_visible = true;
|
||||
static char custom_text_buf[256] = {0};
|
||||
|
||||
#define LVGL_CMD_FIFO "/tmp/lvgl_cmd"
|
||||
#define LOGO_SHOW_SECONDS 5
|
||||
|
||||
/* ===================== Dark Theme ===================== */
|
||||
|
||||
static void apply_dark_theme(void)
|
||||
{
|
||||
lv_obj_t *scr = lv_disp_get_scr_act(NULL);
|
||||
lv_obj_set_style_bg_color(scr, lv_color_black(), 0);
|
||||
lv_obj_set_style_bg_opa(scr, LV_OPA_COVER, 0);
|
||||
}
|
||||
|
||||
/* ===================== Time UI ===================== */
|
||||
|
||||
static void create_time_labels(lv_obj_t *parent)
|
||||
{
|
||||
static lv_style_t style;
|
||||
lv_style_init(&style);
|
||||
lv_style_set_text_font(&style, &lv_font_montserrat_48);
|
||||
lv_style_set_text_color(&style, lv_color_white());
|
||||
|
||||
hours_label = lv_label_create(parent);
|
||||
minutes_label = lv_label_create(parent);
|
||||
seconds_label = lv_label_create(parent);
|
||||
colon1_label = lv_label_create(parent);
|
||||
colon2_label = lv_label_create(parent);
|
||||
|
||||
lv_obj_add_style(hours_label, &style, 0);
|
||||
lv_obj_add_style(minutes_label, &style, 0);
|
||||
lv_obj_add_style(seconds_label, &style, 0);
|
||||
lv_obj_add_style(colon1_label, &style, 0);
|
||||
lv_obj_add_style(colon2_label, &style, 0);
|
||||
|
||||
lv_label_set_text(colon1_label, ":");
|
||||
lv_label_set_text(colon2_label, ":");
|
||||
|
||||
lv_obj_align(hours_label, LV_ALIGN_CENTER, -80, -25);
|
||||
lv_obj_align_to(colon1_label, hours_label, LV_ALIGN_OUT_RIGHT_MID, 6, 0);
|
||||
lv_obj_align_to(minutes_label, colon1_label, LV_ALIGN_OUT_RIGHT_MID, 6, 0);
|
||||
lv_obj_align_to(colon2_label, minutes_label, LV_ALIGN_OUT_RIGHT_MID, 6, 0);
|
||||
lv_obj_align_to(seconds_label, colon2_label, LV_ALIGN_OUT_RIGHT_MID, 6, 0);
|
||||
|
||||
|
||||
lv_obj_add_flag(hours_label, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_add_flag(minutes_label, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_add_flag(seconds_label, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_add_flag(colon1_label, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_add_flag(colon2_label, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
|
||||
static void update_time_labels(int h, int m, int s)
|
||||
{
|
||||
char buf[4];
|
||||
snprintf(buf, sizeof(buf), "%02d", h);
|
||||
lv_label_set_text(hours_label, buf);
|
||||
snprintf(buf, sizeof(buf), "%02d", m);
|
||||
lv_label_set_text(minutes_label, buf);
|
||||
snprintf(buf, sizeof(buf), "%02d", s);
|
||||
lv_label_set_text(seconds_label, buf);
|
||||
|
||||
lv_obj_align_to(colon1_label, hours_label, LV_ALIGN_OUT_RIGHT_MID, 6, 0);
|
||||
lv_obj_align_to(minutes_label, colon1_label, LV_ALIGN_OUT_RIGHT_MID, 6, 0);
|
||||
lv_obj_align_to(colon2_label, minutes_label, LV_ALIGN_OUT_RIGHT_MID, 6, 0);
|
||||
lv_obj_align_to(seconds_label, colon2_label, LV_ALIGN_OUT_RIGHT_MID,6, 0);
|
||||
}
|
||||
|
||||
static void create_custom_text_label(lv_obj_t *parent)
|
||||
{
|
||||
static lv_style_t style;
|
||||
lv_style_init(&style);
|
||||
lv_style_set_text_font(&style, &lv_font_montserrat_48);
|
||||
lv_style_set_text_color(&style, lv_color_white());
|
||||
|
||||
custom_text_label = lv_label_create(parent);
|
||||
lv_obj_add_style(custom_text_label, &style, 0);
|
||||
lv_label_set_text(custom_text_label, "");
|
||||
lv_obj_align(custom_text_label, LV_ALIGN_CENTER, 0, -25);
|
||||
lv_obj_add_flag(custom_text_label, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
|
||||
static void show_time_row(bool visible)
|
||||
{
|
||||
if(visible) {
|
||||
lv_obj_clear_flag(hours_label, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(minutes_label, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(seconds_label, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(colon1_label, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(colon2_label, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_add_flag(custom_text_label, LV_OBJ_FLAG_HIDDEN);
|
||||
} else {
|
||||
lv_obj_add_flag(hours_label, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_add_flag(minutes_label, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_add_flag(seconds_label, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_add_flag(colon1_label, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_add_flag(colon2_label, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(custom_text_label, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
}
|
||||
|
||||
static void apply_show_text_async(void *arg)
|
||||
{
|
||||
const char *text = (const char *)arg;
|
||||
show_custom_text = true;
|
||||
custom_text_blink = false;
|
||||
custom_text_visible = true;
|
||||
lv_label_set_text(custom_text_label, text ? text : "");
|
||||
lv_obj_align(custom_text_label, LV_ALIGN_CENTER, 0, -25);
|
||||
show_time_row(false);
|
||||
lv_obj_clear_flag(custom_text_label, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
|
||||
static void apply_show_ap_async(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
show_custom_text = true;
|
||||
custom_text_blink = true;
|
||||
custom_text_visible = true;
|
||||
lv_label_set_text(custom_text_label, "AP");
|
||||
lv_obj_align(custom_text_label, LV_ALIGN_CENTER, 0, -25);
|
||||
show_time_row(false);
|
||||
lv_obj_clear_flag(custom_text_label, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
|
||||
static void apply_show_time_async(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
show_custom_text = false;
|
||||
custom_text_blink = false;
|
||||
custom_text_visible = true;
|
||||
show_time_row(true);
|
||||
}
|
||||
|
||||
static void *fifo_thread(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
unlink(LVGL_CMD_FIFO);
|
||||
if (mkfifo(LVGL_CMD_FIFO, 0666) < 0 && errno != EEXIST) {
|
||||
perror("mkfifo lvgl_cmd");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
int fd = open(LVGL_CMD_FIFO, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
usleep(200000);
|
||||
continue;
|
||||
}
|
||||
|
||||
FILE *fp = fdopen(fd, "r");
|
||||
if (!fp) {
|
||||
close(fd);
|
||||
usleep(200000);
|
||||
continue;
|
||||
}
|
||||
|
||||
char line[256];
|
||||
while (fgets(line, sizeof(line), fp)) {
|
||||
size_t len = strlen(line);
|
||||
while (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r')) {
|
||||
line[--len] = '\0';
|
||||
}
|
||||
|
||||
if (strncmp(line, "show_text:", 10) == 0) {
|
||||
strncpy(custom_text_buf, line + 10, sizeof(custom_text_buf) - 1);
|
||||
custom_text_buf[sizeof(custom_text_buf) - 1] = '\0';
|
||||
if (strcmp(custom_text_buf, "AP") == 0) {
|
||||
lv_async_call(apply_show_ap_async, NULL);
|
||||
} else {
|
||||
lv_async_call(apply_show_text_async, custom_text_buf);
|
||||
}
|
||||
} else if (strcmp(line, "show_time") == 0) {
|
||||
lv_async_call(apply_show_time_async, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ===================== IP UI ===================== */
|
||||
|
||||
static void create_ip_labels(lv_obj_t *parent)
|
||||
{
|
||||
static lv_style_t style;
|
||||
lv_style_init(&style);
|
||||
lv_style_set_text_font(&style, &lv_font_montserrat_20);
|
||||
lv_style_set_text_color(&style, lv_color_white());
|
||||
|
||||
eth_ip_label = lv_label_create(parent);
|
||||
wifi_ip_label = lv_label_create(parent);
|
||||
|
||||
lv_obj_add_style(eth_ip_label, &style, 0);
|
||||
lv_obj_add_style(wifi_ip_label, &style, 0);
|
||||
|
||||
lv_label_set_text(eth_ip_label, "ETH : --");
|
||||
lv_label_set_text(wifi_ip_label, "WiFi: --");
|
||||
|
||||
lv_obj_align(eth_ip_label, LV_ALIGN_CENTER, 0, 35);
|
||||
lv_obj_align(wifi_ip_label, LV_ALIGN_CENTER, 0, 60);
|
||||
|
||||
lv_obj_add_flag(eth_ip_label, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_add_flag(wifi_ip_label, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
|
||||
/* ===================== IP Logic ===================== */
|
||||
|
||||
static void get_ip(const char *ifname, char *out, size_t len)
|
||||
{
|
||||
struct ifaddrs *ifaddr, *ifa;
|
||||
out[0] = 0;
|
||||
|
||||
if (getifaddrs(&ifaddr))
|
||||
return;
|
||||
|
||||
for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
|
||||
if (!ifa->ifa_addr)
|
||||
continue;
|
||||
if (ifa->ifa_addr->sa_family == AF_INET &&
|
||||
strcmp(ifa->ifa_name, ifname) == 0) {
|
||||
|
||||
inet_ntop(AF_INET,
|
||||
&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr,
|
||||
out, len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
freeifaddrs(ifaddr);
|
||||
}
|
||||
|
||||
static void update_ip_ui(void)
|
||||
{
|
||||
char eth[32] = {0}, wifi[32] = {0};
|
||||
get_ip("enP4p65s0", eth, sizeof(eth));
|
||||
get_ip("wlan0", wifi, sizeof(wifi));
|
||||
|
||||
if (eth[0]) {
|
||||
lv_label_set_text_fmt(eth_ip_label, "ETH : %s", eth);
|
||||
} else {
|
||||
lv_label_set_text(eth_ip_label, "ETH : Not Connected");
|
||||
}
|
||||
|
||||
if (wifi[0]) {
|
||||
lv_label_set_text_fmt(wifi_ip_label, "WiFi: %s", wifi);
|
||||
} else {
|
||||
lv_label_set_text(wifi_ip_label, "WiFi: Not Connected");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ===================== Netlink Thread ===================== */
|
||||
|
||||
static void *netlink_thread(void *arg)
|
||||
{
|
||||
int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
|
||||
struct sockaddr_nl addr = {
|
||||
.nl_family = AF_NETLINK,
|
||||
.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR,
|
||||
};
|
||||
|
||||
bind(sock, (struct sockaddr *)&addr, sizeof(addr));
|
||||
|
||||
char buf[4096];
|
||||
while (1) {
|
||||
recv(sock, buf, sizeof(buf), 0);
|
||||
lv_async_call((lv_async_cb_t)update_ip_ui, NULL);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ===================== LVGL Tick ===================== */
|
||||
|
||||
uint32_t custom_tick_get(void)
|
||||
{
|
||||
static uint64_t start = 0;
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
uint64_t now = tv.tv_sec * 1000ULL + tv.tv_usec / 1000;
|
||||
if (!start)
|
||||
start = now;
|
||||
return now - start;
|
||||
}
|
||||
|
||||
/* ===================== Main ===================== */
|
||||
|
||||
int main(void)
|
||||
{
|
||||
lv_init();
|
||||
fbdev_init();
|
||||
|
||||
static lv_color_t buf[DISP_BUF_SIZE];
|
||||
static lv_disp_draw_buf_t draw_buf;
|
||||
lv_disp_draw_buf_init(&draw_buf, buf, NULL, DISP_BUF_SIZE);
|
||||
|
||||
static lv_disp_drv_t disp_drv;
|
||||
lv_disp_drv_init(&disp_drv);
|
||||
disp_drv.draw_buf = &draw_buf;
|
||||
disp_drv.flush_cb = fbdev_flush;
|
||||
disp_drv.hor_res = 320;
|
||||
disp_drv.ver_res = 240;
|
||||
lv_disp_drv_register(&disp_drv);
|
||||
|
||||
apply_dark_theme();
|
||||
|
||||
lv_obj_t *scr = lv_disp_get_scr_act(NULL);
|
||||
|
||||
lv_obj_t *img = lv_img_create(scr);
|
||||
lv_img_set_src(img, &logo);
|
||||
lv_obj_center(img);
|
||||
|
||||
create_time_labels(scr);
|
||||
create_custom_text_label(scr);
|
||||
create_ip_labels(scr);
|
||||
|
||||
pthread_t tid;
|
||||
pthread_create(&tid, NULL, netlink_thread, NULL);
|
||||
pthread_detach(tid);
|
||||
|
||||
pthread_t fifo_tid;
|
||||
pthread_create(&fifo_tid, NULL, fifo_thread, NULL);
|
||||
pthread_detach(fifo_tid);
|
||||
|
||||
time_t start = time(NULL);
|
||||
int last_sec = -1;
|
||||
bool shown = false;
|
||||
|
||||
while (1) {
|
||||
time_t now = time(NULL);
|
||||
|
||||
if (!shown && now - start >= LOGO_SHOW_SECONDS) {
|
||||
lv_obj_add_flag(img, LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
show_time_row(true);
|
||||
|
||||
lv_obj_clear_flag(eth_ip_label, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(wifi_ip_label, LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
update_ip_ui();
|
||||
shown = true;
|
||||
}
|
||||
|
||||
struct tm *tm = localtime(&now);
|
||||
if (!show_custom_text && tm->tm_sec != last_sec) {
|
||||
update_time_labels(tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||
last_sec = tm->tm_sec;
|
||||
}
|
||||
|
||||
static uint32_t last_blink_ms = 0;
|
||||
uint32_t now_ms = lv_tick_get();
|
||||
if (custom_text_blink && now_ms - last_blink_ms >= 500) {
|
||||
last_blink_ms = now_ms;
|
||||
custom_text_visible = !custom_text_visible;
|
||||
if (custom_text_visible) {
|
||||
lv_obj_clear_flag(custom_text_label, LV_OBJ_FLAG_HIDDEN);
|
||||
} else {
|
||||
lv_obj_add_flag(custom_text_label, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
}
|
||||
|
||||
lv_timer_handler();
|
||||
usleep(10000);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user