diff --git a/bsp/stm32_radio/filelist.c b/bsp/stm32_radio/filelist.c new file mode 100644 index 000000000..4e39fe48a --- /dev/null +++ b/bsp/stm32_radio/filelist.c @@ -0,0 +1,185 @@ +#include +#include + +#include +#include + +/* image for file and folder */ +rtgui_image_t *file_image, *folder_image; + +static void _filelist_view_constructor(filelist_view *view) +{ + /* default rect */ + struct rtgui_rect rect = {0, 0, 200, 200}; + + /* set default widget rect and set event handler */ + rtgui_widget_set_event_handler(RTGUI_WIDGET(view),filelist_view_event_handler); + rtgui_widget_set_rect(RTGUI_WIDGET(view), &rect); + + RTGUI_WIDGET_BACKGROUND(RTGUI_WIDGET(list)) = RTGUI_RGB(212, 208, 200); + + view->count = 0; + view->current_directory = RT_NULL; + view->pattern = RT_NULL; + rtgui_list_init(&view->list); +} + +rtgui_type_t *filelist_view_type_get(void) +{ + static rtgui_type_t *filelist_view_type = RT_NULL; + + if (!filelist_view_type) + { + filelist_view_type = rtgui_type_create("flview", RTGUI_VIEW_TYPE, + sizeof(filelist_view_t), RTGUI_CONSTRUCTOR(_filelist_view_constructor), RT_NULL); + } + + return filelist_view_type; +} + +rt_bool_t filelist_view_event_handler(struct rtgui_widget* widget, struct rtgui_event* event) +{ + struct filelist_view* view = RT_NULL; + + view = FILELIST_VIEW(widget); + switch (event.type) + { + case RTGUI_EVENT_PAINT: + break; + + case RTGUI_EVENT_RESIZE: + { + /* recalculate page items */ + } + break; + + case RTGUI_EVENT_KBD: + { + struct rtgui_event_kbd* ekbd = (struct rtgui_event_kbd*)event; + if (ekbd->type == RTGUI_KEYDOWN) + { + switch (ekbd->key) + { + case RTGUIK_UP: + break; + + case RTGUIK_DOWN: + break; + + default: + break; + } + } + } + break; + } + + /* use view event handler */ + return rtgui_view_event_handler(widget, event); +} + +filelist_view_t* filelist_view_create(const char* directory, const char* pattern) +{ + struct filelist_view* view = RT_NULL; + + view = (struct filelist_view*) rtgui_widget_create(FILELIST_VIEW_TYPE); + if (view != RT_NULL) + { + view->pattern = rt_strdup(pattern); + filelist_view_set_directory(view, directory); + } + + return list; +} + +void filelist_view_destroy(filelist_view_t* view) +{ + /* delete all file items */ + filelist_view_clear(view); + + /* destroy view */ + rtgui_widget_destroy(RTGUI_WIDGET(view)); +} + +/* clear all file items */ +void filelist_view_clear(filelist_view_t* view) +{ + struct rtgui_list_node* node; + struct file_item* item; + + while (view->list.next != RT_NULL) + { + node = view->list.next; + rtgui_list_remove(&view->list, node); + + item = rtgui_list_entry(node, struct file_item, list); + rtgui_free(item->name); + rtgui_free(item); + } +} + +void filelist_view_set_directory(filelist_view_t* view, const char* directory) +{ + rt_uint8_t fullpath[256]; + struct file_item *item; + + RT_ASSERT(view != RT_NULL); + + /* clear file items firstly */ + filelist_view_clear(view); + if (directory != RT_NULL) + { + DIR* dir; + dir = opendir(directory); + if (dir != RT_NULL) + { + struct dfs_dirent* dirent; + struct dfs_stat s; + + do + { + dirent = readdir(dir); + if (dirent == RT_NULL) break; + if (fnmatch(dirent->d_name, view->pattern, FNM_FILE_NAME) != 0) continue; + + item = (struct file_item*) rt_malloc (sizeof(struct file_item)); + if (item == RT_NULL) break; + + rt_memset(&s, 0, sizeof(struct dfs_stat)); + + /* build full path for the file */ + rt_sprintf(fullpath, "%s/%s", directory, dirent->d_name); + + item->name = strdup(direct->d_name); + rtgui_list_init(&item->list); + stat(fullpath, &s); + if ( s.st_mode & DFS_S_IFDIR ) + { + item->type = FITEM_DIR; + item->size = 0; + } + else + { + item->type = FITEM_FILE; + item->size = s.st_size; + } + + rtgui_list_append(&view->list, &item->list); + view->count ++; + } while (dirent != RT_NULL); + + closedir(dir); + } + } + + if (view->count > 0) + { + /* select first one */ + view->selected = rtgui_list_entry(view->list.next, + struct file_item, list); + } + else view->selected = RT_NULL; + + /* update view */ + rtgui_widget_update(RTGUI_WIDGET(view)); +} diff --git a/bsp/stm32_radio/filelist.h b/bsp/stm32_radio/filelist.h new file mode 100644 index 000000000..098657edb --- /dev/null +++ b/bsp/stm32_radio/filelist.h @@ -0,0 +1,48 @@ +#ifndef __FILE_LIST_VIEW_H__ +#define __FILE_LIST_VIEW_H__ + +#define FITEM_FILE 0x0 +#define FITEM_DIR 0x1 +struct file_item +{ + char* name; + + rt_uint32_t type; + rt_uint32_t size; + + /* files under same directory */ + rtgui_list_t list; +}; + +/** Gets the type of a filelist view */ +#define FILELIST_VIEW_TYPE (filelist_view_type_get()) +/** Casts the object to a filelist */ +#define FILELIST_VIEW(obj) (RTGUI_OBJECT_CAST((obj), FILELIST_VIEW_TYPE, filelist_view_t)) +/** Checks if the object is a filelist view */ +#define IS_FILELIST_VIEW(obj) (RTGUI_OBJECT_CHECK_TYPE((obj), FILELIST_VIEW_TYPE)) + +struct filelist_view +{ + struct rtgui_view parent; + + /* widget private data */ + + /* total number of items */ + rt_uint32_t count; + + /* the selected item */ + struct file_item* selected; + + /* current directory */ + rt_uint8_t* current_directory; + rt_uint8_t* pattern; + + /* the number of item in a page */ + rt_uint16_t page_items; + + /* item_list */ + rtgui_list_t item_list; +}; +typedef struct filelist_view filelist_view_t; + +#endif \ No newline at end of file diff --git a/bsp/stm32_radio/fnmatch.c b/bsp/stm32_radio/fnmatch.c new file mode 100644 index 000000000..0eeaa0206 --- /dev/null +++ b/bsp/stm32_radio/fnmatch.c @@ -0,0 +1,139 @@ +#include +#include +#include + +#define NOTFIRST 128 + +#define STRUCT_CHARCLASS(c) { #c , is##c } + +static struct charclass { + char * class; + int (*istype)(int); +} allclasses[] = { + STRUCT_CHARCLASS(alnum), + STRUCT_CHARCLASS(alpha), + STRUCT_CHARCLASS(blank), + STRUCT_CHARCLASS(cntrl), + STRUCT_CHARCLASS(digit), + STRUCT_CHARCLASS(graph), + STRUCT_CHARCLASS(lower), + STRUCT_CHARCLASS(print), + STRUCT_CHARCLASS(punct), + STRUCT_CHARCLASS(space), + STRUCT_CHARCLASS(upper), + STRUCT_CHARCLASS(xdigit), +}; + +/* look for "class:]" in pattern */ +static struct charclass *charclass_lookup(const char *pattern) { + unsigned int i; + + for (i = 0; i< sizeof(allclasses)/sizeof(*allclasses); i++) { + int len = strlen(allclasses[i].class); + if (!strncmp(pattern, allclasses[i].class, len)) { + pattern += len; + if (strncmp(pattern, ":]", 2)) goto noclass; + return &allclasses[i]; + } + } +noclass: + return NULL; +} + +static int match(char c,char d,int flags) { + if (flags&FNM_CASEFOLD) + return (tolower(c)==tolower(d)); + else + return (c==d); +} + +int fnmatch(const char *pattern, const char *string, int flags) { + if (*string==0) { + while (*pattern=='*') ++pattern; + return (!!*pattern); + } + if (*string=='.' && *pattern!='.' && (flags&FNM_PERIOD)) { + /* don't match if FNM_PERIOD and this is the first char */ + if (!(flags&NOTFIRST)) + return FNM_NOMATCH; + /* don't match if FNM_PERIOD and FNM_PATHNAME and previous was '/' */ + if ((flags&(FNM_PATHNAME)) && string[-1]=='/') + return FNM_NOMATCH; + } + flags|=NOTFIRST; + switch (*pattern) { + case '[': + { + int neg=0; + const char* start; /* first member of character class */ + + ++pattern; + if (*string=='/' && flags&FNM_PATHNAME) return FNM_NOMATCH; + if (*pattern=='!') { neg=1; ++pattern; } + start=pattern; + while (*pattern) { + int res=0; + + if (*pattern==']' && pattern!=start) break; + if (*pattern=='[' && pattern[1]==':') { + /* MEMBER - stupid POSIX char classes */ + const struct charclass *cc; + + if (!(cc = charclass_lookup(pattern+2))) goto invalidclass; + pattern += strlen(cc->class) + 4; + if (flags&FNM_CASEFOLD + && (cc->istype == isupper || cc->istype == islower)) { + res = islower(tolower(*string)); + } else { + res = ((*(cc->istype))(*string)); + } + } else { +invalidclass: + if (pattern[1]=='-' && pattern[2]!=']') { + /* MEMBER - character range */ + if (*string>=*pattern && *string<=pattern[2]) res=1; + if (flags&FNM_CASEFOLD) { + if (tolower(*string)>=tolower(*pattern) && tolower(*string)<=tolower(pattern[2])) res=1; + } + pattern+=3; + } else { + /* MEMBER - literal character match */ + res=match(*pattern,*string,flags); + ++pattern; + } + } + if ((res&&!neg) || ((neg&&!res) && *pattern==']')) { + while (*pattern && *pattern!=']') ++pattern; + return fnmatch(pattern+!!*pattern,string+1,flags); + } else if (res && neg) + return FNM_NOMATCH; + } + } + break; + case '\\': + if (flags&FNM_NOESCAPE) { + if (*string=='\\') + return fnmatch(pattern+1,string+1,flags); + } else { + if (*string==pattern[1]) + return fnmatch(pattern+2,string+1,flags); + } + break; + case '*': + if ((*string=='/' && flags&FNM_PATHNAME) || fnmatch(pattern,string+1,flags)) + return fnmatch(pattern+1,string,flags); + return 0; + case 0: + if (*string==0 || (*string=='/' && (flags&FNM_LEADING_DIR))) + return 0; + break; + case '?': + if (*string=='/' && flags&FNM_PATHNAME) break; + return fnmatch(pattern+1,string+1,flags); + default: + if (match(*pattern,*string,flags)) + return fnmatch(pattern+1,string+1,flags); + break; + } + return FNM_NOMATCH; +} diff --git a/bsp/stm32_radio/fnmatch.h b/bsp/stm32_radio/fnmatch.h new file mode 100644 index 000000000..a3336cad5 --- /dev/null +++ b/bsp/stm32_radio/fnmatch.h @@ -0,0 +1,21 @@ +#ifndef _FNMATCH_H +#define _FNMATCH_H + +#include + +__BEGIN_DECLS + +int fnmatch(const char *pattern, const char *string, int flags) __THROW; + +#define FNM_NOESCAPE 1 +#define FNM_PATHNAME 2 +#define FNM_FILE_NAME 2 +#define FNM_PERIOD 4 +#define FNM_LEADING_DIR 8 +#define FNM_CASEFOLD 16 + +#define FNM_NOMATCH 1 + +__END_DECLS + +#endif diff --git a/bsp/stm32_radio/info.c b/bsp/stm32_radio/info.c new file mode 100644 index 000000000..77ef4416b --- /dev/null +++ b/bsp/stm32_radio/info.c @@ -0,0 +1,77 @@ +#include +#include +#include + +#include +#include + +#include "network.xpm" + +static rtgui_image_t *network_image = RT_NULL; +static rtgui_image_t *usb_image = RT_NULL; +static rtgui_image_t *power_image = RT_NULL; + +static rt_bool_t view_event_handler(struct rtgui_widget* widget, struct rtgui_event* event) +{ + if (event->type == RTGUI_EVENT_PAINT) + { + struct rtgui_dc* dc; + struct rtgui_rect rect; + + dc = rtgui_dc_begin_drawing(widget); + if (dc == RT_NULL) return RT_FALSE; + rtgui_widget_get_rect(widget, &rect); + + rtgui_dc_fill_rect(dc, &rect); + + if (network_image != RT_NULL) + { + rect.x1 = rect.x2 - (network_image->w + 2); + rtgui_image_blit(network_image, dc, &rect); + } + + rtgui_dc_end_drawing(dc); + + return RT_FALSE; + } + + return rtgui_view_event_handler(widget, event); +} + +static void info_entry(void* parameter) +{ + rt_mq_t mq; + struct rtgui_view* view; + struct rtgui_workbench* workbench; + + mq = rt_mq_create("qInfo", 256, 4, RT_IPC_FLAG_FIFO); + rtgui_thread_register(rt_thread_self(), mq); + + network_image = rtgui_image_create_from_mem("xpm", + network_xpm, sizeof(network_xpm)); + workbench = rtgui_workbench_create("info", "workbench"); + if (workbench == RT_NULL) return; + + view = rtgui_view_create("view"); + rtgui_widget_set_event_handler(RTGUI_WIDGET(view), view_event_handler); + + rtgui_workbench_add_view(workbench, view); + + rtgui_view_show(view); + + rtgui_workbench_event_loop(workbench); + + rtgui_thread_deregister(rt_thread_self()); + rt_mq_delete(mq); +} + +void info_init() +{ + rt_thread_t tid; + + tid = rt_thread_create("info", + info_entry, RT_NULL, + 2048, 25, 10); + + if (tid != RT_NULL) rt_thread_startup(tid); +} diff --git a/bsp/stm32_radio/key.c b/bsp/stm32_radio/key.c new file mode 100644 index 000000000..4c769d41e --- /dev/null +++ b/bsp/stm32_radio/key.c @@ -0,0 +1,103 @@ +#include +#include + +#include +#include + +/* +key_enter PA0 +key_down PA1 +key_up PA2 +key_right PC2 +key_left PC3 +*/ +#define key_enter_GETVALUE() GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) +#define key_down_GETVALUE() GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1) +#define key_up_GETVALUE() GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_2) +#define key_right_GETVALUE() GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_2) +#define key_left_GETVALUE() GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_3) + +static void key_thread_entry(void *parameter) +{ + rt_time_t next_delay; + struct rtgui_event_kbd kbd_event; + GPIO_InitTypeDef GPIO_InitStructure; + + /* init gpio configuration */ + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC,ENABLE); + + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2; + GPIO_Init(GPIOA,&GPIO_InitStructure); + + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3; + GPIO_Init(GPIOC,&GPIO_InitStructure); + + /* init keyboard event */ + RTGUI_EVENT_KBD_INIT(&kbd_event); + kbd_event.mod = RTGUI_KMOD_NONE; + kbd_event.unicode = 0; + + while (1) + { + next_delay = 20; + kbd_event.type = RTGUI_KEYDOWN; + if ( key_enter_GETVALUE() == 0 ) + { + rt_thread_delay(next_delay); + if (key_enter_GETVALUE() == 0) + { + /* HOME key */ + rt_kprintf("key_home\n"); + kbd_event.key = RTGUIK_HOME; + } + else + { + rt_kprintf("key_enter\n"); + kbd_event.key = RTGUIK_RETURN; + } + } + if ( key_down_GETVALUE() == 0 ) + { + rt_kprintf("key_down\n"); + kbd_event.key = RTGUIK_DOWN; + } + + if ( key_up_GETVALUE() == 0 ) + { + rt_kprintf("key_up\n"); + kbd_event.key = RTGUIK_UP; + } + + if ( key_right_GETVALUE() == 0 ) + { + rt_kprintf("key_right\n"); + kbd_event.key = RTGUIK_RIGHT; + } + + if ( key_left_GETVALUE() == 0 ) + { + rt_kprintf("key_left\n"); + kbd_event.key = RTGUIK_LEFT; + } + /* post down event */ + rtgui_server_post_event(&(kbd_event.parent), sizeof(kbd_event)); + + /* wait next key press */ + rt_thread_delay(next_delay); + + /* post up event */ + kbd_event.type = RTGUI_KEYUP; + rtgui_server_post_event(&(kbd_event.parent), sizeof(kbd_event)); + } +} + +void rt_hw_key_init() +{ + rt_thread_t key_tid; + key_tid = rt_thread_create("key", + key_thread_entry, RT_NULL, + 512, 30, 5); + if (key_tid != RT_NULL) rt_thread_startup(key_tid); +} diff --git a/bsp/stm32_radio/today.c b/bsp/stm32_radio/today.c new file mode 100644 index 000000000..2bc0df2fc --- /dev/null +++ b/bsp/stm32_radio/today.c @@ -0,0 +1,73 @@ +#include +#include +#include + +#include +#include + +static rtgui_image_t *background = RT_NULL; +static rt_bool_t view_event_handler(struct rtgui_widget* widget, struct rtgui_event* event) +{ + if (event->type == RTGUI_EVENT_PAINT) + { + struct rtgui_dc* dc; + struct rtgui_rect rect; + + dc = rtgui_dc_begin_drawing(widget); + if (dc == RT_NULL) return RT_FALSE; + rtgui_widget_get_rect(widget, &rect); + + rtgui_dc_fill_rect(dc, &rect); + + if (background != RT_NULL) + rtgui_image_blit(background, dc, &rect); + + rtgui_dc_draw_text(dc, "Radio Today", &rect); + + rtgui_dc_end_drawing(dc); + + return RT_FALSE; + } + + return rtgui_view_event_handler(widget, event); +} + +static void today_entry(void* parameter) +{ + rt_mq_t mq; + struct rtgui_view* view; + struct rtgui_workbench* workbench; + + mq = rt_mq_create("qToday", 256, 4, RT_IPC_FLAG_FIFO); + rtgui_thread_register(rt_thread_self(), mq); + + /* create background image */ + background = rtgui_image_create_from_file("png", + "/bg.png", RT_FALSE); + + workbench = rtgui_workbench_create("main", "workbench"); + if (workbench == RT_NULL) return; + + view = rtgui_view_create("Today"); + rtgui_widget_set_event_handler(RTGUI_WIDGET(view), view_event_handler); + + rtgui_workbench_add_view(workbench, view); + + rtgui_view_show(view); + + rtgui_workbench_event_loop(workbench); + + rtgui_thread_deregister(rt_thread_self()); + rt_mq_delete(mq); +} + +void today_init() +{ + rt_thread_t tid; + + tid = rt_thread_create("today", + today_entry, RT_NULL, + 2048, 25, 10); + + if (tid != RT_NULL) rt_thread_startup(tid); +} diff --git a/bsp/stm32_radio/workbench.c b/bsp/stm32_radio/workbench.c new file mode 100644 index 000000000..92474cf15 --- /dev/null +++ b/bsp/stm32_radio/workbench.c @@ -0,0 +1,95 @@ +#include +#include + +#include +#include + +static rt_bool_t view_event_handler(struct rtgui_widget* widget, struct rtgui_event* event) +{ + /* 我们目前只对绘制事件感兴趣 */ + if (event->type == RTGUI_EVENT_PAINT) + { + struct rtgui_dc* dc; + struct rtgui_rect rect; + + /* 获得一个设备上下文 */ + dc = rtgui_dc_begin_drawing(widget); + if (dc == RT_NULL) return RT_FALSE; /* 如果获取失败代表什么?这个控件是隐藏的或... */ + rtgui_widget_get_rect(widget, &rect); /* 获得控件的可视区域 */ + + /* 先对所在可视区域全部填充为背景色 */ + rtgui_dc_fill_rect(dc, &rect); + + /* 绘制一个hello! */ + rtgui_dc_draw_text(dc, "hello world", &rect); + + /* 通知RTGUI,绘制结束 */ + rtgui_dc_end_drawing(dc); + + return RT_FALSE; + } + + /* 如果不是绘制事件,使用view原来的事件处理函数处理 */ + return rtgui_view_event_handler(widget, event); +} + +static void workbench_entry(void* parameter) +{ + rt_mq_t mq; + struct rtgui_view* view; + struct rtgui_workbench* workbench; + + /* 创建GUI应用需要的消息队列 */ + mq = rt_mq_create("qWB", 256, 4, RT_IPC_FLAG_FIFO); + /* 注册当前线程为GUI线程 */ + rtgui_thread_register(rt_thread_self(), mq); + + /* 创建一个工作台 */ + workbench = rtgui_workbench_create("main", "workbench"); + if (workbench == RT_NULL) return; + + /* 创建一个工作台上的一个视图 */ + view = rtgui_view_create("view"); + rtgui_widget_set_event_handler(RTGUI_WIDGET(view), view_event_handler); + + /* 在工作台上添加一个视图 */ + rtgui_workbench_add_view(workbench, view); + + /* 显示这个视图 */ + rtgui_view_show(view); + + /* 执行工作台事件循环 */ + rtgui_workbench_event_loop(workbench); + + /* 去注册GUI线程 */ + rtgui_thread_deregister(rt_thread_self()); + rt_mq_delete(mq); +} + +void workbench_init() +{ + static rt_bool_t inited = RT_FALSE; + + if (inited == RT_FALSE) /* 避免重复初始化而做的保护 */ + { + rt_thread_t tid; + + tid = rt_thread_create("wb", + workbench_entry, RT_NULL, + 2048, 25, 10); + + if (tid != RT_NULL) rt_thread_startup(tid); + + inited = RT_TRUE; + } +} + +#ifdef RT_USING_RTGUI +#include +void workbench() +{ + workbench_init(); +} +/* finsh的命令输出,可以直接执行workbench()函数以执行上面的函数 */ +FINSH_FUNCTION_EXPORT(workbench, workbench demo) +#endif