Browse Source

add more UI files into radio.

git-svn-id: https://rt-thread.googlecode.com/svn/trunk@150 bbd45198-f89e-11dd-88c7-29a3b14d5316
bernard.xiong 15 years ago
parent
commit
852f73f7a0

+ 185 - 0
bsp/stm32_radio/filelist.c

@@ -0,0 +1,185 @@
+#include <rtgui/rtgui_object.h>
+#include <rtgui/rtgui_system.h>
+
+#include <rtgui/list.h>
+#include <rtgui/widgets/view.h>
+
+/* 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));
+}

+ 48 - 0
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

+ 139 - 0
bsp/stm32_radio/fnmatch.c

@@ -0,0 +1,139 @@
+#include <ctype.h>
+#include <fnmatch.h>
+#include <string.h>
+
+#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;
+}

+ 21 - 0
bsp/stm32_radio/fnmatch.h

@@ -0,0 +1,21 @@
+#ifndef _FNMATCH_H
+#define _FNMATCH_H
+
+#include <sys/cdefs.h>
+
+__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

+ 77 - 0
bsp/stm32_radio/info.c

@@ -0,0 +1,77 @@
+#include <rtgui/rtgui.h>
+#include <rtgui/image.h>
+#include <rtgui/rtgui_system.h>
+
+#include <rtgui/widgets/view.h>
+#include <rtgui/widgets/workbench.h>
+
+#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);
+}

+ 103 - 0
bsp/stm32_radio/key.c

@@ -0,0 +1,103 @@
+#include <rtthread.h>
+#include <stm32f10x.h>
+
+#include <rtgui/event.h>
+#include <rtgui/rtgui_server.h>
+
+/*
+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);
+}

+ 73 - 0
bsp/stm32_radio/today.c

@@ -0,0 +1,73 @@
+#include <rtgui/rtgui.h>
+#include <rtgui/image.h>
+#include <rtgui/rtgui_system.h>
+
+#include <rtgui/widgets/view.h>
+#include <rtgui/widgets/workbench.h>
+
+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);
+}

+ 95 - 0
bsp/stm32_radio/workbench.c

@@ -0,0 +1,95 @@
+#include <rtgui/rtgui.h>
+#include <rtgui/rtgui_system.h>
+
+#include <rtgui/widgets/view.h>
+#include <rtgui/widgets/workbench.h>
+
+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 <finsh.h>
+void workbench()
+{
+	workbench_init();
+}
+/* finsh的命令输出,可以直接执行workbench()函数以执行上面的函数 */
+FINSH_FUNCTION_EXPORT(workbench, workbench demo)
+#endif