diff --git a/bsp/stm32_radio/board.h b/bsp/stm32_radio/board.h
index 67e3efc9042b340685c439e16e28c2bfbca26287..73a85be5c4b2f64af6ce8423b4f8c891d320eb10 100644
--- a/bsp/stm32_radio/board.h
+++ b/bsp/stm32_radio/board.h
@@ -42,6 +42,10 @@
 // 	<i>Default: 1
 #define STM32_CONSOLE_USART			1
 
+// <o> Codec Version <1=>Version 1 <2=>Version 2
+// 	<i>Default: 1
+#define CODEC_VERSION	1
+
 void rt_hw_board_led_on(int n);
 void rt_hw_board_led_off(int n);
 void rt_hw_board_init(void);
diff --git a/bsp/stm32_radio/filelist.c b/bsp/stm32_radio/filelist.c
index f0c7570137178f47fab129ad839ffdc3b527a22a..8c2aed8b5a8e6eddd8168bcd52dddbfa699682ee 100644
--- a/bsp/stm32_radio/filelist.c
+++ b/bsp/stm32_radio/filelist.c
@@ -224,9 +224,9 @@ static void _filelist_view_constructor(struct filelist_view *view)
 	RTGUI_WIDGET_TEXTALIGN(RTGUI_WIDGET(view)) = RTGUI_ALIGN_CENTER_VERTICAL;
 
 	file_image = rtgui_image_create_from_mem("xpm",
-		(rt_uint8_t*)file_xpm, sizeof(file_xpm));
+		(rt_uint8_t*)file_xpm, sizeof(file_xpm), RT_TRUE);
 	folder_image = rtgui_image_create_from_mem("xpm",
-		(rt_uint8_t*)folder_xpm, sizeof(folder_xpm));
+		(rt_uint8_t*)folder_xpm, sizeof(folder_xpm), RT_TRUE);
 }
 
 rtgui_type_t *filelist_view_type_get(void)
diff --git a/bsp/stm32_radio/info.c b/bsp/stm32_radio/info.c
index a32f656150309376fbdcbf5ea157ffa3a8a35bd6..8185f987050f6c498bcf1384bd6eadc72d415738 100644
--- a/bsp/stm32_radio/info.c
+++ b/bsp/stm32_radio/info.c
@@ -36,7 +36,7 @@ static rt_bool_t view_event_handler(struct rtgui_widget* widget, struct rtgui_ev
 			
 			rtt_image = RT_NULL;
 		}
-		
+
         if (network_image != RT_NULL)
         {
             rect.x1 = rect.x2 - (network_image->w + 2);
@@ -61,7 +61,7 @@ static void info_entry(void* parameter)
 	rtgui_thread_register(rt_thread_self(), mq);
 
     network_image = rtgui_image_create_from_mem("xpm",
-		(rt_uint8_t*)network_xpm, sizeof(network_xpm));
+		(rt_uint8_t*)network_xpm, sizeof(network_xpm), RT_TRUE);
 	workbench = rtgui_workbench_create("info", "workbench");
 	if (workbench == RT_NULL) return;
 
diff --git a/bsp/stm32_radio/mp3.c b/bsp/stm32_radio/mp3.c
index 2d5ad641f6c4e6743f16afdd1479d99dcae21172..535a56b9eb937044e20d783ce7a1d8badcd305ed 100644
--- a/bsp/stm32_radio/mp3.c
+++ b/bsp/stm32_radio/mp3.c
@@ -1,11 +1,17 @@
 #include <rtthread.h>
 #include <dfs_posix.h>
 #include <mp3/pub/mp3dec.h>
+#include <string.h>
 
 #include "board.h"
 #include "netbuffer.h"
+#include "player_ui.h"
+#include "player_bg.h"
 
 #define MP3_AUDIO_BUF_SZ    4096
+#ifndef MIN
+#define MIN(x, y)			((x) < (y)? (x) : (y))
+#endif
 
 rt_uint8_t mp3_fd_buffer[MP3_AUDIO_BUF_SZ];
 
@@ -21,9 +27,8 @@ struct mp3_decoder
 	void* fetch_parameter;
 
     /* mp3 read session */
-    rt_uint8_t *read_buffer;
-    rt_uint8_t* read_ptr;
-    rt_int32_t read_offset;
+    rt_uint8_t *read_buffer, *read_ptr;
+    rt_int32_t  read_offset;
     rt_uint32_t bytes_left, bytes_left_before_decoding;
 
 	/* audio device */
@@ -99,7 +104,6 @@ void mp3_decoder_delete(struct mp3_decoder* decoder)
     rt_free(decoder);
 }
 
-rt_uint16_t is_first = 1;
 rt_uint32_t current_offset = 0;
 static rt_int32_t mp3_decoder_fill_buffer(struct mp3_decoder* decoder)
 {
@@ -116,9 +120,6 @@ static rt_int32_t mp3_decoder_fill_buffer(struct mp3_decoder* decoder)
 	bytes_to_read = (MP3_AUDIO_BUF_SZ - decoder->bytes_left) & ~(512 - 1);
 	// rt_kprintf("read bytes: %d\n", bytes_to_read);
 
-	if (is_first) is_first = 0;
-	else current_offset += MP3_AUDIO_BUF_SZ - decoder->bytes_left;
-
 	bytes_read = decoder->fetch_data(decoder->fetch_parameter,
 		(rt_uint8_t *)(decoder->read_buffer + decoder->bytes_left),
         bytes_to_read);
@@ -141,9 +142,12 @@ int mp3_decoder_run(struct mp3_decoder* decoder)
 {
 	int err;
 	rt_uint16_t* buffer;
+	rt_uint32_t  delta;
 
     RT_ASSERT(decoder != RT_NULL);
 
+	if (player_is_playing() != RT_TRUE) return -1;
+
 	if ((decoder->read_ptr == RT_NULL) || decoder->bytes_left < 2*MAINBUF_SIZE)
 	{
 		if(mp3_decoder_fill_buffer(decoder) != 0)
@@ -162,6 +166,7 @@ int mp3_decoder_run(struct mp3_decoder* decoder)
 	// rt_kprintf("sync position: %x\n", decoder->read_offset);
 
 	decoder->read_ptr += decoder->read_offset;
+	delta = decoder->read_offset;
 	decoder->bytes_left -= decoder->read_offset;
 	decoder->bytes_left_before_decoding = decoder->bytes_left;
 
@@ -196,6 +201,10 @@ int mp3_decoder_run(struct mp3_decoder* decoder)
 
 	err = MP3Decode(decoder->decoder, &decoder->read_ptr,
         (int*)&decoder->bytes_left, (short*)buffer, 0);
+	delta += (decoder->bytes_left_before_decoding - decoder->bytes_left);
+
+	current_offset += delta;
+	player_set_position(current_offset);
 
 	// rt_kprintf("bytes left after decode: %d\n", decoder->bytes_left);
 
@@ -277,26 +286,114 @@ int mp3_decoder_run(struct mp3_decoder* decoder)
 
 		/* write to sound device */
 		rt_device_write(decoder->snd_device, 0, buffer, decoder->frame_info.outputSamps * 2);
-		// rt_mp_free(buffer);
 	}
 
 	return 0;
 }
 
-/* audio information structure */
-struct audio_info
+/* get mp3 information */
+void mp3_get_info(const char* filename, struct tag_info* info)
 {
-	char* title;
-	char* artist;
+	int fd;
+	char* id3buffer;
+	rt_size_t   bytes_read;
+	int sync_word;
+    HMP3Decoder decoder;
+    MP3FrameInfo frame_info;
 
-	rt_uint32_t duration;
-	rt_uint32_t bit_rate;
-	rt_uint32_t sampling;
-};
+	id3buffer = (char*)&mp3_fd_buffer[0];
+	if (filename == RT_NULL || info == RT_NULL) return;
 
-/* get mp3 information */
-void mp3_get_info(char* filename, struct audio_info* info)
-{
+	fd = open(filename, O_RDONLY, 0);
+	if (fd < 0) return; /* can't read file */
+
+	/* init decoder */
+	decoder = MP3InitDecoder();
+
+	/* read data */
+	bytes_read = read(fd, id3buffer, sizeof(mp3_fd_buffer));
+
+	/* get frame information */
+	sync_word = MP3FindSyncWord(id3buffer, bytes_read);
+	if (sync_word < 0)
+	{
+		/* can't get sync word */
+		close(fd);
+		mp3_decoder_detach(decoder);
+	}
+	/* get frame information */
+	MP3GetNextFrameInfo(decoder, &frame_info, &id3buffer[sync_word]);
+	info->bit_rate = frame_info.bitrate;
+	info->sampling = frame_info.samprate;
+	info->duration = lseek(fd, 0, SEEK_END)/ (info->bit_rate / 8); /* second */
+
+	if (strncmp("ID3", id3buffer, 4) == 0)
+	{
+		rt_uint32_t tag_size, frame_size, i;
+		rt_uint8_t version_major;
+		int frame_header_size;
+
+		tag_size = ((rt_uint32_t)id3buffer[6] << 21)|((rt_uint32_t)id3buffer[7] << 14)|((rt_uint16_t)id3buffer[8] << 7)|id3buffer[9];
+		info->data_start = tag_size;
+		version_major = id3buffer[3];
+		if (version_major >= 3)
+		{
+			frame_header_size = 10;
+		}
+		else
+		{
+			frame_header_size = 6;
+		}
+		i = 10;
+
+		// iterate through frames
+		while (i < MIN(tag_size, sizeof(id3buffer)))
+		{
+			if (version_major >= 3)
+			{
+				frame_size = ((rt_uint32_t)id3buffer[i + 4] << 24)|((rt_uint32_t)id3buffer[i + 5] << 16)|((rt_uint16_t)id3buffer[i + 6] << 8)|id3buffer[i + 7];
+			}
+			else
+			{
+				frame_size = ((rt_uint32_t)id3buffer[i + 3] << 14)|((rt_uint16_t)id3buffer[i + 4] << 7)|id3buffer[i + 5];
+			}
+
+			if (strncmp("TT2", id3buffer + i, 3) == 0 || strncmp("TIT2", id3buffer + i, 4) == 0)
+			{
+				strncpy(info->title, id3buffer + i + frame_header_size + 1, MIN(frame_size - 1, sizeof(info->title) - 1));
+			}
+			else if (strncmp("TP1", id3buffer + i, 3) == 0 || strncmp("TPE1", id3buffer + i, 4) == 0)
+			{
+				strncpy(info->artist, id3buffer + i + frame_header_size + 1, MIN(frame_size - 1, sizeof(info->artist) - 1));
+			}
+
+			i += frame_size + frame_header_size;
+		}
+	}
+	else
+	{
+		lseek(fd, -128, SEEK_END);
+		bytes_read = read(fd, id3buffer, 128);
+
+		/* ID3v1 */
+		if (strncmp("TAG", id3buffer, 3) == 0)
+		{
+			strncpy(info->title, id3buffer + 3, MIN(30, sizeof(info->title) - 1));
+			strncpy(info->artist, id3buffer + 3 + 30, MIN(30, sizeof(info->artist) - 1));
+		}
+
+		/* set data start position */
+		info->data_start = 0;
+	}
+
+    /* set current position */
+    info->position = 0;
+
+	/* release mp3 decoder */
+    MP3FreeDecoder(decoder);
+
+	/* close file */
+	close(fd);
 }
 
 #include <finsh.h>
@@ -309,7 +406,9 @@ void mp3(char* filename)
 {
 	int fd;
 	struct mp3_decoder* decoder;
-
+	extern rt_bool_t is_playing;
+	
+	is_playing = RT_TRUE;
 	fd = open(filename, O_RDONLY, 0);
 	if (fd >= 0)
 	{
@@ -319,6 +418,7 @@ void mp3(char* filename)
 			decoder->fetch_data = fd_fetch;
 			decoder->fetch_parameter = (void*)fd;
 
+			current_offset = 0;
 			while (mp3_decoder_run(decoder) != -1);
 			close(fd);
 
@@ -326,6 +426,7 @@ void mp3(char* filename)
 			mp3_decoder_delete(decoder);
 		}
 	}
+	is_playing = RT_FALSE;
 }
 FINSH_FUNCTION_EXPORT(mp3, mp3 decode test);
 
@@ -369,6 +470,7 @@ void http_mp3(char* url)
 			decoder->fetch_data = http_data_fetch;
 			decoder->fetch_parameter = RT_NULL;
 
+			current_offset = 0;
 			while (mp3_decoder_run(decoder) != -1);
 
 			/* delete decoder object */
diff --git a/bsp/stm32_radio/play_list.c b/bsp/stm32_radio/play_list.c
new file mode 100644
index 0000000000000000000000000000000000000000..2484951f4746356fa78d536a773cf4d086d75366
--- /dev/null
+++ b/bsp/stm32_radio/play_list.c
@@ -0,0 +1,101 @@
+#include "play_list.h"
+#include "player_ui.h"
+#include <string.h>
+
+static struct play_item **play_list = RT_NULL;
+static rt_uint16_t play_list_size = 0;
+static rt_int16_t  play_list_current = 0;
+
+void play_list_clear()
+{
+    rt_uint32_t index;
+
+    for (index = 0; index < play_list_size; index ++)
+    {
+        rt_free(play_list[index]->fn);
+        rt_free(play_list[index]);
+
+		play_list[index] = RT_NULL;
+    }
+
+    rt_free(play_list);
+    play_list = RT_NULL;
+    play_list_size = 0;
+}
+
+char* play_list_start()
+{
+    play_list_current = 0;
+    return play_list[play_list_current]->fn;
+}
+
+rt_bool_t play_list_is_end()
+{
+    if ((play_list_current == play_list_size - 1) ||
+        play_list_size == 0)
+        return RT_TRUE;
+
+    return RT_FALSE;
+}
+
+rt_uint32_t play_list_items(void)
+{
+    return play_list_size;
+}
+
+struct play_item* play_list_item(rt_uint32_t n)
+{
+    if (n > play_list_size) return RT_NULL;
+    return play_list[n];
+}
+
+void play_list_append(char* fn)
+{
+    play_list_size ++;
+	if (play_list == RT_NULL)
+		play_list = (struct play_item**) rt_malloc (play_list_size * sizeof(struct play_item*));
+	else
+    	play_list = (struct play_item**) rt_realloc(play_list, play_list_size * sizeof(struct play_item*));
+
+    play_list[play_list_size - 1] = (struct play_item*)rt_malloc(sizeof(struct play_item));
+	if (strstr(fn, ".mp3") != RT_NULL ||
+		strstr(fn, ".MP3") != RT_NULL)
+	{
+		struct tag_info info;
+
+		memset(&info, 0, sizeof(info));
+		mp3_get_info(fn, &info);
+		if (info.title[0] == '\0')
+			rt_snprintf(play_list[play_list_size - 1]->title, sizeof(play_list[play_list_size - 1]->title),
+				"<未知名音乐>");
+		else
+			strcpy(play_list[play_list_size - 1]->title, info.title);
+
+		play_list[play_list_size - 1]->fn = rt_strdup(fn);
+		play_list[play_list_size - 1]->duration = info.duration;
+	}
+	else
+	{
+		rt_snprintf(play_list[play_list_size - 1]->title, sizeof(play_list[play_list_size - 1]->title),
+			"<未知名音乐>");
+		play_list[play_list_size - 1]->fn = rt_strdup(fn);
+		play_list[play_list_size - 1]->duration = 0;
+	}
+}
+
+char* play_list_next()
+{
+    if (play_list_current < play_list_size - 1) play_list_current ++;
+    return play_list[play_list_current]->fn;
+}
+
+char* play_list_prev()
+{
+    if (play_list_current > 0) play_list_current --;
+    return play_list[play_list_current]->fn;
+}
+
+char* play_list_current_item()
+{
+    return play_list[play_list_current]->fn;
+}
diff --git a/bsp/stm32_radio/play_list.h b/bsp/stm32_radio/play_list.h
new file mode 100644
index 0000000000000000000000000000000000000000..f7aa05382fdf134d74b7bdc14edd7365390dae0e
--- /dev/null
+++ b/bsp/stm32_radio/play_list.h
@@ -0,0 +1,25 @@
+#ifndef __PLAY_LIST_H__
+#define __PLAY_LIST_H__
+
+#include <rtthread.h>
+
+struct play_item
+{
+	char title[40];
+	char *fn;
+	rt_uint32_t duration;
+};
+
+void play_list_clear(void);
+
+char* play_list_start(void);
+rt_bool_t play_list_is_end(void);
+rt_uint32_t play_list_items(void);
+struct play_item* play_list_item(rt_uint32_t n);
+
+void play_list_append(char* fn);
+char* play_list_next(void);
+char* play_list_prev(void);
+char* play_list_current_item(void);
+
+#endif
diff --git a/bsp/stm32_radio/player.c b/bsp/stm32_radio/player.c
deleted file mode 100644
index 23d97ecd238e698636b4e319deb61bda0e14d002..0000000000000000000000000000000000000000
--- a/bsp/stm32_radio/player.c
+++ /dev/null
@@ -1,673 +0,0 @@
-#include <rtgui/rtgui.h>
-#include <rtgui/image.h>
-#include <rtgui/rtgui_system.h>
-
-#include <rtgui/widgets/view.h>
-#include <rtgui/widgets/workbench.h>
-#include <string.h>
-
-#include "listview.h"
-#include "filelist.h"
-
-static const char * next_xpm[] = {
-"24 24 149 2",
-"  	c None",
-". 	c #373737",
-"+ 	c #383838",
-"@ 	c #3A3A3A",
-"# 	c #393939",
-"$ 	c #434343",
-"% 	c #676767",
-"& 	c #9D9D9D",
-"* 	c #C1C1C1",
-"= 	c #D3D3D3",
-"- 	c #404040",
-"; 	c #707070",
-"> 	c #EDEDED",
-", 	c #F5F5F5",
-"' 	c #4A4A4A",
-") 	c #909090",
-"! 	c #D9D9D9",
-"~ 	c #4B4B4B",
-"{ 	c #939393",
-"] 	c #CECECE",
-"^ 	c #E4E4E4",
-"/ 	c #E5E5E5",
-"( 	c #444444",
-"_ 	c #8B8B8B",
-": 	c #ABABAB",
-"< 	c #DCDCDC",
-"[ 	c #D4D4D4",
-"} 	c #D2D2D2",
-"| 	c #DDDDDD",
-"1 	c #DEDEDE",
-"2 	c #DFDFDF",
-"3 	c #414141",
-"4 	c #B8B8B8",
-"5 	c #BBBBBB",
-"6 	c #ADADAD",
-"7 	c #B7B7B7",
-"8 	c #CFCFCF",
-"9 	c #D8D8D8",
-"0 	c #D6D6D6",
-"a 	c #B2B2B2",
-"b 	c #AEAEAE",
-"c 	c #B6B6B6",
-"d 	c #4C4C4C",
-"e 	c #989898",
-"f 	c #9E9E9E",
-"g 	c #CDCDCD",
-"h 	c #C5C5C5",
-"i 	c #C7C7C7",
-"j 	c #A1A1A1",
-"k 	c #B3B3B3",
-"l 	c #9F9F9F",
-"m 	c #A2A2A2",
-"n 	c #CACACA",
-"o 	c #696969",
-"p 	c #A0A0A0",
-"q 	c #B1B1B1",
-"r 	c #F1F1F1",
-"s 	c #E3E3E3",
-"t 	c #CCCCCC",
-"u 	c #C6C6C6",
-"v 	c #D1D1D1",
-"w 	c #C2C2C2",
-"x 	c #464646",
-"y 	c #848484",
-"z 	c #A4A4A4",
-"A 	c #A9A9A9",
-"B 	c #BFBFBF",
-"C 	c #959595",
-"D 	c #EFEFEF",
-"E 	c #EEEEEE",
-"F 	c #929292",
-"G 	c #808080",
-"H 	c #CBCBCB",
-"I 	c #858585",
-"J 	c #B9B9B9",
-"K 	c #A5A5A5",
-"L 	c #494949",
-"M 	c #A7A7A7",
-"N 	c #B0B0B0",
-"O 	c #888888",
-"P 	c #EAEAEA",
-"Q 	c #777777",
-"R 	c #6C6C6C",
-"S 	c #C4C4C4",
-"T 	c #757575",
-"U 	c #A8A8A8",
-"V 	c #A3A3A3",
-"W 	c #949494",
-"X 	c #9C9C9C",
-"Y 	c #EBEBEB",
-"Z 	c #575757",
-"` 	c #4D4D4D",
-" .	c #ACACAC",
-"..	c #6B6B6B",
-"+.	c #9A9A9A",
-"@.	c #E9E9E9",
-"#.	c #D7D7D7",
-"$.	c #BDBDBD",
-"%.	c #515151",
-"&.	c #E8E8E8",
-"*.	c #E2E2E2",
-"=.	c #9B9B9B",
-"-.	c #4E4E4E",
-";.	c #B4B4B4",
-">.	c #525252",
-",.	c #BEBEBE",
-"'.	c #8C8C8C",
-").	c #AAAAAA",
-"!.	c #AFAFAF",
-"~.	c #E7E7E7",
-"{.	c #5D5D5D",
-"].	c #7E7E7E",
-"^.	c #616161",
-"/.	c #C8C8C8",
-"(.	c #747474",
-"_.	c #B5B5B5",
-":.	c #6D6D6D",
-"<.	c #4F4F4F",
-"[.	c #5A5A5A",
-"}.	c #A6A6A6",
-"|.	c #919191",
-"1.	c #8D8D8D",
-"2.	c #DBDBDB",
-"3.	c #7F7F7F",
-"4.	c #E0E0E0",
-"5.	c #C0C0C0",
-"6.	c #828282",
-"7.	c #595959",
-"8.	c #C9C9C9",
-"9.	c #E1E1E1",
-"0.	c #E6E6E6",
-"a.	c #D5D5D5",
-"b.	c #626262",
-"c.	c #ECECEC",
-"d.	c #636363",
-"e.	c #646464",
-"f.	c #F0F0F0",
-"g.	c #F3F3F3",
-"h.	c #F4F4F4",
-"i.	c #F6F6F6",
-"j.	c #F7F7F7",
-"k.	c #5E5E5E",
-"l.	c #898989",
-"m.	c #F9F9F9",
-"n.	c #F8F8F8",
-"o.	c #8A8A8A",
-"p.	c #656565",
-"q.	c #5C5C5C",
-"r.	c #5F5F5F",
-"                  . + @ @ + .                   ",
-"            # $ % & * = = * & % $ #             ",
-"          - ; * > , , , , , , > * ; -           ",
-"        ' ) ! > > > > > > > > > > ! ) '         ",
-"      ~ { ] ^ ^ / / / / / / / / / / ] { ~       ",
-"    ( _ : < [ } | 1 2 2 2 2 1 | < < < : _ (     ",
-"  3 ; & 4 = 5 6 7 8 9 ! ! ! 0 a b c = 4 & ; 3   ",
-"  d e f 4 g b h i j k ] [ [ g l } m n 4 f e d   ",
-"  o & p q i j * r s b { k t u ) v { w q j f o   ",
-"x y l z A B C 4 D D E v F _ : G H I J A K j y x ",
-"L { m M : N O N > > > > P 4 Q R S T U : U V W L ",
-"~ X K A b 6 ; K Y Y Y Y Y Y 2 k S Z K b : M & ~ ",
-"` f M  .N N ..+.@.@.@.@.@.@.#.f $.%.M a k q V ` ",
-"` e U b a a R +.&.&.&.&.*.=.-.( ;.>.b ,.,.$.f ` ",
-"-.'.).!.;.;.R +.&.&.~.7 {.Z ].L ;.^.B /./.i ) -.",
-"  (.).N _.;.:.+.&.] T <.G ).A %.h _ n } } i (.  ",
-"  [.}.q _.;.:.|.) ` :.K B t /.1.= l [ 2.2.c [.  ",
-"  >.G _.B B 3.[.o =.,.= 4./ 2.K 5.k | s #.6.>.  ",
-"    7.l S H 7 q 8.#.9.0.@.@./ g H a.&.0.M 7.    ",
-"      b. .8 a.9 1 ^ &.Y c.E > c.c.E > 7 d.      ",
-"        e.}.= s ~.Y > f.r g.h.i.j.@. .e.        ",
-"          k.l.5.1 E g.i.j.m.n.Y /.o.k.          ",
-"            [.p.6.m 5 H H ,.z 6.p.[.            ",
-"                  q.k.r.r.k.q.                  "};
-
-static const char * prev_xpm[] = {
-"24 24 153 2",
-"  	c None",
-". 	c #373737",
-"+ 	c #383838",
-"@ 	c #3A3A3A",
-"# 	c #393939",
-"$ 	c #434343",
-"% 	c #676767",
-"& 	c #9D9D9D",
-"* 	c #C1C1C1",
-"= 	c #D3D3D3",
-"- 	c #404040",
-"; 	c #707070",
-"> 	c #EDEDED",
-", 	c #F5F5F5",
-"' 	c #4A4A4A",
-") 	c #909090",
-"! 	c #D9D9D9",
-"~ 	c #4B4B4B",
-"{ 	c #939393",
-"] 	c #CECECE",
-"^ 	c #E5E5E5",
-"/ 	c #E4E4E4",
-"( 	c #444444",
-"_ 	c #8B8B8B",
-": 	c #ABABAB",
-"< 	c #DCDCDC",
-"[ 	c #DDDDDD",
-"} 	c #DEDEDE",
-"| 	c #DFDFDF",
-"1 	c #D5D5D5",
-"2 	c #D2D2D2",
-"3 	c #DADADA",
-"4 	c #414141",
-"5 	c #B8B8B8",
-"6 	c #D4D4D4",
-"7 	c #BBBBBB",
-"8 	c #AEAEAE",
-"9 	c #AFAFAF",
-"0 	c #D0D0D0",
-"a 	c #D8D8D8",
-"b 	c #ADADAD",
-"c 	c #B5B5B5",
-"d 	c #B7B7B7",
-"e 	c #4C4C4C",
-"f 	c #989898",
-"g 	c #9E9E9E",
-"h 	c #AAAAAA",
-"i 	c #CCCCCC",
-"j 	c #A3A3A3",
-"k 	c #D1D1D1",
-"l 	c #A1A1A1",
-"m 	c #CDCDCD",
-"n 	c #A5A5A5",
-"o 	c #C5C5C5",
-"p 	c #696969",
-"q 	c #A0A0A0",
-"r 	c #B1B1B1",
-"s 	c #C8C8C8",
-"t 	c #C9C9C9",
-"u 	c #949494",
-"v 	c #CACACA",
-"w 	c #B9B9B9",
-"x 	c #959595",
-"y 	c #A7A7A7",
-"z 	c #F1F1F1",
-"A 	c #969696",
-"B 	c #BCBCBC",
-"C 	c #464646",
-"D 	c #848484",
-"E 	c #9F9F9F",
-"F 	c #A4A4A4",
-"G 	c #A9A9A9",
-"H 	c #C2C2C2",
-"I 	c #868686",
-"J 	c #8E8E8E",
-"K 	c #8C8C8C",
-"L 	c #EFEFEF",
-"M 	c #C6C6C6",
-"N 	c #888888",
-"O 	c #B2B2B2",
-"P 	c #494949",
-"Q 	c #A2A2A2",
-"R 	c #828282",
-"S 	c #777777",
-"T 	c #737373",
-"U 	c #E7E7E7",
-"V 	c #C0C0C0",
-"W 	c #797979",
-"X 	c #A8A8A8",
-"Y 	c #9C9C9C",
-"Z 	c #B0B0B0",
-"` 	c #686868",
-" .	c #B6B6B6",
-"..	c #EBEBEB",
-"+.	c #5D5D5D",
-"@.	c #9A9A9A",
-"#.	c #4D4D4D",
-"$.	c #ACACAC",
-"%.	c #B3B3B3",
-"&.	c #636363",
-"*.	c #CFCFCF",
-"=.	c #E9E9E9",
-"-.	c #575757",
-";.	c #515151",
-">.	c #E8E8E8",
-",.	c #BEBEBE",
-"'.	c #BDBDBD",
-").	c #4E4E4E",
-"!.	c #B4B4B4",
-"~.	c #646464",
-"{.	c #525252",
-"].	c #5F5F5F",
-"^.	c #565656",
-"/.	c #666666",
-"(.	c #C7C7C7",
-"_.	c #747474",
-":.	c #929292",
-"<.	c #555555",
-"[.	c #6B6B6B",
-"}.	c #C3C3C3",
-"|.	c #5A5A5A",
-"1.	c #A6A6A6",
-"2.	c #C4C4C4",
-"3.	c #BABABA",
-"4.	c #838383",
-"5.	c #DBDBDB",
-"6.	c #808080",
-"7.	c #BFBFBF",
-"8.	c #858585",
-"9.	c #5E5E5E",
-"0.	c #E0E0E0",
-"a.	c #E2E2E2",
-"b.	c #D7D7D7",
-"c.	c #595959",
-"d.	c #E3E3E3",
-"e.	c #E6E6E6",
-"f.	c #626262",
-"g.	c #D6D6D6",
-"h.	c #ECECEC",
-"i.	c #EEEEEE",
-"j.	c #EAEAEA",
-"k.	c #F0F0F0",
-"l.	c #F3F3F3",
-"m.	c #F4F4F4",
-"n.	c #F6F6F6",
-"o.	c #F7F7F7",
-"p.	c #898989",
-"q.	c #F9F9F9",
-"r.	c #F8F8F8",
-"s.	c #8A8A8A",
-"t.	c #656565",
-"u.	c #CBCBCB",
-"v.	c #5C5C5C",
-"                  . + @ @ + .                   ",
-"            # $ % & * = = * & % $ #             ",
-"          - ; * > , , , , , , > * ; -           ",
-"        ' ) ! > > > > > > > > > > ! ) '         ",
-"      ~ { ] ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ / / ] { ~       ",
-"    ( _ : < < < [ } } | | | } } 1 2 3 : _ (     ",
-"  4 ; & 5 6 7 8 9 0 a ! ! ! = 7 b c 0 d & ; 4   ",
-"  e f g 5 ] h i j * k 6 k 5 l * m n o d g f e   ",
-"  p & q r s & t u c v w x y } z m A B 9 l g p   ",
-"C D E F G * ) H I q J K v > L L M N O y n l D C ",
-"P { Q y : O R 7 S T 9 U > > > > V W E X X j u P ",
-"~ Y n G 8 Z `  . .3 ............ .+.@.: : y & ~ ",
-"#.g y $.r %.&.b j *.=.=.=.=.=.=.8 -.& Z %.r j #.",
-"#.f X 8 %.c &.X ;.' ) } >.>.>.>.8 -.j B ,.'.g #.",
-").K h 9 !.d ~.X {.W ].^.$.^ >.>.8 /. .(.s (.) ).",
-"  _.h Z c 5 ~.X {.:.O :.<.[.o =.H J }.0 2 (._.  ",
-"  |.1.r c 5 ~.X {.f 2.i 3.4.T !.s Q ] ! 5. .|.  ",
-"  {.6.c 7.H S 8.9.n *.} 0.[ *.O X  .! a.b.R {.  ",
-"    c.E 2.m  .j G m 0.U =.=.U d.b.b.e.e.y c.    ",
-"      f.$.0 g.g.a | U ..h.i.i.L i.L h.d &.      ",
-"        ~.1.= d.U j.> k.z l.m.n.o.=.$.~.        ",
-"          9.p.V } i.l.n.o.q.r...s s.9.          ",
-"            |.t.R Q 7 u.u.,.F R t.|.            ",
-"                  v.9.].].9.v.                  "};
-
-static rtgui_image_t *background = RT_NULL;
-static rtgui_image_t *next = RT_NULL, *prev = RT_NULL;
-
-static struct rtgui_view* function_view;
-static struct rtgui_view* home_view;
-static struct rtgui_workbench* workbench;
-
-void player_play_list(const char** list);
-void player_play_file(const char * fn);
-void player_next(void);
-void player_prev(void);
-
-void function_filelist(void* parameter)
-{
-	rtgui_rect_t rect;
-	filelist_view_t *view;
-
-	rtgui_widget_get_rect(RTGUI_WIDGET(workbench), &rect);
-	view = filelist_view_create(workbench, "/", "*.*", &rect);
-	if (view != RT_NULL)
-	{
-	    if (rtgui_view_show(RTGUI_VIEW(view), RT_TRUE) == RTGUI_MODAL_OK)
-	    {
-			char fn[64];
-			
-	    	/* get open file */
-			rt_kprintf("dir %s\n", view->current_directory);
-			rt_kprintf("item %s\n", view->items[view->current_item].name);
-			
-			rt_snprintf(fn, 64, "%s/%s", view->current_directory,
-				view->items[view->current_item].name);
-
-			rtgui_view_show(home_view, RT_FALSE);
-
-			player_play_file(fn);
-	    }
-		
-		/* destroy view */
-		filelist_view_destroy(view);
-	}
-
-	return;
-}
-
-void function_device(void* parameter)
-{
-	rtgui_view_t *view;
-	extern rtgui_view_t* device_view_create(rtgui_workbench_t* workbench);
-	
-	view = device_view_create(workbench);
-	if (view != RT_NULL)
-	{
-	    rtgui_view_show(view, RT_FALSE);
-	}
-
-	return;
-}
-
-void function_player(void* parameter)
-{
-    rtgui_view_show(home_view, RT_FALSE);
-	return;
-}
-
-void function_action(void* parameter)
-{
-	rt_kprintf("item action!\n");
-	return;
-}
-
-struct list_item function_list[] =
-{
-	{"选择电台", RT_NULL, function_action, RT_NULL},
-	{"更新电台", RT_NULL, function_action, RT_NULL},
-	{"播放文件", RT_NULL, function_filelist, RT_NULL},
-	{"设备信息", RT_NULL, function_device, RT_NULL},
-	{"返回播放器", RT_NULL, function_player, RT_NULL},
-};
-
-static rt_bool_t home_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);
-
-		/* draw background */
-	    background = rtgui_image_create_from_file("hdc",
-	        "/resource/bg.hdc", RT_FALSE);
-		if (background != RT_NULL)
-		{
-            rtgui_image_blit(background, dc, &rect);
-			rtgui_image_destroy(background);
-			
-			background = RT_NULL;
-		}
-		else
-		{
-			rtgui_dc_fill_rect(dc, &rect);
-		}
-
-		/* draw playing information */
-		rect.x1 = 10; rect.y1 = 260;
-		rect.x2 = 25; rect.y2 = 285;
-		if (prev != RT_NULL) rtgui_image_blit(prev, dc, &rect);
-		if (next != RT_NULL)
-		{
-			rect.x2 = 230; rect.x1 = rect.x2 - 25;
-			rtgui_image_blit(next, dc, &rect);
-		}
-
-		rect.x1 = 35; rect.y1 = 260;
-		rect.x2 = 205; rect.y2 = 285;
-		rtgui_dc_fill_rect(dc, &rect);
-		rtgui_dc_end_drawing(dc);
-
-		return RT_FALSE;
-	}
-	else if (event->type == RTGUI_EVENT_KBD)
-	{
-		struct rtgui_event_kbd* ekbd = (struct rtgui_event_kbd*)event;
-		if (ekbd->type == RTGUI_KEYDOWN)
-		{
-			switch (ekbd->key)
-			{
-			case RTGUIK_RIGHT:
-			case RTGUIK_LEFT:
-				break;
-
-			case RTGUIK_DOWN:
-                rtgui_view_show(function_view, RT_FALSE);
-				break;
-			}
-		}
-		return RT_FALSE;
-	}
-
-	return rtgui_view_event_handler(widget, event);
-}
-
-rt_bool_t today_workbench_event_handler(rtgui_widget_t *widget, rtgui_event_t *event)
-{
-    if (event->type == RTGUI_EVENT_KBD)
-    {
-        struct rtgui_event_kbd* ekbd = (struct rtgui_event_kbd*)event;
-        if ((ekbd->type == RTGUI_KEYUP) && ekbd->key == RTGUIK_HOME)
-        {
-            /* active home view */
-            if (workbench->current_view != home_view)
-            {
-                rtgui_view_show(home_view, RT_FALSE);
-                return RT_FALSE;
-            }
-        }
-    }
-
-    return rtgui_workbench_event_handler(widget, event);
-}
-
-static void player_entry(void* parameter)
-{
-	rt_mq_t mq;
-	rtgui_rect_t rect;
-
-	mq = rt_mq_create("qPlayer", 256, 4, RT_IPC_FLAG_FIFO);
-	rtgui_thread_register(rt_thread_self(), mq);
-
-	next = rtgui_image_create_from_mem("xpm", (rt_uint8_t*)next_xpm, 
-		sizeof(next_xpm));
-	prev = rtgui_image_create_from_mem("xpm", (rt_uint8_t*)prev_xpm,
-		sizeof(prev_xpm));
-
-	workbench = rtgui_workbench_create("main", "workbench");
-	if (workbench == RT_NULL) return;
-	rtgui_widget_set_event_handler(RTGUI_WIDGET(workbench), today_workbench_event_handler);
-
-    /* add home view */
-	home_view = rtgui_view_create("Home");
-	rtgui_widget_set_event_handler(RTGUI_WIDGET(home_view), home_view_event_handler);
-
-	rtgui_workbench_add_view(workbench, home_view);
-	/* this view can be focused */
-	RTGUI_WIDGET(home_view)->flag |= RTGUI_WIDGET_FLAG_FOCUSABLE;
-	/* set widget focus */
-	rtgui_widget_focus(RTGUI_WIDGET(home_view));
-
-	rtgui_view_show(home_view, RT_FALSE);
-
-    /* add function view */
-	rtgui_widget_get_rect(RTGUI_WIDGET(workbench), &rect);
-	function_view = (struct rtgui_view*)list_view_create(function_list,
-		sizeof(function_list)/sizeof(struct list_item),
-		&rect);
-	rtgui_workbench_add_view(workbench, function_view);
-
-	rtgui_workbench_event_loop(workbench);
-
-	rtgui_thread_deregister(rt_thread_self());
-	rt_mq_delete(mq);
-}
-
-enum PLAYER_MODE
-{
-	PLAYER_SINGLE,
-	PLAYER_FILE,
-	PLAYER_RADIO,
-};
-
-enum PLAYER_REQUEST_TYPE
-{
-	PLAYER_REQUEST_PLAY_SINGLE_FILE,
-	PLAYER_REQUEST_PLAY_LIST,
-	PLAYER_REQUEST_STOP,
-	PLAYER_REQUEST_NEXT,
-	PLAYER_REQUEST_PREV,
-};
-
-struct player_request
-{
-	enum PLAYER_REQUEST_TYPE type;
-
-	char fn[64];
-};
-static rt_mq_t player_thread_mq;
-
-void player_play_list(const char** list)
-{
-}
-
-void player_play_file(const char* fn)
-{
-	struct player_request request;
-	request.type = PLAYER_REQUEST_PLAY_SINGLE_FILE;
-	strncpy(request.fn, fn, sizeof(request.fn));
-
-	/* send to message queue */
-	rt_mq_send(player_thread_mq, (void*)&request, sizeof(struct player_request));
-}
-
-void player_stop()
-{
-}
-
-void player_next()
-{
-}
-
-void player_prev()
-{
-}
-
-void player_thread(void* parameter)
-{
-	rt_err_t result;
-	struct player_request request;
-	
-	while(1)
-	{
-		/* get request from message queue */
-		result = rt_mq_recv(player_thread_mq, (void*)&request, 
-			sizeof(struct player_request), RT_WAITING_FOREVER);
-		if (result == RT_EOK)
-		{
-			switch (request.type)
-			{
-			case PLAYER_REQUEST_PLAY_SINGLE_FILE:
-				if ((strstr(request.fn, ".mp3") != RT_NULL) ||
-					(strstr(request.fn, ".MP3") != RT_NULL))
-				{
-					mp3(request.fn);
-				}
-				else if ((strstr(request.fn, ".wav") != RT_NULL) ||
-					(strstr(request.fn, ".WAV") != RT_NULL))
-				{
-					wav(request.fn);
-				}
-				break;
-			}
-		}
-	}
-}
-
-void player_init()
-{
-    rt_thread_t tid;
-
-    tid = rt_thread_create("player",
-        player_entry, RT_NULL,
-        2048, RTGUI_APP_THREAD_PRIORITY, RTGUI_APP_THREAD_TIMESLICE);
-
-    if (tid != RT_NULL) rt_thread_startup(tid);
-
-	/* create player thread */
-	player_thread_mq = rt_mq_create("player", sizeof(struct player_request),
-		8, RT_IPC_FLAG_FIFO);
-	RT_ASSERT(player_thread_mq != RT_NULL);
-
-	tid = rt_thread_create("pthread", player_thread, RT_NULL,
-		2048, RTGUI_APP_THREAD_PRIORITY, RTGUI_APP_THREAD_TIMESLICE);
-	if (tid != RT_NULL) rt_thread_startup(tid);
-}
-
diff --git a/bsp/stm32_radio/player_bg.c b/bsp/stm32_radio/player_bg.c
new file mode 100644
index 0000000000000000000000000000000000000000..e2553c26e76ce71793b6bbb59adee253ea91b19a
--- /dev/null
+++ b/bsp/stm32_radio/player_bg.c
@@ -0,0 +1,83 @@
+#include "player_bg.h"
+#include "player_ui.h"
+
+#include <string.h>
+
+static rt_mq_t player_thread_mq;
+rt_bool_t is_playing = RT_FALSE;
+
+rt_bool_t player_is_playing()
+{
+	return is_playing;
+}
+
+void player_play_file(const char* fn)
+{
+    struct player_request request;
+    request.type = PLAYER_REQUEST_PLAY_SINGLE_FILE;
+    strncpy(request.fn, fn, sizeof(request.fn));
+
+    /* send to message queue */
+    rt_mq_send(player_thread_mq, (void*)&request, sizeof(struct player_request));
+}
+
+void player_stop()
+{
+	is_playing = RT_FALSE;
+}
+
+void player_thread(void* parameter)
+{
+	rt_err_t result;
+	struct player_request request;
+
+	while(1)
+	{
+		/* get request from message queue */
+		result = rt_mq_recv(player_thread_mq, (void*)&request,
+			sizeof(struct player_request), RT_WAITING_FOREVER);
+		if (result == RT_EOK)
+		{
+			switch (request.type)
+			{
+			case PLAYER_REQUEST_PLAY_SINGLE_FILE:
+				if ((strstr(request.fn, ".mp3") != RT_NULL) ||
+					(strstr(request.fn, ".MP3") != RT_NULL))
+				{
+					is_playing = RT_TRUE;
+					player_notify_play();
+
+				    /* get music tag information */
+					mp3(request.fn);
+					
+					player_notify_stop();
+					is_playing = RT_FALSE;
+				}
+				else if ((strstr(request.fn, ".wav") != RT_NULL) ||
+					(strstr(request.fn, ".WAV") != RT_NULL))
+				{
+					is_playing = RT_TRUE;
+					wav(request.fn);
+					is_playing = RT_FALSE;
+				}
+				break;
+			}
+		}
+	}
+}
+
+void player_init()
+{
+    rt_thread_t tid;
+
+	/* create player thread */
+	player_thread_mq = rt_mq_create("player", sizeof(struct player_request),
+		8, RT_IPC_FLAG_FIFO);
+	RT_ASSERT(player_thread_mq != RT_NULL);
+
+	tid = rt_thread_create("ply_bg", player_thread, RT_NULL,
+		2048, 20, 5);
+	if (tid != RT_NULL) rt_thread_startup(tid);
+	
+	player_ui_init();
+}
diff --git a/bsp/stm32_radio/player_bg.h b/bsp/stm32_radio/player_bg.h
new file mode 100644
index 0000000000000000000000000000000000000000..c419e828e34d67f66688424312746bb5f28d3e86
--- /dev/null
+++ b/bsp/stm32_radio/player_bg.h
@@ -0,0 +1,28 @@
+#ifndef __PLAYER_BG_H__
+#define __PLAYER_BG_H__
+
+#include <rtthread.h>
+
+enum PLAYER_REQUEST_TYPE
+{
+	PLAYER_REQUEST_PLAY_SINGLE_FILE,
+	PLAYER_REQUEST_PLAY_LIST,
+	PLAYER_REQUEST_STOP,
+	PLAYER_REQUEST_NEXT,
+	PLAYER_REQUEST_PREV,
+};
+
+struct player_request
+{
+	enum PLAYER_REQUEST_TYPE type;
+
+	char fn[64];
+};
+
+rt_bool_t player_is_playing(void);
+void player_stop(void);
+
+void player_play_list(const char** list);
+void player_play_file(const char* fn);
+
+#endif
diff --git a/bsp/stm32_radio/player_ui.c b/bsp/stm32_radio/player_ui.c
new file mode 100644
index 0000000000000000000000000000000000000000..f3d155f1d25c59883d967a95b3720490653c8867
--- /dev/null
+++ b/bsp/stm32_radio/player_ui.c
@@ -0,0 +1,652 @@
+#include <rtgui/rtgui.h>
+#include <rtgui/image.h>
+#include <rtgui/rtgui_system.h>
+
+#include <rtgui/widgets/view.h>
+#include <rtgui/widgets/workbench.h>
+#include <string.h>
+
+#include <dfs_posix.h>
+
+#include "player_ui.h"
+#include "player_bg.h"
+#include "play_list.h"
+
+#include "listview.h"
+#include "filelist.h"
+
+#include "play.hdh"
+#include "stop.hdh"
+
+static rtgui_image_t *background = RT_NULL;
+
+static struct rtgui_view* function_view;
+static struct rtgui_view* home_view;
+static struct rtgui_workbench* workbench;
+static rtgui_timer_t* info_timer;
+static rt_thread_t player_ui_tid = RT_NULL;
+static enum PLAYER_MODE player_mode = PLAYER_STOP;
+static enum PLAYER_STEP next_step = PLAYER_STEP_STOP;
+static struct tag_info tinfo;
+
+void player_set_position(rt_uint32_t position)
+{
+    tinfo.position = position / (tinfo.bit_rate / 8);
+}
+
+void info_timer_timeout(rtgui_timer_t* timer, void* parameter)
+{
+	struct rtgui_dc* dc;
+	rtgui_color_t saved;
+
+	dc = rtgui_dc_begin_drawing(RTGUI_WIDGET(home_view));
+	if (dc == RT_NULL) return ;
+
+	saved = RTGUI_WIDGET_FOREGROUND(RTGUI_WIDGET(home_view));
+
+	RTGUI_WIDGET_FOREGROUND(RTGUI_WIDGET(home_view)) = RTGUI_RGB(206, 231, 255);
+	rtgui_dc_draw_hline(dc, 14, 14  + (tinfo.position * 212)/ tinfo.duration,
+		75);
+
+	RTGUI_WIDGET_FOREGROUND(RTGUI_WIDGET(home_view)) = saved;
+	rtgui_dc_end_drawing(dc);
+}
+
+rt_uint32_t read_line(int fd, char* line, rt_uint32_t line_size)
+{
+    char *pos, *next;
+    rt_uint32_t length;
+
+    length = read(fd, line, line_size);
+    if (length > 0)
+    {
+        pos = strstr(line, "\r\n");
+		if (pos == RT_NULL)
+		{
+			pos = strstr(line, "\n");
+			next = pos ++;
+		}
+		else next = pos + 2;
+
+        if (pos != RT_NULL)
+        {
+            *pos = '\0';
+
+            /* move back */
+            lseek(fd, -(length - (next - line)), SEEK_CUR);
+
+            length = pos - line;
+        }
+        else length = 0;
+    }
+
+	rt_kprintf("line %s\n", line);
+    return length;
+}
+
+static void player_update_tag_info(struct rtgui_dc* dc)
+{
+	rtgui_rect_t rect;
+    char line[32];
+	rtgui_color_t saved;
+
+	saved = rtgui_dc_get_color(dc);
+	rtgui_dc_set_color(dc, black);
+
+	rect.x1 = 0; rect.y1 = 0;
+	rect.x2 = 240; rect.y2 = 65;
+	/* draw background */
+    background = rtgui_image_create_from_file("hdc",
+        "/resource/bg.hdc", RT_FALSE);
+	if (background != RT_NULL)
+	{
+        rtgui_image_blit(background, dc, &rect);
+		rtgui_image_destroy(background);
+
+		background = RT_NULL;
+	}
+	else
+	{
+		rtgui_dc_fill_rect(dc, &rect);
+	}
+
+	/* draw playing information */
+    rect.x1 = 28; rect.y1 = 12;
+    rect.x2 = 220; rect.y2 = rect.y1 + 16;
+	if (player_mode == PLAYER_STOP)
+	{
+		rt_snprintf(line, sizeof(line),
+			"网络收音机");
+	    rtgui_dc_draw_text(dc, line, &rect);
+	}
+	else
+	    rtgui_dc_draw_text(dc, tinfo.title, &rect);
+
+    rect.x1 = 28; rect.y1 = 39;
+    rect.x2 = 220; rect.y2 = 59;
+	if (player_mode == PLAYER_STOP)
+	{
+		rt_snprintf(line, sizeof(line),
+			"radio.rt-thread.org");
+	    rtgui_dc_draw_text(dc, line, &rect);
+	}
+	else
+	    rtgui_dc_draw_text(dc, tinfo.artist, &rect);
+
+	if ((tinfo.duration != 0) && player_mode != PLAYER_STOP)
+	{
+        rect.x1 = rect.x2 - 64;
+		rt_snprintf(line, sizeof(line), "%02d:%02d:%02d",
+			tinfo.duration / 360, tinfo.duration / 60, tinfo.duration % 60);
+        rtgui_dc_draw_text(dc, line, &rect);
+	}
+
+	rtgui_dc_set_color(dc, saved);
+}
+
+void play_mp3_file(const char* fn)
+{
+	struct rtgui_dc* dc;
+
+    /* get music tag information */
+    mp3_get_info(fn, &tinfo);
+    if (tinfo.title[0] == '\0')
+        rt_snprintf(tinfo.title, sizeof(tinfo.title), "<未知名音乐>");
+	
+	/* set player mode */
+	player_mode = PLAYER_PLAY_FILE;
+
+	dc = rtgui_dc_begin_drawing(RTGUI_WIDGET(home_view));
+	if (dc != RT_NULL)
+	{
+		rtgui_rect_t play_rect;
+		rtgui_image_t *button;
+		
+		/* update tag information */
+		player_update_tag_info(dc);
+
+		/* update play button */
+		button = rtgui_image_create_from_mem("hdc",
+            play_hdh, sizeof(play_hdh), RT_FALSE);
+        play_rect.x1 = 32; play_rect.y1 = 92;
+        play_rect.x2 = 61; play_rect.y2 = 114;
+        rtgui_image_blit(button, dc, &play_rect);
+        rtgui_image_destroy(button);
+
+		rtgui_dc_end_drawing(dc);
+	}
+
+    rtgui_view_show(home_view, RT_FALSE);
+
+	rt_kprintf("play file: %s\n", fn);
+    player_play_file(fn);
+}
+
+void function_filelist(void* parameter)
+{
+	rtgui_rect_t rect;
+	filelist_view_t *view;
+
+	rtgui_widget_get_rect(RTGUI_WIDGET(workbench), &rect);
+	view = filelist_view_create(workbench, "/", "*.*", &rect);
+	if (view != RT_NULL)
+	{
+	    if (rtgui_view_show(RTGUI_VIEW(view), RT_TRUE) == RTGUI_MODAL_OK)
+	    {
+			char fn[64];
+
+            /* get open file */
+            rt_snprintf(fn, 64, "%s/%s", view->current_directory,
+                view->items[view->current_item].name);
+
+            if (strstr(view->items[view->current_item].name , ".mp3") != RT_NULL ||
+                strstr(view->items[view->current_item].name , ".MP3") != RT_NULL)
+            {
+				/* clear old play list */
+				play_list_clear();
+				play_list_append(fn);
+
+			    player_mode = PLAYER_PLAY_FILE;
+				next_step = PLAYER_STEP_STOP;
+				play_mp3_file(play_list_start());
+            }
+            else if (strstr(view->items[view->current_item].name , ".m3u") != RT_NULL ||
+                strstr(view->items[view->current_item].name , ".M3U") != RT_NULL)
+            {
+                /* read all of music filename to a list */
+                int fd;
+                char line[64];
+
+                fd = open(fn, O_RDONLY, 0);
+                if (fd >= 0)
+                {
+                    rt_uint32_t length;
+
+                    length = read_line(fd, line, sizeof(line));
+                    if (strcmp(line, "#EXTM3U") == 0)
+                    {
+						/* clear old play list */
+						play_list_clear();
+
+                        do
+                        {
+                            length = read_line(fd, line, sizeof(line));
+                            if (length > 0)
+                            {
+                                if (line[0] != '/')
+                                {
+                                    rt_snprintf(fn, sizeof(fn),
+                                        "%s/%s", view->current_directory, line);
+                                    play_list_append(fn);
+                                }
+                                else play_list_append(line);
+                            }
+                        } while (length > 0);
+                    }
+
+                    close(fd);
+
+					if (play_list_items() > 0)
+					{
+					    player_mode = PLAYER_PLAY_FILE;
+						next_step = PLAYER_STEP_NEXT;
+		                play_mp3_file(play_list_start());
+					}
+                }
+            }
+            else if (strstr(view->items[view->current_item].name , ".wav") != RT_NULL ||
+                strstr(view->items[view->current_item].name , ".WAV") != RT_NULL)
+            {
+            }
+	    }
+
+		/* destroy view */
+		filelist_view_destroy(view);
+	}
+
+	return;
+}
+
+void function_device(void* parameter)
+{
+	rtgui_view_t *view;
+	extern rtgui_view_t* device_view_create(rtgui_workbench_t* workbench);
+
+	view = device_view_create(workbench);
+	if (view != RT_NULL)
+	{
+	    rtgui_view_show(view, RT_FALSE);
+	}
+
+	return;
+}
+
+void function_player(void* parameter)
+{
+    rtgui_view_show(home_view, RT_FALSE);
+	return;
+}
+
+void function_action(void* parameter)
+{
+	rt_kprintf("item action!\n");
+	return;
+}
+
+struct list_item function_list[] =
+{
+	{"选择电台", RT_NULL, function_action, RT_NULL},
+	{"更新电台", RT_NULL, function_action, RT_NULL},
+	{"播放文件", RT_NULL, function_filelist, RT_NULL},
+	{"设备信息", RT_NULL, function_device, RT_NULL},
+	{"选项设置", RT_NULL, function_action, RT_NULL},
+	{"返回播放器", RT_NULL, function_player, RT_NULL},
+};
+
+static rt_bool_t home_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;
+		rtgui_color_t saved;
+
+		dc = rtgui_dc_begin_drawing(widget);
+		if (dc == RT_NULL) return RT_FALSE;
+		rtgui_widget_get_rect(widget, &rect);
+		saved = RTGUI_WIDGET_FOREGROUND(widget);
+
+		/* draw background */
+	    background = rtgui_image_create_from_file("hdc",
+	        "/resource/bg.hdc", RT_FALSE);
+		if (background != RT_NULL)
+		{
+            rtgui_image_t *play;
+            rtgui_rect_t  play_rect;
+
+            rtgui_image_blit(background, dc, &rect);
+			rtgui_image_destroy(background);
+
+			background = RT_NULL;
+
+			if (player_mode == PLAYER_STOP)
+				play = rtgui_image_create_from_mem("hdc",
+	                stop_hdh, sizeof(stop_hdh), RT_FALSE);
+			else
+				play = rtgui_image_create_from_mem("hdc",
+	                play_hdh, sizeof(play_hdh), RT_FALSE);
+            play_rect.x1 = 32; play_rect.y1 = 92;
+            play_rect.x2 = 61; play_rect.y2 = 114;
+            rtgui_image_blit(play, dc, &play_rect);
+            rtgui_image_destroy(play);
+		}
+		else
+		{
+			rtgui_dc_fill_rect(dc, &rect);
+		}
+
+		/* draw playing information */
+		rtgui_dc_set_color(dc, black);
+        {
+            char line[32];
+
+            rect.x1 = 28; rect.y1 = 12;
+            rect.x2 = 220; rect.y2 = rect.y1 + 16;
+			if (player_mode == PLAYER_STOP)
+			{
+				rt_snprintf(line, sizeof(line),
+					"网络收音机");
+			    rtgui_dc_draw_text(dc, line, &rect);
+			}
+			else
+			    rtgui_dc_draw_text(dc, tinfo.title, &rect);
+
+            rect.x1 = 28; rect.y1 = 39;
+            rect.x2 = 220; rect.y2 = 59;
+			if (player_mode == PLAYER_STOP)
+			{
+				rt_snprintf(line, sizeof(line),
+					"radio.rt-thread.org");
+			    rtgui_dc_draw_text(dc, line, &rect);
+			}
+			else
+			    rtgui_dc_draw_text(dc, tinfo.artist, &rect);
+
+			if (tinfo.duration != 0)
+			{
+	            rect.x1 = rect.x2 - 64;
+				rt_snprintf(line, sizeof(line), "%02d:%02d:%02d",
+					tinfo.duration / 360, tinfo.duration / 60, tinfo.duration % 60);
+	            rtgui_dc_draw_text(dc, line, &rect);
+			}
+        }
+
+		RTGUI_WIDGET_FOREGROUND(widget) = RTGUI_RGB(82, 199, 16);
+		rtgui_dc_draw_hline(dc, 14, 226, 75);
+
+		RTGUI_WIDGET_FOREGROUND(widget) = saved;
+
+		if (player_mode == PLAYER_PLAY_FILE)
+		{
+			char line[32];
+			rt_uint32_t index;
+			struct play_item* item;
+
+			rect.x1 = 20; rect.y1 = 150;
+			rect.x2 = 220; rect.y2 = 168;
+			for (index = 0; index < play_list_items() && index < 8; index ++)
+			{
+				item = play_list_item(index);
+				rtgui_dc_draw_text(dc, item->title, &rect);
+
+	            rect.x1 = rect.x2 - 64;
+				rt_snprintf(line, sizeof(line), "%02d:%02d:%02d",
+					item->duration / 360,
+					item->duration / 60,
+					item->duration % 60);
+	            rtgui_dc_draw_text(dc, line, &rect);
+
+				/* move to next item */
+				rect.x1 = 20;
+				rect.y1 += 18; rect.y2 += 18;
+			}
+		}
+		rtgui_dc_end_drawing(dc);
+
+		return RT_FALSE;
+	}
+	else if (event->type == RTGUI_EVENT_KBD)
+	{
+		struct rtgui_event_kbd* ekbd = (struct rtgui_event_kbd*)event;
+		if (ekbd->type == RTGUI_KEYDOWN)
+		{
+			switch (ekbd->key)
+			{
+			case RTGUIK_RIGHT:
+                if (player_mode == PLAYER_PLAY_FILE && play_list_items() > 0)
+                {
+					player_stop();
+					next_step = PLAYER_STEP_NEXT;
+                }
+                break;
+			case RTGUIK_LEFT:
+                if (player_mode == PLAYER_PLAY_FILE && play_list_items() > 0)
+                {
+					player_stop();
+					next_step = PLAYER_STEP_PREV;
+                }
+				break;
+
+			case RTGUIK_RETURN:
+				if (player_is_playing() == RT_TRUE)
+				{
+					player_stop();
+					next_step = PLAYER_STEP_STOP;
+				}
+				else
+				{
+					if ((player_mode == PLAYER_STOP) && (play_list_items() > 0))
+					{
+						next_step = PLAYER_STEP_NEXT;
+						play_mp3_file(play_list_current_item());
+					}
+				}
+				break;
+
+			case RTGUIK_DOWN:
+                rtgui_view_show(function_view, RT_FALSE);
+				break;
+			}
+		}
+		return RT_FALSE;
+	}
+	else if (event->type == RTGUI_EVENT_COMMAND)
+	{
+		struct rtgui_event_command* ecmd = (struct rtgui_event_command*)event;
+
+		switch (ecmd->command_id)
+		{
+		case PLAYER_REQUEST_PLAY_SINGLE_FILE:
+		case PLAYER_REQUEST_PLAY_LIST:
+			rtgui_timer_start(info_timer);
+			break;
+		case PLAYER_REQUEST_STOP:
+		{
+			rtgui_timer_stop(info_timer);
+
+			switch (next_step)
+			{
+			case PLAYER_STEP_STOP:
+			{
+				struct rtgui_dc* dc;
+				rtgui_color_t saved;
+	            rtgui_image_t *button;
+	            rtgui_rect_t  play_rect;
+
+				player_mode = PLAYER_STOP;
+
+				dc = rtgui_dc_begin_drawing(widget);
+				if (dc == RT_NULL) return RT_FALSE;
+	
+				player_update_tag_info(dc);
+
+				RTGUI_WIDGET_FOREGROUND(widget) = RTGUI_RGB(82, 199, 16);
+				rtgui_dc_draw_hline(dc, 14, 226, 75);
+	
+				/* update play button */
+				button = rtgui_image_create_from_mem("hdc",
+	                stop_hdh, sizeof(stop_hdh), RT_FALSE);
+	            play_rect.x1 = 32; play_rect.y1 = 92;
+	            play_rect.x2 = 61; play_rect.y2 = 114;
+	            rtgui_image_blit(button, dc, &play_rect);
+	            rtgui_image_destroy(button);
+	
+				RTGUI_WIDGET_FOREGROUND(widget) = saved;
+				rtgui_dc_end_drawing(dc);
+			}
+				break;
+			case PLAYER_STEP_NEXT:
+				if (play_list_is_end() == RT_TRUE)
+				{
+					struct rtgui_dc* dc;
+					rtgui_color_t saved;
+		            rtgui_image_t *button;
+		            rtgui_rect_t  play_rect;
+	
+					/* set stat */
+					next_step = PLAYER_STEP_STOP;
+					player_mode = PLAYER_STOP;
+
+					/* update UI */
+					dc = rtgui_dc_begin_drawing(widget);
+					if (dc == RT_NULL) return RT_FALSE;
+
+					player_update_tag_info(dc);
+
+					RTGUI_WIDGET_FOREGROUND(widget) = RTGUI_RGB(82, 199, 16);
+					rtgui_dc_draw_hline(dc, 14, 226, 75);
+
+					/* update play button */
+					button = rtgui_image_create_from_mem("hdc",
+		                stop_hdh, sizeof(stop_hdh), RT_FALSE);
+		            play_rect.x1 = 32; play_rect.y1 = 92;
+		            play_rect.x2 = 61; play_rect.y2 = 114;
+		            rtgui_image_blit(button, dc, &play_rect);
+		            rtgui_image_destroy(button);
+
+					RTGUI_WIDGET_FOREGROUND(widget) = saved;
+					rtgui_dc_end_drawing(dc);
+				}
+				else
+				{
+	                play_mp3_file(play_list_next());
+					next_step = PLAYER_STEP_NEXT;
+				}
+				break;
+
+			case PLAYER_STEP_PREV:
+				play_mp3_file(play_list_prev());
+				next_step = PLAYER_STEP_NEXT;
+				break;
+			};
+		}
+			break;
+
+		default:
+			break;
+		}
+
+		return RT_FALSE;
+	}
+
+	return rtgui_view_event_handler(widget, event);
+}
+
+rt_bool_t player_workbench_event_handler(rtgui_widget_t *widget, rtgui_event_t *event)
+{
+    if (event->type == RTGUI_EVENT_KBD)
+    {
+        struct rtgui_event_kbd* ekbd = (struct rtgui_event_kbd*)event;
+        if ((ekbd->type == RTGUI_KEYUP) && ekbd->key == RTGUIK_HOME)
+        {
+            /* active home view */
+            if (workbench->current_view != home_view)
+            {
+                rtgui_view_show(home_view, RT_FALSE);
+                return RT_FALSE;
+            }
+        }
+    }
+
+    return rtgui_workbench_event_handler(widget, event);
+}
+
+static void player_entry(void* parameter)
+{
+	rt_mq_t mq;
+	rtgui_rect_t rect;
+
+	mq = rt_mq_create("ply_ui", 256, 4, RT_IPC_FLAG_FIFO);
+	rtgui_thread_register(rt_thread_self(), mq);
+
+	/* create information timer */
+	info_timer = rtgui_timer_create(RT_TICK_PER_SECOND,
+		RT_TIMER_FLAG_PERIODIC,
+		info_timer_timeout, RT_NULL);
+
+	workbench = rtgui_workbench_create("main", "workbench");
+	if (workbench == RT_NULL) return;
+	rtgui_widget_set_event_handler(RTGUI_WIDGET(workbench), player_workbench_event_handler);
+
+    /* add home view */
+	home_view = rtgui_view_create("Home");
+	rtgui_widget_set_event_handler(RTGUI_WIDGET(home_view), home_view_event_handler);
+
+	rtgui_workbench_add_view(workbench, home_view);
+	/* this view can be focused */
+	RTGUI_WIDGET(home_view)->flag |= RTGUI_WIDGET_FLAG_FOCUSABLE;
+	/* set widget focus */
+	rtgui_widget_focus(RTGUI_WIDGET(home_view));
+
+	rtgui_view_show(home_view, RT_FALSE);
+
+    /* add function view */
+	rtgui_widget_get_rect(RTGUI_WIDGET(workbench), &rect);
+	function_view = (struct rtgui_view*)list_view_create(function_list,
+		sizeof(function_list)/sizeof(struct list_item),
+		&rect);
+	rtgui_workbench_add_view(workbench, function_view);
+
+	rtgui_workbench_event_loop(workbench);
+
+	rtgui_thread_deregister(rt_thread_self());
+	rt_mq_delete(mq);
+}
+
+void player_notify_play(void)
+{
+    struct rtgui_event_command ecmd;
+    RTGUI_EVENT_COMMAND_INIT(&ecmd);
+    ecmd.type = RTGUI_CMD_USER_INT;
+    ecmd.command_id = PLAYER_REQUEST_PLAY_SINGLE_FILE;
+
+    rtgui_thread_send(player_ui_tid, &ecmd.parent, sizeof(ecmd));
+}
+
+void player_notify_stop()
+{
+    struct rtgui_event_command ecmd;
+    RTGUI_EVENT_COMMAND_INIT(&ecmd);
+    ecmd.type = RTGUI_CMD_USER_INT;
+    ecmd.command_id = PLAYER_REQUEST_STOP;
+
+    rtgui_thread_send(player_ui_tid, &ecmd.parent, sizeof(ecmd));
+}
+
+void player_ui_init()
+{
+	player_ui_tid = rt_thread_create("ply_ui", player_entry, RT_NULL,
+		4096, 25, 5);
+	if (player_ui_tid != RT_NULL)
+		rt_thread_startup(player_ui_tid);
+}
diff --git a/bsp/stm32_radio/player_ui.h b/bsp/stm32_radio/player_ui.h
new file mode 100644
index 0000000000000000000000000000000000000000..50d4e0ce7df606d446dadf79c4923ae95874bcba
--- /dev/null
+++ b/bsp/stm32_radio/player_ui.h
@@ -0,0 +1,47 @@
+#ifndef __PLAYER_H__
+#define __PLAYER_H__
+
+#include <rtthread.h>
+
+/* music tag information structure */
+struct tag_info
+{
+	char title [40];        /* music title              */
+	char artist[40];        /* music artist             */
+
+	rt_uint32_t duration;   /* music total duration (second)   */
+	rt_uint32_t position;   /* music current position (second) */
+
+	rt_uint32_t bit_rate;   /* bit rate                 */
+	rt_uint32_t sampling;   /* sampling                 */
+	rt_uint32_t data_start; /* start position of data   */
+};
+
+enum PLAYER_CMD
+{
+    PLAYER_CMD_START,
+    PLAYER_CMD_STOP
+};
+
+enum PLAYER_MODE
+{
+    PLAYER_STOP,
+	PLAYER_PLAY_FILE,
+	PLAYER_PLAY_RADIO,
+};
+
+enum PLAYER_STEP
+{
+	PLAYER_STEP_STOP,
+	PLAYER_STEP_PREV,
+	PLAYER_STEP_NEXT,
+};
+
+void player_ui_init(void);
+
+void player_notify_play(void);
+void player_notify_stop(void);
+
+void player_set_position(rt_uint32_t position);
+
+#endif
diff --git a/bsp/stm32_radio/project.Opt b/bsp/stm32_radio/project.Opt
index 79329c24e4959d1b9b1c8eadd2a45210a3c1a282..70bc14f1574d1d63944064aa0fd548c0b07d669f 100644
--- a/bsp/stm32_radio/project.Opt
+++ b/bsp/stm32_radio/project.Opt
@@ -11,7 +11,7 @@
  DaveTm { 0,0,0,0,0,0,0,0 }
 
 Target (RT-Thread STM32 Radio), 0x0004 // Tools: 'ARM-ADS'
-GRPOPT 1,(Startup),0,0,0
+GRPOPT 1,(Startup),1,0,0
 GRPOPT 2,(Kernel),0,0,0
 GRPOPT 3,(STM32),0,0,0
 GRPOPT 4,(StdPeriph_Driver),0,0,0
@@ -27,191 +27,195 @@ OPTFFF 1,2,5,0,0,0,0,0,<.\board.h><board.h>
 OPTFFF 1,3,5,0,0,0,0,0,<.\stm32f10x_conf.h><stm32f10x_conf.h> 
 OPTFFF 1,4,1,0,0,0,0,0,<.\application.c><application.c> 
 OPTFFF 1,5,1,0,0,0,0,0,<.\board.c><board.c> 
-OPTFFF 1,6,1,335544320,0,0,0,0,<.\startup.c><startup.c> 
+OPTFFF 1,6,1,0,0,0,0,0,<.\startup.c><startup.c> 
 OPTFFF 1,7,1,0,0,0,0,0,<.\stm32f10x_it.c><stm32f10x_it.c> 
 OPTFFF 1,8,1,0,0,0,0,0,<.\usart.c><usart.c> 
-OPTFFF 1,9,1,0,0,0,0,0,<.\sdcard.c><sdcard.c> 
+OPTFFF 1,9,1,402653184,0,0,0,0,<.\sdcard.c><sdcard.c> 
 OPTFFF 1,10,1,0,0,0,0,0,<.\rtc.c><rtc.c> 
-OPTFFF 1,11,1,0,0,0,0,0,<.\wm8753.c><wm8753.c> 
-OPTFFF 1,12,1,0,0,0,0,0,<.\dm9000.c><dm9000.c> 
-OPTFFF 1,13,1,889192448,0,0,0,0,<.\fsmc_nand.c><fsmc_nand.c> 
-OPTFFF 1,14,1,0,0,0,0,0,<.\fsmc_sram.c><fsmc_sram.c> 
-OPTFFF 1,15,1,0,0,0,0,0,<.\fmt0371\fmt0371.c><fmt0371.c> 
-OPTFFF 1,16,1,0,0,0,0,0,<.\http.c><http.c> 
-OPTFFF 1,17,1,0,0,0,0,0,<.\lcd.c><lcd.c> 
-OPTFFF 1,18,1,620756992,0,0,0,0,<.\mp3.c><mp3.c> 
-OPTFFF 1,19,1,369098752,0,0,0,0,<.\wav.c><wav.c> 
-OPTFFF 1,20,1,620756992,0,0,0,0,<.\netbuffer.c><netbuffer.c> 
-OPTFFF 1,21,1,0,0,0,0,0,<.\key.c><key.c> 
-OPTFFF 1,22,1,0,0,0,0,0,<.\info.c><info.c> 
-OPTFFF 1,23,1,0,0,0,0,0,<E:\Projects\opensvn\rt-thread\google\bsp\stm32_radio\player.c><player.c> 
-OPTFFF 1,24,1,0,0,0,0,0,<.\filelist.c><filelist.c> 
-OPTFFF 1,25,1,0,0,0,0,0,<.\device_info.c><device_info.c> 
-OPTFFF 1,26,1,0,0,0,0,0,<.\listview.c><listview.c> 
-OPTFFF 2,27,1,0,0,0,0,0,<..\..\src\clock.c><clock.c> 
-OPTFFF 2,28,1,0,0,0,0,0,<..\..\src\idle.c><idle.c> 
-OPTFFF 2,29,1,671088640,0,0,0,0,<..\..\src\ipc.c><ipc.c> 
-OPTFFF 2,30,1,0,0,0,0,0,<..\..\src\mempool.c><mempool.c> 
-OPTFFF 2,31,1,0,0,0,0,0,<..\..\src\mem.c><mem.c> 
-OPTFFF 2,32,1,0,0,0,0,0,<..\..\src\object.c><object.c> 
-OPTFFF 2,33,1,0,0,0,0,0,<..\..\src\scheduler.c><scheduler.c> 
-OPTFFF 2,34,1,285212672,0,0,0,0,<..\..\src\thread.c><thread.c> 
-OPTFFF 2,35,1,0,0,0,0,0,<..\..\src\timer.c><timer.c> 
-OPTFFF 2,36,1,0,0,0,0,0,<..\..\src\irq.c><irq.c> 
-OPTFFF 2,37,1,0,0,0,0,0,<..\..\src\kservice.c><kservice.c> 
-OPTFFF 2,38,1,0,0,0,0,0,<..\..\src\device.c><device.c> 
-OPTFFF 2,39,1,0,0,0,0,0,<..\..\src\slab.c><slab.c> 
-OPTFFF 3,40,1,0,0,0,0,0,<..\..\libcpu\arm\stm32\stack.c><stack.c> 
-OPTFFF 3,41,1,0,0,0,0,0,<..\..\libcpu\arm\stm32\interrupt.c><interrupt.c> 
-OPTFFF 3,42,1,0,0,0,0,0,<..\..\libcpu\arm\stm32\cpu.c><cpu.c> 
-OPTFFF 3,43,1,0,0,0,0,0,<..\..\libcpu\arm\stm32\serial.c><serial.c> 
-OPTFFF 3,44,2,0,0,0,0,0,<..\..\libcpu\arm\stm32\context_rvds.S><context_rvds.S> 
-OPTFFF 3,45,2,570425344,0,0,0,0,<..\..\libcpu\arm\stm32\start_rvds.s><start_rvds.s> 
-OPTFFF 3,46,1,0,0,0,0,0,<..\..\libcpu\arm\stm32\fault.c><fault.c> 
-OPTFFF 3,47,2,0,0,0,0,0,<..\..\libcpu\arm\stm32\fault_rvds.S><fault_rvds.S> 
-OPTFFF 4,48,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\misc.c><misc.c> 
-OPTFFF 4,49,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_adc.c><stm32f10x_adc.c> 
-OPTFFF 4,50,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_bkp.c><stm32f10x_bkp.c> 
-OPTFFF 4,51,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_can.c><stm32f10x_can.c> 
-OPTFFF 4,52,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_crc.c><stm32f10x_crc.c> 
-OPTFFF 4,53,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_dac.c><stm32f10x_dac.c> 
-OPTFFF 4,54,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_dbgmcu.c><stm32f10x_dbgmcu.c> 
-OPTFFF 4,55,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_dma.c><stm32f10x_dma.c> 
-OPTFFF 4,56,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_exti.c><stm32f10x_exti.c> 
-OPTFFF 4,57,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_flash.c><stm32f10x_flash.c> 
-OPTFFF 4,58,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_fsmc.c><stm32f10x_fsmc.c> 
-OPTFFF 4,59,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_gpio.c><stm32f10x_gpio.c> 
-OPTFFF 4,60,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_i2c.c><stm32f10x_i2c.c> 
-OPTFFF 4,61,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_iwdg.c><stm32f10x_iwdg.c> 
-OPTFFF 4,62,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_pwr.c><stm32f10x_pwr.c> 
-OPTFFF 4,63,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_rcc.c><stm32f10x_rcc.c> 
-OPTFFF 4,64,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_rtc.c><stm32f10x_rtc.c> 
-OPTFFF 4,65,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_sdio.c><stm32f10x_sdio.c> 
-OPTFFF 4,66,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_spi.c><stm32f10x_spi.c> 
-OPTFFF 4,67,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_tim.c><stm32f10x_tim.c> 
-OPTFFF 4,68,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_usart.c><stm32f10x_usart.c> 
-OPTFFF 4,69,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_wwdg.c><stm32f10x_wwdg.c> 
-OPTFFF 5,70,1,0,0,0,0,0,<.\Libraries\CMSIS\Core\CM3\core_cm3.c><core_cm3.c> 
-OPTFFF 5,71,1,0,0,0,0,0,<.\Libraries\CMSIS\Core\CM3\system_stm32f10x.c><system_stm32f10x.c> 
-OPTFFF 6,72,1,0,0,0,0,0,<..\..\finsh\finsh_compiler.c><finsh_compiler.c> 
-OPTFFF 6,73,1,0,0,0,0,0,<..\..\finsh\finsh_error.c><finsh_error.c> 
-OPTFFF 6,74,1,0,0,0,0,0,<..\..\finsh\finsh_heap.c><finsh_heap.c> 
-OPTFFF 6,75,1,0,0,0,0,0,<..\..\finsh\finsh_init.c><finsh_init.c> 
-OPTFFF 6,76,1,0,0,0,0,0,<..\..\finsh\finsh_node.c><finsh_node.c> 
-OPTFFF 6,77,1,0,0,0,0,0,<..\..\finsh\finsh_ops.c><finsh_ops.c> 
-OPTFFF 6,78,1,0,0,0,0,0,<..\..\finsh\finsh_parser.c><finsh_parser.c> 
-OPTFFF 6,79,1,0,0,0,0,0,<..\..\finsh\finsh_token.c><finsh_token.c> 
-OPTFFF 6,80,1,0,0,0,0,0,<..\..\finsh\finsh_var.c><finsh_var.c> 
-OPTFFF 6,81,1,0,0,0,0,0,<..\..\finsh\finsh_vm.c><finsh_vm.c> 
-OPTFFF 6,82,1,0,0,0,0,0,<..\..\finsh\shell.c><shell.c> 
-OPTFFF 6,83,1,0,0,0,0,0,<..\..\finsh\symbol.c><symbol.c> 
-OPTFFF 6,84,1,285212672,0,0,0,0,<..\..\finsh\cmd.c><cmd.c> 
-OPTFFF 7,85,1,0,0,0,0,0,<..\..\filesystem\dfs\src\dfs_init.c><dfs_init.c> 
-OPTFFF 7,86,1,503316480,0,0,0,0,<..\..\filesystem\dfs\src\dfs_fs.c><dfs_fs.c> 
-OPTFFF 7,87,1,0,0,0,0,0,<..\..\filesystem\dfs\src\dfs_raw.c><dfs_raw.c> 
-OPTFFF 7,88,1,0,0,0,0,0,<..\..\filesystem\dfs\src\dfs_util.c><dfs_util.c> 
-OPTFFF 7,89,1,0,0,0,0,0,<..\..\filesystem\dfs\src\dfs_posix.c><dfs_posix.c> 
-OPTFFF 7,90,1,0,0,0,0,0,<..\..\filesystem\dfs\filesystems\efsl\src\fs\vfat\dir.c><dir.c> 
-OPTFFF 7,91,1,0,0,0,0,0,<..\..\filesystem\dfs\filesystems\efsl\src\fs\vfat\fat.c><fat.c> 
-OPTFFF 7,92,1,0,0,0,0,0,<..\..\filesystem\dfs\filesystems\efsl\src\fs\vfat\file.c><file.c> 
-OPTFFF 7,93,1,0,0,0,0,0,<..\..\filesystem\dfs\filesystems\efsl\src\fs\vfat\fs.c><fs.c> 
-OPTFFF 7,94,1,0,0,0,0,0,<..\..\filesystem\dfs\filesystems\efsl\src\fs\vfat\ls.c><ls.c> 
-OPTFFF 7,95,1,0,0,0,0,0,<..\..\filesystem\dfs\filesystems\efsl\src\fs\vfat\time.c><time.c> 
-OPTFFF 7,96,1,0,0,0,0,0,<..\..\filesystem\dfs\filesystems\efsl\src\fs\vfat\ui.c><ui.c> 
-OPTFFF 7,97,1,0,0,0,0,0,<..\..\filesystem\dfs\filesystems\efsl\src\base\plibc.c><plibc.c> 
-OPTFFF 7,98,1,0,0,0,0,0,<..\..\filesystem\dfs\filesystems\efsl\src\base\efs.c><efs.c> 
-OPTFFF 7,99,1,0,0,0,0,0,<..\..\filesystem\dfs\filesystems\efsl\src\base\extract.c><extract.c> 
-OPTFFF 7,100,1,0,0,0,0,0,<..\..\filesystem\dfs\filesystems\efsl\src\base\partition.c><partition.c> 
-OPTFFF 7,101,1,0,0,0,0,0,<..\..\filesystem\dfs\src\dfs_cache.c><dfs_cache.c> 
-OPTFFF 8,102,1,0,0,0,0,0,<..\..\net\lwip\src\core\dhcp.c><dhcp.c> 
-OPTFFF 8,103,1,0,0,0,0,0,<..\..\net\lwip\src\core\dns.c><dns.c> 
-OPTFFF 8,104,1,0,0,0,0,0,<..\..\net\lwip\src\core\init.c><init.c> 
-OPTFFF 8,105,1,0,0,0,0,0,<..\..\net\lwip\src\core\netif.c><netif.c> 
-OPTFFF 8,106,1,0,0,0,0,0,<..\..\net\lwip\src\core\pbuf.c><pbuf.c> 
-OPTFFF 8,107,1,0,0,0,0,0,<..\..\net\lwip\src\core\raw.c><raw.c> 
-OPTFFF 8,108,1,0,0,0,0,0,<..\..\net\lwip\src\core\stats.c><stats.c> 
-OPTFFF 8,109,1,0,0,0,0,0,<..\..\net\lwip\src\core\sys.c><sys.c> 
-OPTFFF 8,110,1,0,0,0,0,0,<..\..\net\lwip\src\core\tcp.c><tcp.c> 
-OPTFFF 8,111,1,0,0,0,0,0,<..\..\net\lwip\src\core\tcp_in.c><tcp_in.c> 
-OPTFFF 8,112,1,0,0,0,0,0,<..\..\net\lwip\src\core\tcp_out.c><tcp_out.c> 
-OPTFFF 8,113,1,0,0,0,0,0,<..\..\net\lwip\src\core\udp.c><udp.c> 
-OPTFFF 8,114,1,0,0,0,0,0,<..\..\net\lwip\src\core\ipv4\autoip.c><autoip.c> 
-OPTFFF 8,115,1,0,0,0,0,0,<..\..\net\lwip\src\core\ipv4\icmp.c><icmp.c> 
-OPTFFF 8,116,1,0,0,0,0,0,<..\..\net\lwip\src\core\ipv4\igmp.c><igmp.c> 
-OPTFFF 8,117,1,0,0,0,0,0,<..\..\net\lwip\src\core\ipv4\inet.c><inet.c> 
-OPTFFF 8,118,1,0,0,0,0,0,<..\..\net\lwip\src\core\ipv4\inet_chksum.c><inet_chksum.c> 
-OPTFFF 8,119,1,0,0,0,0,0,<..\..\net\lwip\src\core\ipv4\ip.c><ip.c> 
-OPTFFF 8,120,1,0,0,0,0,0,<..\..\net\lwip\src\core\ipv4\ip_addr.c><ip_addr.c> 
-OPTFFF 8,121,1,285212672,0,0,0,0,<..\..\net\lwip\src\core\ipv4\ip_frag.c><ip_frag.c> 
-OPTFFF 8,122,1,0,0,0,0,0,<..\..\net\lwip\src\core\snmp\msg_in.c><msg_in.c> 
-OPTFFF 8,123,1,0,0,0,0,0,<..\..\net\lwip\src\core\snmp\msg_out.c><msg_out.c> 
-OPTFFF 8,124,1,0,0,0,0,0,<..\..\net\lwip\src\api\api_lib.c><api_lib.c> 
-OPTFFF 8,125,1,50331648,0,0,0,0,<..\..\net\lwip\src\api\api_msg.c><api_msg.c> 
-OPTFFF 8,126,1,0,0,0,0,0,<..\..\net\lwip\src\api\err.c><err.c> 
-OPTFFF 8,127,1,0,0,0,0,0,<..\..\net\lwip\src\api\netbuf.c><netbuf.c> 
-OPTFFF 8,128,1,0,0,0,0,0,<..\..\net\lwip\src\api\netdb.c><netdb.c> 
-OPTFFF 8,129,1,0,0,0,0,0,<..\..\net\lwip\src\api\netifapi.c><netifapi.c> 
-OPTFFF 8,130,1,0,0,0,0,0,<..\..\net\lwip\src\api\tcpip.c><tcpip.c> 
-OPTFFF 8,131,1,0,0,0,0,0,<..\..\net\lwip\src\netif\etharp.c><etharp.c> 
-OPTFFF 8,132,1,150994944,0,0,0,0,<..\..\net\lwip\src\netif\ethernetif.c><ethernetif.c> 
-OPTFFF 8,133,1,0,0,0,0,0,<..\..\net\lwip\src\netif\loopif.c><loopif.c> 
-OPTFFF 8,134,1,285212672,0,0,0,0,<..\..\net\lwip\src\arch\sys_arch_init.c><sys_arch_init.c> 
-OPTFFF 8,135,1,0,0,0,0,0,<..\..\net\lwip\src\arch\sys_arch.c><sys_arch.c> 
-OPTFFF 8,136,1,0,0,0,0,0,<..\..\net\lwip\src\api\sockets.c><sockets.c> 
-OPTFFF 8,137,1,0,0,0,0,0,<..\..\net\lwip\src\core\memp_tiny.c><memp_tiny.c> 
-OPTFFF 9,138,1,268435456,0,0,0,0,<.\mp3\mp3dec.c><mp3dec.c> 
-OPTFFF 9,139,1,0,0,0,0,0,<.\mp3\mp3tabs.c><mp3tabs.c> 
-OPTFFF 9,140,1,0,0,0,0,0,<.\mp3\real\bitstream.c><bitstream.c> 
-OPTFFF 9,141,1,83886080,0,0,0,0,<.\mp3\real\buffers.c><buffers.c> 
-OPTFFF 9,142,1,0,0,0,0,0,<.\mp3\real\dct32.c><dct32.c> 
-OPTFFF 9,143,1,0,0,0,0,0,<.\mp3\real\dequant.c><dequant.c> 
-OPTFFF 9,144,1,0,0,0,0,0,<.\mp3\real\dqchan.c><dqchan.c> 
-OPTFFF 9,145,1,0,0,0,0,0,<.\mp3\real\huffman.c><huffman.c> 
-OPTFFF 9,146,1,0,0,0,0,0,<.\mp3\real\hufftabs.c><hufftabs.c> 
-OPTFFF 9,147,1,0,0,0,0,0,<.\mp3\real\imdct.c><imdct.c> 
-OPTFFF 9,148,1,0,0,0,0,0,<.\mp3\real\scalfact.c><scalfact.c> 
-OPTFFF 9,149,1,0,0,0,0,0,<.\mp3\real\stproc.c><stproc.c> 
-OPTFFF 9,150,1,0,0,0,0,0,<.\mp3\real\subband.c><subband.c> 
-OPTFFF 9,151,1,0,0,0,0,0,<.\mp3\real\trigtabs.c><trigtabs.c> 
-OPTFFF 9,152,2,0,0,0,0,0,<.\mp3\real\arm\asmpoly_thumb2.s><asmpoly_thumb2.s> 
-OPTFFF 9,153,2,0,0,0,0,0,<.\mp3\real\arm\asmmisc.s><asmmisc.s> 
-OPTFFF 10,154,1,0,0,0,0,0,<..\..\rtgui\common\rtgui_object.c><rtgui_object.c> 
-OPTFFF 10,155,1,0,0,0,0,0,<..\..\rtgui\common\rtgui_system.c><rtgui_system.c> 
-OPTFFF 10,156,1,620756992,0,0,0,0,<..\..\rtgui\common\rtgui_theme.c><rtgui_theme.c> 
-OPTFFF 10,157,1,0,0,0,0,0,<..\..\rtgui\common\asc12font.c><asc12font.c> 
-OPTFFF 10,158,1,402653184,0,0,0,0,<..\..\rtgui\common\asc16font.c><asc16font.c> 
-OPTFFF 10,159,1,0,0,0,0,0,<..\..\rtgui\common\color.c><color.c> 
-OPTFFF 10,160,1,0,0,0,0,0,<..\..\rtgui\common\dc.c><dc.c> 
-OPTFFF 10,161,1,0,0,0,0,0,<..\..\rtgui\common\dc_buffer.c><dc_buffer.c> 
-OPTFFF 10,162,1,0,0,0,0,0,<..\..\rtgui\common\dc_hw.c><dc_hw.c> 
-OPTFFF 10,163,1,16777216,0,0,0,0,<..\..\rtgui\common\filerw.c><filerw.c> 
-OPTFFF 10,164,1,0,0,0,0,0,<..\..\rtgui\common\font.c><font.c> 
-OPTFFF 10,165,1,469762048,0,0,0,0,<..\..\rtgui\common\image.c><image.c> 
-OPTFFF 10,166,1,0,0,0,0,0,<..\..\rtgui\common\image_xpm.c><image_xpm.c> 
-OPTFFF 10,167,1,0,0,0,0,0,<..\..\rtgui\common\image_hdc.c><image_hdc.c> 
-OPTFFF 10,168,1,0,0,0,0,0,<..\..\rtgui\common\region.c><region.c> 
-OPTFFF 10,169,1,100663296,0,0,0,0,<..\..\rtgui\server\server.c><server.c> 
-OPTFFF 10,170,1,0,0,0,0,0,<..\..\rtgui\server\driver.c><driver.c> 
-OPTFFF 10,171,1,335544320,0,0,0,0,<..\..\rtgui\server\panel.c><panel.c> 
-OPTFFF 10,172,1,0,0,0,0,0,<..\..\rtgui\widgets\widget.c><widget.c> 
-OPTFFF 10,173,1,16777216,0,0,0,0,<..\..\rtgui\widgets\window.c><window.c> 
-OPTFFF 10,174,1,0,0,0,0,0,<..\..\rtgui\widgets\workbench.c><workbench.c> 
-OPTFFF 10,175,1,16777216,0,0,0,0,<..\..\rtgui\widgets\view.c><view.c> 
-OPTFFF 10,176,1,0,0,0,0,0,<..\..\rtgui\widgets\box.c><box.c> 
-OPTFFF 10,177,1,0,0,0,0,0,<..\..\rtgui\widgets\button.c><button.c> 
-OPTFFF 10,178,1,0,0,0,0,0,<..\..\rtgui\widgets\container.c><container.c> 
-OPTFFF 10,179,1,0,0,0,0,0,<..\..\rtgui\widgets\iconbox.c><iconbox.c> 
-OPTFFF 10,180,1,0,0,0,0,0,<..\..\rtgui\widgets\label.c><label.c> 
-OPTFFF 10,181,1,0,0,0,0,0,<..\..\rtgui\widgets\textbox.c><textbox.c> 
-OPTFFF 10,182,1,0,0,0,0,0,<..\..\rtgui\widgets\title.c><title.c> 
-OPTFFF 10,183,1,67108864,0,0,0,0,<..\..\rtgui\widgets\toplevel.c><toplevel.c> 
-OPTFFF 10,184,1,0,0,0,0,0,<..\..\rtgui\server\mouse.c><mouse.c> 
-OPTFFF 10,185,1,0,0,0,0,0,<..\..\rtgui\server\topwin.c><topwin.c> 
-OPTFFF 10,186,1,0,0,0,0,0,<..\..\rtgui\common\caret.c><caret.c> 
-OPTFFF 10,187,1,0,0,0,0,0,<..\..\rtgui\common\font_hz_file.c><font_hz_file.c> 
-OPTFFF 10,188,1,0,0,0,0,0,<..\..\rtgui\common\hz16font.c><hz16font.c> 
-OPTFFF 10,189,1,0,0,0,0,0,<..\..\rtgui\common\hz12font.c><hz12font.c> 
+OPTFFF 1,11,1,0,0,0,0,0,<.\dm9000.c><dm9000.c> 
+OPTFFF 1,12,1,889192448,0,0,0,0,<.\fsmc_nand.c><fsmc_nand.c> 
+OPTFFF 1,13,1,0,0,0,0,0,<.\fsmc_sram.c><fsmc_sram.c> 
+OPTFFF 1,14,1,0,0,0,0,0,<.\fmt0371\fmt0371.c><fmt0371.c> 
+OPTFFF 1,15,1,0,0,0,0,0,<.\http.c><http.c> 
+OPTFFF 1,16,1,0,0,0,0,0,<.\lcd.c><lcd.c> 
+OPTFFF 1,17,1,16777216,0,401,410,0,<.\mp3.c><mp3.c> { 44,0,0,0,0,0,0,0,1,0,0,0,255,255,255,255,255,255,255,255,252,255,255,255,226,255,255,255,22,0,0,0,29,0,0,0,164,2,0,0,145,1,0,0 }
+OPTFFF 1,18,1,369098752,0,0,0,0,<.\wav.c><wav.c> 
+OPTFFF 1,19,1,0,0,0,0,0,<.\netbuffer.c><netbuffer.c> 
+OPTFFF 1,20,1,0,0,0,0,0,<.\key.c><key.c> 
+OPTFFF 1,21,1,553648128,0,0,0,0,<.\info.c><info.c> 
+OPTFFF 1,22,1,0,0,0,0,0,<.\filelist.c><filelist.c> 
+OPTFFF 1,23,1,0,0,0,0,0,<.\device_info.c><device_info.c> 
+OPTFFF 1,24,1,0,0,0,0,0,<.\listview.c><listview.c> 
+OPTFFF 1,25,1,0,0,0,0,0,<.\wm8753.c><wm8753.c> 
+OPTFFF 1,26,1,3,0,481,487,0,<.\player_ui.c><player_ui.c> { 44,0,0,0,2,0,0,0,3,0,0,0,255,255,255,255,255,255,255,255,252,255,255,255,226,255,255,255,0,0,0,0,0,0,0,0,186,2,0,0,218,0,0,0 }
+OPTFFF 1,27,1,268435456,0,1,1,0,<.\player_bg.c><player_bg.c> { 44,0,0,0,0,0,0,0,1,0,0,0,255,255,255,255,255,255,255,255,252,255,255,255,226,255,255,255,66,0,0,0,87,0,0,0,252,2,0,0,49,1,0,0 }
+OPTFFF 1,28,1,0,0,0,0,0,<.\wm8978.c><wm8978.c> 
+OPTFFF 1,29,1,469762048,0,0,0,0,<.\play_list.c><play_list.c> 
+OPTFFF 2,30,1,0,0,0,0,0,<..\..\src\clock.c><clock.c> 
+OPTFFF 2,31,1,0,0,0,0,0,<..\..\src\idle.c><idle.c> 
+OPTFFF 2,32,1,0,0,0,0,0,<..\..\src\ipc.c><ipc.c> 
+OPTFFF 2,33,1,0,0,0,0,0,<..\..\src\mempool.c><mempool.c> 
+OPTFFF 2,34,1,0,0,0,0,0,<..\..\src\mem.c><mem.c> 
+OPTFFF 2,35,1,0,0,0,0,0,<..\..\src\object.c><object.c> 
+OPTFFF 2,36,1,0,0,0,0,0,<..\..\src\scheduler.c><scheduler.c> 
+OPTFFF 2,37,1,285212672,0,0,0,0,<..\..\src\thread.c><thread.c> 
+OPTFFF 2,38,1,0,0,0,0,0,<..\..\src\timer.c><timer.c> 
+OPTFFF 2,39,1,0,0,0,0,0,<..\..\src\irq.c><irq.c> 
+OPTFFF 2,40,1,0,0,0,0,0,<..\..\src\kservice.c><kservice.c> 
+OPTFFF 2,41,1,0,0,0,0,0,<..\..\src\device.c><device.c> 
+OPTFFF 2,42,1,0,0,0,0,0,<..\..\src\slab.c><slab.c> 
+OPTFFF 3,43,1,0,0,0,0,0,<..\..\libcpu\arm\stm32\stack.c><stack.c> 
+OPTFFF 3,44,1,0,0,0,0,0,<..\..\libcpu\arm\stm32\interrupt.c><interrupt.c> 
+OPTFFF 3,45,1,0,0,0,0,0,<..\..\libcpu\arm\stm32\cpu.c><cpu.c> 
+OPTFFF 3,46,1,0,0,0,0,0,<..\..\libcpu\arm\stm32\serial.c><serial.c> 
+OPTFFF 3,47,2,0,0,0,0,0,<..\..\libcpu\arm\stm32\context_rvds.S><context_rvds.S> 
+OPTFFF 3,48,2,0,0,13,19,0,<..\..\libcpu\arm\stm32\start_rvds.s><start_rvds.s> { 44,0,0,0,0,0,0,0,1,0,0,0,255,255,255,255,255,255,255,255,252,255,255,255,226,255,255,255,88,0,0,0,116,0,0,0,1,3,0,0,232,1,0,0 }
+OPTFFF 3,49,1,0,0,0,0,0,<..\..\libcpu\arm\stm32\fault.c><fault.c> 
+OPTFFF 3,50,2,0,0,0,0,0,<..\..\libcpu\arm\stm32\fault_rvds.S><fault_rvds.S> 
+OPTFFF 4,51,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\misc.c><misc.c> 
+OPTFFF 4,52,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_adc.c><stm32f10x_adc.c> 
+OPTFFF 4,53,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_bkp.c><stm32f10x_bkp.c> 
+OPTFFF 4,54,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_can.c><stm32f10x_can.c> 
+OPTFFF 4,55,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_crc.c><stm32f10x_crc.c> 
+OPTFFF 4,56,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_dac.c><stm32f10x_dac.c> 
+OPTFFF 4,57,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_dbgmcu.c><stm32f10x_dbgmcu.c> 
+OPTFFF 4,58,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_dma.c><stm32f10x_dma.c> 
+OPTFFF 4,59,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_exti.c><stm32f10x_exti.c> 
+OPTFFF 4,60,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_flash.c><stm32f10x_flash.c> 
+OPTFFF 4,61,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_fsmc.c><stm32f10x_fsmc.c> 
+OPTFFF 4,62,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_gpio.c><stm32f10x_gpio.c> 
+OPTFFF 4,63,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_i2c.c><stm32f10x_i2c.c> 
+OPTFFF 4,64,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_iwdg.c><stm32f10x_iwdg.c> 
+OPTFFF 4,65,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_pwr.c><stm32f10x_pwr.c> 
+OPTFFF 4,66,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_rcc.c><stm32f10x_rcc.c> 
+OPTFFF 4,67,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_rtc.c><stm32f10x_rtc.c> 
+OPTFFF 4,68,1,16777216,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_sdio.c><stm32f10x_sdio.c> 
+OPTFFF 4,69,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_spi.c><stm32f10x_spi.c> 
+OPTFFF 4,70,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_tim.c><stm32f10x_tim.c> 
+OPTFFF 4,71,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_usart.c><stm32f10x_usart.c> 
+OPTFFF 4,72,1,0,0,0,0,0,<.\Libraries\STM32F10x_StdPeriph_Driver\src\stm32f10x_wwdg.c><stm32f10x_wwdg.c> 
+OPTFFF 5,73,1,0,0,0,0,0,<.\Libraries\CMSIS\Core\CM3\core_cm3.c><core_cm3.c> 
+OPTFFF 5,74,1,0,0,0,0,0,<.\Libraries\CMSIS\Core\CM3\system_stm32f10x.c><system_stm32f10x.c> 
+OPTFFF 6,75,1,0,0,0,0,0,<..\..\finsh\finsh_compiler.c><finsh_compiler.c> 
+OPTFFF 6,76,1,0,0,0,0,0,<..\..\finsh\finsh_error.c><finsh_error.c> 
+OPTFFF 6,77,1,0,0,0,0,0,<..\..\finsh\finsh_heap.c><finsh_heap.c> 
+OPTFFF 6,78,1,0,0,0,0,0,<..\..\finsh\finsh_init.c><finsh_init.c> 
+OPTFFF 6,79,1,0,0,0,0,0,<..\..\finsh\finsh_node.c><finsh_node.c> 
+OPTFFF 6,80,1,0,0,0,0,0,<..\..\finsh\finsh_ops.c><finsh_ops.c> 
+OPTFFF 6,81,1,0,0,0,0,0,<..\..\finsh\finsh_parser.c><finsh_parser.c> 
+OPTFFF 6,82,1,0,0,0,0,0,<..\..\finsh\finsh_token.c><finsh_token.c> 
+OPTFFF 6,83,1,0,0,0,0,0,<..\..\finsh\finsh_var.c><finsh_var.c> 
+OPTFFF 6,84,1,0,0,0,0,0,<..\..\finsh\finsh_vm.c><finsh_vm.c> 
+OPTFFF 6,85,1,0,0,0,0,0,<..\..\finsh\shell.c><shell.c> 
+OPTFFF 6,86,1,0,0,0,0,0,<..\..\finsh\symbol.c><symbol.c> 
+OPTFFF 6,87,1,285212672,0,0,0,0,<..\..\finsh\cmd.c><cmd.c> 
+OPTFFF 7,88,1,0,0,0,0,0,<..\..\filesystem\dfs\src\dfs_init.c><dfs_init.c> 
+OPTFFF 7,89,1,503316480,0,0,0,0,<..\..\filesystem\dfs\src\dfs_fs.c><dfs_fs.c> 
+OPTFFF 7,90,1,0,0,0,0,0,<..\..\filesystem\dfs\src\dfs_raw.c><dfs_raw.c> 
+OPTFFF 7,91,1,0,0,0,0,0,<..\..\filesystem\dfs\src\dfs_util.c><dfs_util.c> 
+OPTFFF 7,92,1,0,0,0,0,0,<..\..\filesystem\dfs\src\dfs_posix.c><dfs_posix.c> 
+OPTFFF 7,93,1,0,0,0,0,0,<..\..\filesystem\dfs\filesystems\efsl\src\fs\vfat\dir.c><dir.c> 
+OPTFFF 7,94,1,0,0,0,0,0,<..\..\filesystem\dfs\filesystems\efsl\src\fs\vfat\fat.c><fat.c> 
+OPTFFF 7,95,1,0,0,0,0,0,<..\..\filesystem\dfs\filesystems\efsl\src\fs\vfat\file.c><file.c> 
+OPTFFF 7,96,1,0,0,0,0,0,<..\..\filesystem\dfs\filesystems\efsl\src\fs\vfat\fs.c><fs.c> 
+OPTFFF 7,97,1,0,0,0,0,0,<..\..\filesystem\dfs\filesystems\efsl\src\fs\vfat\ls.c><ls.c> 
+OPTFFF 7,98,1,0,0,0,0,0,<..\..\filesystem\dfs\filesystems\efsl\src\fs\vfat\time.c><time.c> 
+OPTFFF 7,99,1,0,0,0,0,0,<..\..\filesystem\dfs\filesystems\efsl\src\fs\vfat\ui.c><ui.c> 
+OPTFFF 7,100,1,0,0,0,0,0,<..\..\filesystem\dfs\filesystems\efsl\src\base\plibc.c><plibc.c> 
+OPTFFF 7,101,1,0,0,0,0,0,<..\..\filesystem\dfs\filesystems\efsl\src\base\efs.c><efs.c> 
+OPTFFF 7,102,1,0,0,0,0,0,<..\..\filesystem\dfs\filesystems\efsl\src\base\extract.c><extract.c> 
+OPTFFF 7,103,1,0,0,0,0,0,<..\..\filesystem\dfs\filesystems\efsl\src\base\partition.c><partition.c> 
+OPTFFF 7,104,1,0,0,0,0,0,<..\..\filesystem\dfs\src\dfs_cache.c><dfs_cache.c> 
+OPTFFF 8,105,1,0,0,0,0,0,<..\..\net\lwip\src\core\dhcp.c><dhcp.c> 
+OPTFFF 8,106,1,0,0,0,0,0,<..\..\net\lwip\src\core\dns.c><dns.c> 
+OPTFFF 8,107,1,0,0,0,0,0,<..\..\net\lwip\src\core\init.c><init.c> 
+OPTFFF 8,108,1,0,0,0,0,0,<..\..\net\lwip\src\core\netif.c><netif.c> 
+OPTFFF 8,109,1,0,0,0,0,0,<..\..\net\lwip\src\core\pbuf.c><pbuf.c> 
+OPTFFF 8,110,1,0,0,0,0,0,<..\..\net\lwip\src\core\raw.c><raw.c> 
+OPTFFF 8,111,1,0,0,0,0,0,<..\..\net\lwip\src\core\stats.c><stats.c> 
+OPTFFF 8,112,1,0,0,0,0,0,<..\..\net\lwip\src\core\sys.c><sys.c> 
+OPTFFF 8,113,1,0,0,0,0,0,<..\..\net\lwip\src\core\tcp.c><tcp.c> 
+OPTFFF 8,114,1,0,0,0,0,0,<..\..\net\lwip\src\core\tcp_in.c><tcp_in.c> 
+OPTFFF 8,115,1,0,0,0,0,0,<..\..\net\lwip\src\core\tcp_out.c><tcp_out.c> 
+OPTFFF 8,116,1,0,0,0,0,0,<..\..\net\lwip\src\core\udp.c><udp.c> 
+OPTFFF 8,117,1,0,0,0,0,0,<..\..\net\lwip\src\core\ipv4\autoip.c><autoip.c> 
+OPTFFF 8,118,1,0,0,0,0,0,<..\..\net\lwip\src\core\ipv4\icmp.c><icmp.c> 
+OPTFFF 8,119,1,0,0,0,0,0,<..\..\net\lwip\src\core\ipv4\igmp.c><igmp.c> 
+OPTFFF 8,120,1,0,0,0,0,0,<..\..\net\lwip\src\core\ipv4\inet.c><inet.c> 
+OPTFFF 8,121,1,0,0,0,0,0,<..\..\net\lwip\src\core\ipv4\inet_chksum.c><inet_chksum.c> 
+OPTFFF 8,122,1,0,0,0,0,0,<..\..\net\lwip\src\core\ipv4\ip.c><ip.c> 
+OPTFFF 8,123,1,0,0,0,0,0,<..\..\net\lwip\src\core\ipv4\ip_addr.c><ip_addr.c> 
+OPTFFF 8,124,1,285212672,0,0,0,0,<..\..\net\lwip\src\core\ipv4\ip_frag.c><ip_frag.c> 
+OPTFFF 8,125,1,0,0,0,0,0,<..\..\net\lwip\src\core\snmp\msg_in.c><msg_in.c> 
+OPTFFF 8,126,1,0,0,0,0,0,<..\..\net\lwip\src\core\snmp\msg_out.c><msg_out.c> 
+OPTFFF 8,127,1,0,0,0,0,0,<..\..\net\lwip\src\api\api_lib.c><api_lib.c> 
+OPTFFF 8,128,1,50331648,0,0,0,0,<..\..\net\lwip\src\api\api_msg.c><api_msg.c> 
+OPTFFF 8,129,1,0,0,0,0,0,<..\..\net\lwip\src\api\err.c><err.c> 
+OPTFFF 8,130,1,0,0,0,0,0,<..\..\net\lwip\src\api\netbuf.c><netbuf.c> 
+OPTFFF 8,131,1,0,0,0,0,0,<..\..\net\lwip\src\api\netdb.c><netdb.c> 
+OPTFFF 8,132,1,0,0,0,0,0,<..\..\net\lwip\src\api\netifapi.c><netifapi.c> 
+OPTFFF 8,133,1,0,0,0,0,0,<..\..\net\lwip\src\api\tcpip.c><tcpip.c> 
+OPTFFF 8,134,1,0,0,0,0,0,<..\..\net\lwip\src\netif\etharp.c><etharp.c> 
+OPTFFF 8,135,1,150994944,0,0,0,0,<..\..\net\lwip\src\netif\ethernetif.c><ethernetif.c> 
+OPTFFF 8,136,1,0,0,0,0,0,<..\..\net\lwip\src\netif\loopif.c><loopif.c> 
+OPTFFF 8,137,1,285212672,0,0,0,0,<..\..\net\lwip\src\arch\sys_arch_init.c><sys_arch_init.c> 
+OPTFFF 8,138,1,0,0,0,0,0,<..\..\net\lwip\src\arch\sys_arch.c><sys_arch.c> 
+OPTFFF 8,139,1,0,0,0,0,0,<..\..\net\lwip\src\api\sockets.c><sockets.c> 
+OPTFFF 8,140,1,0,0,0,0,0,<..\..\net\lwip\src\core\memp_tiny.c><memp_tiny.c> 
+OPTFFF 9,141,1,402653184,0,0,0,0,<.\mp3\mp3dec.c><mp3dec.c> 
+OPTFFF 9,142,1,0,0,0,0,0,<.\mp3\mp3tabs.c><mp3tabs.c> 
+OPTFFF 9,143,1,0,0,0,0,0,<.\mp3\real\bitstream.c><bitstream.c> 
+OPTFFF 9,144,1,83886080,0,0,0,0,<.\mp3\real\buffers.c><buffers.c> 
+OPTFFF 9,145,1,0,0,0,0,0,<.\mp3\real\dct32.c><dct32.c> 
+OPTFFF 9,146,1,0,0,0,0,0,<.\mp3\real\dequant.c><dequant.c> 
+OPTFFF 9,147,1,0,0,0,0,0,<.\mp3\real\dqchan.c><dqchan.c> 
+OPTFFF 9,148,1,0,0,0,0,0,<.\mp3\real\huffman.c><huffman.c> 
+OPTFFF 9,149,1,0,0,0,0,0,<.\mp3\real\hufftabs.c><hufftabs.c> 
+OPTFFF 9,150,1,0,0,0,0,0,<.\mp3\real\imdct.c><imdct.c> 
+OPTFFF 9,151,1,0,0,0,0,0,<.\mp3\real\scalfact.c><scalfact.c> 
+OPTFFF 9,152,1,0,0,0,0,0,<.\mp3\real\stproc.c><stproc.c> 
+OPTFFF 9,153,1,0,0,0,0,0,<.\mp3\real\subband.c><subband.c> 
+OPTFFF 9,154,1,0,0,0,0,0,<.\mp3\real\trigtabs.c><trigtabs.c> 
+OPTFFF 9,155,2,0,0,0,0,0,<.\mp3\real\arm\asmpoly_thumb2.s><asmpoly_thumb2.s> 
+OPTFFF 9,156,2,0,0,0,0,0,<.\mp3\real\arm\asmmisc.s><asmmisc.s> 
+OPTFFF 10,157,1,0,0,0,0,0,<..\..\rtgui\common\rtgui_object.c><rtgui_object.c> 
+OPTFFF 10,158,1,0,0,0,0,0,<..\..\rtgui\common\rtgui_system.c><rtgui_system.c> 
+OPTFFF 10,159,1,318767104,0,0,0,0,<..\..\rtgui\common\rtgui_theme.c><rtgui_theme.c> 
+OPTFFF 10,160,1,0,0,0,0,0,<..\..\rtgui\common\asc12font.c><asc12font.c> 
+OPTFFF 10,161,1,402653184,0,0,0,0,<..\..\rtgui\common\asc16font.c><asc16font.c> 
+OPTFFF 10,162,1,0,0,0,0,0,<..\..\rtgui\common\color.c><color.c> 
+OPTFFF 10,163,1,603979776,0,0,0,0,<..\..\rtgui\common\dc.c><dc.c> 
+OPTFFF 10,164,1,0,0,0,0,0,<..\..\rtgui\common\dc_buffer.c><dc_buffer.c> 
+OPTFFF 10,165,1,0,0,0,0,0,<..\..\rtgui\common\dc_hw.c><dc_hw.c> 
+OPTFFF 10,166,1,16777216,0,0,0,0,<..\..\rtgui\common\filerw.c><filerw.c> 
+OPTFFF 10,167,1,0,0,0,0,0,<..\..\rtgui\common\font.c><font.c> 
+OPTFFF 10,168,1,0,0,0,0,0,<..\..\rtgui\common\image.c><image.c> 
+OPTFFF 10,169,1,0,0,0,0,0,<..\..\rtgui\common\image_xpm.c><image_xpm.c> 
+OPTFFF 10,170,1,0,0,0,0,0,<..\..\rtgui\common\image_hdc.c><image_hdc.c> 
+OPTFFF 10,171,1,0,0,0,0,0,<..\..\rtgui\common\region.c><region.c> 
+OPTFFF 10,172,1,100663296,0,0,0,0,<..\..\rtgui\server\server.c><server.c> 
+OPTFFF 10,173,1,0,0,0,0,0,<..\..\rtgui\server\driver.c><driver.c> 
+OPTFFF 10,174,1,335544320,0,0,0,0,<..\..\rtgui\server\panel.c><panel.c> 
+OPTFFF 10,175,1,0,0,0,0,0,<..\..\rtgui\widgets\widget.c><widget.c> 
+OPTFFF 10,176,1,16777216,0,0,0,0,<..\..\rtgui\widgets\window.c><window.c> 
+OPTFFF 10,177,1,0,0,0,0,0,<..\..\rtgui\widgets\workbench.c><workbench.c> 
+OPTFFF 10,178,1,0,0,0,0,0,<..\..\rtgui\widgets\view.c><view.c> 
+OPTFFF 10,179,1,0,0,0,0,0,<..\..\rtgui\widgets\box.c><box.c> 
+OPTFFF 10,180,1,0,0,0,0,0,<..\..\rtgui\widgets\button.c><button.c> 
+OPTFFF 10,181,1,0,0,0,0,0,<..\..\rtgui\widgets\container.c><container.c> 
+OPTFFF 10,182,1,0,0,0,0,0,<..\..\rtgui\widgets\iconbox.c><iconbox.c> 
+OPTFFF 10,183,1,0,0,0,0,0,<..\..\rtgui\widgets\label.c><label.c> 
+OPTFFF 10,184,1,0,0,0,0,0,<..\..\rtgui\widgets\textbox.c><textbox.c> 
+OPTFFF 10,185,1,0,0,0,0,0,<..\..\rtgui\widgets\title.c><title.c> 
+OPTFFF 10,186,1,67108864,0,0,0,0,<..\..\rtgui\widgets\toplevel.c><toplevel.c> 
+OPTFFF 10,187,1,0,0,0,0,0,<..\..\rtgui\server\mouse.c><mouse.c> 
+OPTFFF 10,188,1,0,0,0,0,0,<..\..\rtgui\server\topwin.c><topwin.c> 
+OPTFFF 10,189,1,0,0,0,0,0,<..\..\rtgui\common\caret.c><caret.c> 
+OPTFFF 10,190,1,0,0,0,0,0,<..\..\rtgui\common\font_hz_file.c><font_hz_file.c> 
+OPTFFF 10,191,1,0,0,0,0,0,<..\..\rtgui\common\hz16font.c><hz16font.c> 
+OPTFFF 10,192,1,0,0,0,0,0,<..\..\rtgui\common\hz12font.c><hz12font.c> 
 
+ExtF <E:\Projects\opensvn\rt-thread\google\bsp\stm32_radio\player_ui.h> 13,29,0,{ 44,0,0,0,0,0,0,0,1,0,0,0,255,255,255,255,255,255,255,255,252,255,255,255,226,255,255,255,66,0,0,0,87,0,0,0,208,2,0,0,203,1,0,0 }
 
 TARGOPT 1, (RT-Thread STM32 Radio)
  ADSCLK=8000000
@@ -225,15 +229,15 @@ TARGOPT 1, (RT-Thread STM32 Radio)
   OPTAX 255
   OPTDL (SARMCM3.DLL)()(DARMSTM.DLL)(-pSTM32F103ZE)(SARMCM3.DLL)()(TARMSTM.DLL)(-pSTM32F103ZE)
   OPTDBG 48118,7,()()()()()()()()()() (Segger\JL2CM3.dll)()()()
-  OPTKEY 0,(DLGTARM)((1010=-1,-1,-1,-1,0)(1007=-1,-1,-1,-1,0)(1008=-1,-1,-1,-1,0)(1009=-1,-1,-1,-1,0)(100=-1,-1,-1,-1,0)(110=-1,-1,-1,-1,0)(111=-1,-1,-1,-1,0)(1011=-1,-1,-1,-1,0)(180=-1,-1,-1,-1,0)(120=-1,-1,-1,-1,0)(121=-1,-1,-1,-1,0)(122=-1,-1,-1,-1,0)(123=-1,-1,-1,-1,0)(124=-1,-1,-1,-1,0)(125=-1,-1,-1,-1,0)(126=-1,-1,-1,-1,0)(140=-1,-1,-1,-1,0)(240=-1,-1,-1,-1,0)(190=-1,-1,-1,-1,0)(200=-1,-1,-1,-1,0)(170=-1,-1,-1,-1,0)(130=-1,-1,-1,-1,0)(131=-1,-1,-1,-1,0)(132=-1,-1,-1,-1,0)(133=-1,-1,-1,-1,0)(160=-1,-1,-1,-1,0)(161=-1,-1,-1,-1,0)(162=-1,-1,-1,-1,0)(210=-1,-1,-1,-1,0)(211=-1,-1,-1,-1,0)(220=-1,-1,-1,-1,0)(221=-1,-1,-1,-1,0)(230=-1,-1,-1,-1,0)(231=-1,-1,-1,-1,0)(232=-1,-1,-1,-1,0)(233=-1,-1,-1,-1,0)(150=-1,-1,-1,-1,0)(151=-1,-1,-1,-1,0))
+  OPTKEY 0,(DLGTARM)((1010=-1,-1,-1,-1,0)(1007=-1,-1,-1,-1,0)(1008=-1,-1,-1,-1,0)(1009=-1,-1,-1,-1,0)(100=-1,-1,-1,-1,0)(110=-1,-1,-1,-1,0)(111=-1,-1,-1,-1,0)(1011=60,91,584,445,0)(180=-1,-1,-1,-1,0)(120=-1,-1,-1,-1,0)(121=-1,-1,-1,-1,0)(122=-1,-1,-1,-1,0)(123=-1,-1,-1,-1,0)(124=-1,-1,-1,-1,0)(125=-1,-1,-1,-1,0)(126=-1,-1,-1,-1,0)(140=-1,-1,-1,-1,0)(240=-1,-1,-1,-1,0)(190=-1,-1,-1,-1,0)(200=-1,-1,-1,-1,0)(170=-1,-1,-1,-1,0)(130=-1,-1,-1,-1,0)(131=-1,-1,-1,-1,0)(132=-1,-1,-1,-1,0)(133=-1,-1,-1,-1,0)(160=-1,-1,-1,-1,0)(161=-1,-1,-1,-1,0)(162=-1,-1,-1,-1,0)(210=-1,-1,-1,-1,0)(211=-1,-1,-1,-1,0)(220=-1,-1,-1,-1,0)(221=-1,-1,-1,-1,0)(230=-1,-1,-1,-1,0)(231=-1,-1,-1,-1,0)(232=-1,-1,-1,-1,0)(233=-1,-1,-1,-1,0)(150=-1,-1,-1,-1,0)(151=-1,-1,-1,-1,0))
   OPTKEY 0,(ARMDBGFLAGS)()
-  OPTKEY 0,(DLGUARM)((105=-1,-1,-1,-1,0)(106=-1,-1,-1,-1,0)(107=-1,-1,-1,-1,0))
+  OPTKEY 0,(DLGUARM)((105=150,189,819,540,0)(106=-1,-1,-1,-1,0)(107=-1,-1,-1,-1,0))
   OPTKEY 0,(JL2CM3)(-U20090110 -O718 -S8 -C0 -JU1 -JI127.0.0.1 -JP0 -N00("ARM CoreSight SW-DP") -D00(00000000) -L00(0) -TO18 -TC10000000 -TP21 -TDS8007 -TDT0 -TDC1F -TIEFFFFFFFF -TIP8 -FO27 -FD20000000 -FC800 -FN1 -FF0STM32F10x_512 -FS08000000 -FL080000)
-  OPTBB 0,0,590,1,134245962,0,0,0,0,1,<dfs_raw.c>()()
-  OPTBB 1,0,129,1,134325656,0,0,0,0,1,<application.c>()()
-  OPTBB 2,0,41,1,134354810,0,0,0,0,1,<rtgui_system.c>()()
-  OPTBB 3,0,66,1,134343178,0,0,0,0,1,<font.c>()()
-  OPTMM 1,8,(0x20005f34)
+  OPTBB 0,0,129,1,134329636,0,0,0,0,1,<application.c>()()
+  OPTBB 1,0,3051,1,134335826,0,0,0,0,1,<sdcard.c>()()
+  OPTWA 0,1,(_mp)
+  OPTWA 1,1,(tinfo,0x0A)
+  OPTMM 1,8,(text)
   OPTMM 2,8,(mimeBuffer)
   OPTDF 0x82
   OPTLE <>
diff --git a/bsp/stm32_radio/project.Uv2 b/bsp/stm32_radio/project.Uv2
index 9c0f136df12da642cf8adc9509361bb29cf77344..66d99e3b69743b4cba61052d8e0b826db5700359 100644
--- a/bsp/stm32_radio/project.Uv2
+++ b/bsp/stm32_radio/project.Uv2
@@ -24,7 +24,6 @@ File 1,1,<.\stm32f10x_it.c><stm32f10x_it.c>
 File 1,1,<.\usart.c><usart.c>
 File 1,1,<.\sdcard.c><sdcard.c>
 File 1,1,<.\rtc.c><rtc.c>
-File 1,1,<.\wm8753.c><wm8753.c>
 File 1,1,<.\dm9000.c><dm9000.c>
 File 1,1,<.\fsmc_nand.c><fsmc_nand.c>
 File 1,1,<.\fsmc_sram.c><fsmc_sram.c>
@@ -36,10 +35,14 @@ File 1,1,<.\wav.c><wav.c>
 File 1,1,<.\netbuffer.c><netbuffer.c>
 File 1,1,<.\key.c><key.c>
 File 1,1,<.\info.c><info.c>
-File 1,1,<.\player.c><player.c>
 File 1,1,<.\filelist.c><filelist.c>
 File 1,1,<.\device_info.c><device_info.c>
 File 1,1,<.\listview.c><listview.c>
+File 1,1,<.\wm8753.c><wm8753.c>
+File 1,1,<.\player_ui.c><player_ui.c>
+File 1,1,<.\player_bg.c><player_bg.c>
+File 1,1,<.\wm8978.c><wm8978.c>
+File 1,1,<.\play_list.c><play_list.c>
 File 2,1,<..\..\src\clock.c><clock.c>
 File 2,1,<..\..\src\idle.c><idle.c>
 File 2,1,<..\..\src\ipc.c><ipc.c>
diff --git a/bsp/stm32_radio/sdcard.c b/bsp/stm32_radio/sdcard.c
index fbbc42aab335aa878d3c699db101b24a23d374db..386db317936cd4b40b9ff48d027ada5acd7de371 100644
--- a/bsp/stm32_radio/sdcard.c
+++ b/bsp/stm32_radio/sdcard.c
@@ -21,7 +21,9 @@
 /* Includes ------------------------------------------------------------------*/
 #include "sdcard.h"
 #include <stm32f10x_dma.h>
-#include <stm32f10x_sdio.h>
+#include <stm32f10x_sdio.h>
+
+#include <rtthread.h>
 
 /** @addtogroup STM32F10x_StdPeriph_Examples
   * @{
@@ -955,12 +957,30 @@ SD_Error SD_ReadBlock(uint32_t addr, uint32_t *readbuff, uint16_t BlockSize)
     }
   }
   else if (DeviceMode == SD_DMA_MODE)
-  {
+  {
+    int cnt = 0; 
     SDIO_ITConfig(SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_DATAEND | SDIO_IT_RXOVERR | SDIO_IT_STBITERR, ENABLE);
     SDIO_DMACmd(ENABLE);
     DMA_RxConfiguration(readbuff, BlockSize);
     while (DMA_GetFlagStatus(DMA2_FLAG_TC4) == RESET)
-    {}
+    {
+		cnt ++; 
+		if (cnt > 10 * 50000) 
+		{
+			rt_kprintf("DMA flag 0x%08x\n", DMA_GetFlagStatus(DMA2_FLAG_TC4));
+			/* Clear all DPSM configuration */
+			SDIO_DataInitStructure.SDIO_DataTimeOut = SD_DATATIMEOUT;
+			SDIO_DataInitStructure.SDIO_DataLength = 0;
+			SDIO_DataInitStructure.SDIO_DataBlockSize = SDIO_DataBlockSize_1b;
+			SDIO_DataInitStructure.SDIO_TransferDir = SDIO_TransferDir_ToCard;
+			SDIO_DataInitStructure.SDIO_TransferMode = SDIO_TransferMode_Block;
+			SDIO_DataInitStructure.SDIO_DPSM = SDIO_DPSM_Disable;
+			SDIO_DataConfig(&SDIO_DataInitStructure);
+			SDIO_DMACmd(DISABLE);
+			errorstatus = SD_ERROR; 
+			break;
+		} 
+	}
   }
   return(errorstatus);
 }
@@ -2941,7 +2961,7 @@ static void DMA_RxConfiguration(uint32_t *BufferDST, uint32_t BufferSize)
   DMA_InitStructure.DMA_Priority = DMA_Priority_High;
   DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
   DMA_Init(DMA2_Channel4, &DMA_InitStructure);
-
+
   /* DMA2 Channel4 enable */
   DMA_Cmd(DMA2_Channel4, ENABLE);
 }
@@ -2978,7 +2998,7 @@ static rt_err_t rt_sdcard_init(rt_device_t dev)
 	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
 	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
 	NVIC_Init(&NVIC_InitStructure);
-
+
 	if (rt_sem_init(&sd_lock, "sdlock", 1, RT_IPC_FLAG_FIFO) != RT_EOK)
 	{
 		rt_kprintf("init sd lock semaphore failed\n");
@@ -3009,7 +3029,7 @@ static rt_size_t rt_sdcard_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_
 
 	rt_sem_take(&sd_lock, RT_WAITING_FOREVER);
 	retry = 3;
-	/* read all sectors */
+	/* read all sectors */
 	for (i = 0; i < size / SECTOR_SIZE; i ++)
 	{
 __retry:
@@ -3017,9 +3037,10 @@ __retry:
 			(uint32_t*)((rt_uint8_t*)buffer + i * SECTOR_SIZE),
 			SECTOR_SIZE);
 		if (status != SD_OK)
-		{
-			if (--retry != 0) goto __retry;
-			break;
+		{
+			-- retry;
+			if (retry != 0) goto __retry;
+			else break;
 		}
 	}
 
@@ -3130,4 +3151,3 @@ void rt_hw_sdcard_init()
 __return:
 	rt_kprintf("sdcard init failed\n");
 }
-
diff --git a/bsp/stm32_radio/startup.c b/bsp/stm32_radio/startup.c
index af917f4a4a3d261c69766ebd26a2556570b3d71a..d5c16446c78c358ac5f112a591ae7d1595967a4d 100644
--- a/bsp/stm32_radio/startup.c
+++ b/bsp/stm32_radio/startup.c
@@ -44,7 +44,7 @@ extern void finsh_set_device(const char* device);
 #endif
 extern int rt_application_init(void);
 extern rt_err_t wm8753_hw_init(void);
-
+extern rt_err_t wm8978_hw_init(void);
 #ifdef  DEBUG
 /*******************************************************************************
 * Function Name  : assert_failed
@@ -101,9 +101,13 @@ void rtthread_startup(void)
 #endif
 
 	/* init scheduler system */
-	rt_system_scheduler_init();
+	rt_system_scheduler_init();
 
+#if CODEC_VERSION == 1
 	wm8753_hw_init();
+#elif CODEC_VERSION == 2
+	wm8978_hw_init();
+#endif
 
 	/* init hardware serial device */
 	rt_hw_usart_init();
diff --git a/bsp/stm32_radio/stm32f10x_it.c b/bsp/stm32_radio/stm32f10x_it.c
index ac42f4ef59f56c629fd8ee51a20effc67e144fab..b0bb63278c65f99f4e1415776c53f5c63cf6f630 100644
--- a/bsp/stm32_radio/stm32f10x_it.c
+++ b/bsp/stm32_radio/stm32f10x_it.c
@@ -18,6 +18,7 @@
 /* Includes ------------------------------------------------------------------*/
 #include <rtthread.h>
 #include <serial.h>
+#include "board.h"
 
 /* Private typedef -----------------------------------------------------------*/
 /* Private define ------------------------------------------------------------*/
@@ -339,6 +340,7 @@ void DMA1_Channel4_IRQHandler(void)
 {
 }
 
+#if CODEC_VERSION == 1
 /*******************************************************************************
 * Function Name  : DMA1_Channel5_IRQHandler
 * Description    : This function handles DMA1 Channel 5 interrupt request.
@@ -365,9 +367,8 @@ void DMA1_Channel5_IRQHandler(void)
 
     /* leave interrupt */
     rt_interrupt_leave();
-    rt_hw_interrupt_thread_switch();
-
 }
+#endif
 
 /*******************************************************************************
 * Function Name  : DMA1_Channel6_IRQHandler
@@ -394,74 +395,6 @@ void DMA1_Channel6_IRQHandler(void)
 #endif
 }
 
-/*******************************************************************************
-* Function Name  : DMA1_Channel7_IRQHandler
-* Description    : This function handles DMA1 Channel 7 interrupt request.
-* Input          : None
-* Output         : None
-* Return         : None
-*******************************************************************************/
-void DMA1_Channel7_IRQHandler(void)
-{
-}
-
-/*******************************************************************************
-* Function Name  : ADC1_2_IRQHandler
-* Description    : This function handles ADC1 and ADC2 global interrupts requests.
-* Input          : None
-* Output         : None
-* Return         : None
-*******************************************************************************/
-void ADC1_2_IRQHandler(void)
-{
-}
-
-/*******************************************************************************
-* Function Name  : USB_HP_CAN1_TX_IRQHandler
-* Description    : This function handles USB High Priority or CAN TX interrupts
-*                  requests.
-* Input          : None
-* Output         : None
-* Return         : None
-*******************************************************************************/
-void USB_HP_CAN1_TX_IRQHandler(void)
-{
-}
-
-/*******************************************************************************
-* Function Name  : USB_LP_CAN1_RX0_IRQHandler
-* Description    : This function handles USB Low Priority or CAN RX0 interrupts
-*                  requests.
-* Input          : None
-* Output         : None
-* Return         : None
-*******************************************************************************/
-void USB_LP_CAN1_RX0_IRQHandler(void)
-{
-}
-
-/*******************************************************************************
-* Function Name  : CAN1_RX1_IRQHandler
-* Description    : This function handles CAN RX1 interrupt request.
-* Input          : None
-* Output         : None
-* Return         : None
-*******************************************************************************/
-void CAN1_RX1_IRQHandler(void)
-{
-}
-
-/*******************************************************************************
-* Function Name  : CAN1_SCE_IRQHandler
-* Description    : This function handles CAN SCE interrupt request.
-* Input          : None
-* Output         : None
-* Return         : None
-*******************************************************************************/
-void CAN1_SCE_IRQHandler(void)
-{
-}
-
 /*******************************************************************************
 * Function Name  : EXTI9_5_IRQHandler
 * Description    : This function handles External lines 9 to 5 interrupt request.
@@ -488,140 +421,7 @@ void EXTI9_5_IRQHandler(void)
 #endif
 }
 
-/*******************************************************************************
-* Function Name  : TIM1_BRK_IRQHandler
-* Description    : This function handles TIM1 Break interrupt request.
-* Input          : None
-* Output         : None
-* Return         : None
-*******************************************************************************/
-void TIM1_BRK_IRQHandler(void)
-{
-}
-
-/*******************************************************************************
-* Function Name  : TIM1_UP_IRQHandler
-* Description    : This function handles TIM1 overflow and update interrupt
-*                  request.
-* Input          : None
-* Output         : None
-* Return         : None
-*******************************************************************************/
-void TIM1_UP_IRQHandler(void)
-{
-}
-
-/*******************************************************************************
-* Function Name  : TIM1_TRG_COM_IRQHandler
-* Description    : This function handles TIM1 Trigger and commutation interrupts
-*                  requests.
-* Input          : None
-* Output         : None
-* Return         : None
-*******************************************************************************/
-void TIM1_TRG_COM_IRQHandler(void)
-{
-}
-
-/*******************************************************************************
-* Function Name  : TIM1_CC_IRQHandler
-* Description    : This function handles TIM1 capture compare interrupt request.
-* Input          : None
-* Output         : None
-* Return         : None
-*******************************************************************************/
-void TIM1_CC_IRQHandler(void)
-{
-}
-
-/*******************************************************************************
-* Function Name  : TIM2_IRQHandler
-* Description    : This function handles TIM2 global interrupt request.
-* Input          : None
-* Output         : None
-* Return         : None
-*******************************************************************************/
-void TIM2_IRQHandler(void)
-{
-}
-
-/*******************************************************************************
-* Function Name  : TIM3_IRQHandler
-* Description    : This function handles TIM3 global interrupt request.
-* Input          : None
-* Output         : None
-* Return         : None
-*******************************************************************************/
-void TIM3_IRQHandler(void)
-{
-}
-
-/*******************************************************************************
-* Function Name  : TIM4_IRQHandler
-* Description    : This function handles TIM4 global interrupt request.
-* Input          : None
-* Output         : None
-* Return         : None
-*******************************************************************************/
-void TIM4_IRQHandler(void)
-{
-}
-
-/*******************************************************************************
-* Function Name  : I2C1_EV_IRQHandler
-* Description    : This function handles I2C1 Event interrupt request.
-* Input          : None
-* Output         : None
-* Return         : None
-*******************************************************************************/
-void I2C1_EV_IRQHandler(void)
-{
-}
-
-/*******************************************************************************
-* Function Name  : I2C1_ER_IRQHandler
-* Description    : This function handles I2C1 Error interrupt request.
-* Input          : None
-* Output         : None
-* Return         : None
-*******************************************************************************/
-void I2C1_ER_IRQHandler(void)
-{
-}
-
-/*******************************************************************************
-* Function Name  : I2C2_EV_IRQHandler
-* Description    : This function handles I2C2 Event interrupt request.
-* Input          : None
-* Output         : None
-* Return         : None
-*******************************************************************************/
-void I2C2_EV_IRQHandler(void)
-{
-}
-
-/*******************************************************************************
-* Function Name  : I2C2_ER_IRQHandler
-* Description    : This function handles I2C2 Error interrupt request.
-* Input          : None
-* Output         : None
-* Return         : None
-*******************************************************************************/
-void I2C2_ER_IRQHandler(void)
-{
-}
-
-/*******************************************************************************
-* Function Name  : SPI1_IRQHandler
-* Description    : This function handles SPI1 global interrupt request.
-* Input          : None
-* Output         : None
-* Return         : None
-*******************************************************************************/
-void SPI1_IRQHandler(void)
-{
-}
-
+#if CODEC_VERSION == 1
 /*******************************************************************************
 * Function Name  : SPI2_IRQHandler
 * Description    : This function handles SPI2 global interrupt request.
@@ -640,8 +440,8 @@ void SPI2_IRQHandler(void)
 
     /* leave interrupt */
     rt_interrupt_leave();
-    rt_hw_interrupt_thread_switch();
 }
+#endif
 
 /*******************************************************************************
 * Function Name  : USART1_IRQHandler
@@ -836,17 +636,7 @@ void SDIO_IRQHandler(void)
 #endif
 }
 
-/*******************************************************************************
-* Function Name  : TIM5_IRQHandler
-* Description    : This function handles TIM5 global interrupt request.
-* Input          : None
-* Output         : None
-* Return         : None
-*******************************************************************************/
-void TIM5_IRQHandler(void)
-{
-}
-
+#if CODEC_VERSION == 2
 /*******************************************************************************
 * Function Name  : SPI3_IRQHandler
 * Description    : This function handles SPI3 global interrupt request.
@@ -856,61 +646,15 @@ void TIM5_IRQHandler(void)
 *******************************************************************************/
 void SPI3_IRQHandler(void)
 {
-}
-
-/*******************************************************************************
-* Function Name  : UART4_IRQHandler
-* Description    : This function handles UART4 global interrupt request.
-* Input          : None
-* Output         : None
-* Return         : None
-*******************************************************************************/
-void UART4_IRQHandler(void)
-{
-}
+    extern void wm8978_isr(void);
 
-/*******************************************************************************
-* Function Name  : UART5_IRQHandler
-* Description    : This function handles UART5 global interrupt request.
-* Input          : None
-* Output         : None
-* Return         : None
-*******************************************************************************/
-void UART5_IRQHandler(void)
-{
-}
-
-/*******************************************************************************
-* Function Name  : TIM6_IRQHandler
-* Description    : This function handles TIM6 global interrupt request.
-* Input          : None
-* Output         : None
-* Return         : None
-*******************************************************************************/
-void TIM6_IRQHandler(void)
-{
-}
+    /* enter interrupt */
+    rt_interrupt_enter();
 
-/*******************************************************************************
-* Function Name  : TIM7_IRQHandler
-* Description    : This function handles TIM7 global interrupt request.
-* Input          : None
-* Output         : None
-* Return         : None
-*******************************************************************************/
-void TIM7_IRQHandler(void)
-{
-}
+    wm8978_isr();
 
-/*******************************************************************************
-* Function Name  : DMA2_Channel1_IRQHandler
-* Description    : This function handles DMA2 Channel 1 interrupt request.
-* Input          : None
-* Output         : None
-* Return         : None
-*******************************************************************************/
-void DMA2_Channel1_IRQHandler(void)
-{
+    /* leave interrupt */
+    rt_interrupt_leave();
 }
 
 /*******************************************************************************
@@ -922,61 +666,21 @@ void DMA2_Channel1_IRQHandler(void)
 *******************************************************************************/
 void DMA2_Channel2_IRQHandler(void)
 {
-}
-
-/*******************************************************************************
-* Function Name  : DMA2_Channel3_IRQHandler
-* Description    : This function handles DMA2 Channel 3 interrupt request.
-* Input          : None
-* Output         : None
-* Return         : None
-*******************************************************************************/
-void DMA2_Channel3_IRQHandler(void)
-{
-}
-
-/*******************************************************************************
-* Function Name  : DMA2_Channel4_5_IRQHandler
-* Description    : This function handles DMA2 Channel 4 and DMA2 Channel 5
-*                  interrupt request.
-* Input          : None
-* Output         : None
-* Return         : None
-*******************************************************************************/
-void DMA2_Channel4_5_IRQHandler(void)
-{
-}
-
-void DMA2_Channel5_IRQHandler(void)
-{
-}
-
-void ETH_IRQHandler(void)
-{
-}
-
-void ETH_WKUP_IRQHandler(void)
-{
-}
-
-void CAN2_TX_IRQHandler(void)
-{
-}
+    extern void wm8978_dma_isr(void);
 
-void CAN2_RX0_IRQHandler(void)
-{
-}
+    /* enter interrupt */
+    rt_interrupt_enter();
 
-void CAN2_RX1_IRQHandler(void)
-{
-}
+    if (DMA_GetITStatus(DMA2_IT_TC2))
+    {
+        /* clear DMA flag */
+        DMA_ClearFlag(DMA2_FLAG_TC2 | DMA2_FLAG_TE2);
 
-void CAN2_SCE_IRQHandler(void)
-{
-}
+        /* transmission complete, invoke serial dma tx isr */
+        wm8978_dma_isr();
+    }
 
-void OTG_FS_IRQHandler(void)
-{
+    /* leave interrupt */
+    rt_interrupt_leave();
 }
-
-/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/
+#endif
diff --git a/bsp/stm32_radio/wm8978.c b/bsp/stm32_radio/wm8978.c
new file mode 100644
index 0000000000000000000000000000000000000000..834bfdb6bf6bed165e278267be4cb07f98209451
--- /dev/null
+++ b/bsp/stm32_radio/wm8978.c
@@ -0,0 +1,446 @@
+#include <rthw.h>
+#include <rtthread.h>
+#include "stm32f10x.h"
+
+/*
+ * WM8978 Driver
+ */
+
+/* WM8978 register definitions */
+#define WM8978_DAC		0x01
+#define WM8978_ADC		0x02
+#define WM8978_PCM		0x03
+#define WM8978_HIFI		0x04
+#define WM8978_IOCTL	0x05
+#define WM8978_SRATE1	0x06
+#define WM8978_SRATE2	0x07
+#define WM8978_LDAC		0x08
+#define WM8978_RDAC		0x09
+#define WM8978_BASS		0x0a
+#define WM8978_TREBLE	0x0b
+#define WM8978_ALC1		0x0c
+#define WM8978_ALC2		0x0d
+#define WM8978_ALC3		0x0e
+#define WM8978_NGATE	0x0f
+#define WM8978_LADC		0x10
+#define WM8978_RADC		0x11
+#define WM8978_ADCTL1	0x12
+#define WM8978_3D		0x13
+#define WM8978_PWR1		0x14
+#define WM8978_PWR2		0x15
+#define WM8978_PWR3		0x16
+#define WM8978_PWR4		0x17
+#define WM8978_ID		0x18
+#define WM8978_INTPOL	0x19
+#define WM8978_INTEN	0x1a
+#define WM8978_GPIO1	0x1b
+#define WM8978_GPIO2	0x1c
+#define WM8978_RESET	0x1f
+#define WM8978_RECMIX1	0x20
+#define WM8978_RECMIX2	0x21
+#define WM8978_LOUTM1	0x22
+#define WM8978_LOUTM2	0x23
+#define WM8978_ROUTM1	0x24
+#define WM8978_ROUTM2	0x25
+#define WM8978_MOUTM1	0x26
+#define WM8978_MOUTM2	0x27
+#define WM8978_LOUT1V	0x28
+#define WM8978_ROUT1V	0x29
+#define WM8978_LOUT2V	0x2a
+#define WM8978_ROUT2V	0x2b
+#define WM8978_MOUTV	0x2c
+#define WM8978_OUTCTL	0x2d
+#define WM8978_ADCIN	0x2e
+#define WM8978_INCTL1	0x2f
+#define WM8978_INCTL2	0x30
+#define WM8978_LINVOL	0x31
+#define WM8978_RINVOL	0x32
+#define WM8978_MICBIAS	0x33
+#define WM8978_CLOCK	0x34
+#define WM8978_PLL1CTL1	0x35
+#define WM8978_PLL1CTL2	0x36
+#define WM8978_PLL1CTL3	0x37
+#define WM8978_PLL1CTL4	0x38
+#define WM8978_PLL2CTL1	0x39
+#define WM8978_PLL2CTL2	0x3a
+#define WM8978_PLL2CTL3	0x3b
+#define WM8978_PLL2CTL4	0x3c
+#define WM8978_BIASCTL	0x3d
+#define WM8978_ADCTL2	0x3f
+
+/*
+SCLK  PB7
+SDIN  PB8
+CSB   PB9
+*/
+
+#define wm_sclk_0  GPIO_ResetBits(GPIOB,GPIO_Pin_7)
+#define wm_sclk_1  GPIO_SetBits(GPIOB,GPIO_Pin_7)
+#define wm_sdin_0  GPIO_ResetBits(GPIOB,GPIO_Pin_8)
+#define wm_sdin_1  GPIO_SetBits(GPIOB,GPIO_Pin_8)
+#define wm_csb_0   GPIO_ResetBits(GPIOB,GPIO_Pin_9)
+#define wm_csb_1   GPIO_SetBits(GPIOB,GPIO_Pin_9)
+
+#define DATA_NODE_MAX 5
+/* data node for Tx Mode */
+struct wm8978_data_node
+{
+    rt_uint16_t *data_ptr;
+    rt_size_t   data_size;
+};
+
+struct wm8978_device
+{
+    /* inherit from rt_device */
+    struct rt_device parent;
+
+    /* pcm data list */
+    struct wm8978_data_node data_list[DATA_NODE_MAX];
+    rt_uint16_t read_index, put_index;
+
+    /* transmitted offset of current data node */
+    rt_size_t offset;
+};
+struct wm8978_device wm8978;
+
+static void NVIC_Configuration(void)
+{
+    NVIC_InitTypeDef NVIC_InitStructure;
+    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
+
+    /* SPI3 IRQ Channel configuration */
+    NVIC_InitStructure.NVIC_IRQChannel = SPI3_IRQn;
+    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
+    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
+    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+    NVIC_Init(&NVIC_InitStructure);
+
+    /* DMA1 IRQ Channel configuration */
+    NVIC_InitStructure.NVIC_IRQChannel = DMA2_Channel2_IRQn;
+    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
+    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
+    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+    NVIC_Init(&NVIC_InitStructure);
+}
+
+static void GPIO_Configuration(void)
+{
+    GPIO_InitTypeDef GPIO_InitStructure;
+
+    /* configure GPIO B 7, 8, 9 */
+    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8  | GPIO_Pin_9;
+    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
+    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+    GPIO_Init(GPIOB,&GPIO_InitStructure);
+
+    /* configure GPIO B 3, 5 */
+    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_5;
+    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+    GPIO_Init(GPIOB, &GPIO_InitStructure);
+
+    /* configure GPIO A15 */
+    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
+    GPIO_Init(GPIOA, &GPIO_InitStructure);
+
+    /* Disable the JTAG interface and enable the SWJ interface */
+    GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
+}
+
+#define SPI3_DR_Address  0x40003C0C
+static void DMA_Configuration(rt_uint32_t addr, rt_size_t size)
+{
+    DMA_InitTypeDef    DMA_InitStructure;
+
+    /* DMA2 Channel2 configuration ----------------------------------------------*/
+    DMA_Cmd(DMA2_Channel2, DISABLE);
+    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)SPI3_DR_Address;
+    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)addr;
+    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
+    DMA_InitStructure.DMA_BufferSize = size;
+    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
+    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
+    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
+    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
+    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
+    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
+    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
+    DMA_Init(DMA2_Channel2, &DMA_InitStructure);
+
+    /* Enable SPI3 DMA Tx request */
+    SPI_I2S_DMACmd(SPI3, SPI_I2S_DMAReq_Tx, ENABLE);
+
+    DMA_ITConfig(DMA2_Channel2, DMA_IT_TC, ENABLE);
+    DMA_Cmd(DMA2_Channel2, ENABLE);
+}
+
+static void I2S_Configuration(void)
+{
+    I2S_InitTypeDef I2S_InitStructure;
+
+    /* I2S peripheral configuration */
+    I2S_InitStructure.I2S_Standard = I2S_Standard_Phillips;
+    I2S_InitStructure.I2S_DataFormat = I2S_DataFormat_16b;
+    I2S_InitStructure.I2S_MCLKOutput = I2S_MCLKOutput_Disable;
+    I2S_InitStructure.I2S_AudioFreq = I2S_AudioFreq_44k;
+    I2S_InitStructure.I2S_CPOL = I2S_CPOL_High;// I2S_CPOL_Low
+
+    /* I2S2 Master Transmitter to I2S3 Slave Receiver communication -----------*/
+    /* I2S2 configuration */
+    I2S_InitStructure.I2S_Mode = I2S_Mode_SlaveTx;
+    I2S_Init(SPI3, &I2S_InitStructure);
+}
+
+void wm_send(rt_uint16_t s_data)
+{
+    u8 i;
+    wm_csb_0;
+    wm_sclk_0;
+
+    for (i=0;i<16;i++)
+    {
+        if (s_data & 0x8000)
+        {
+            wm_sdin_1;
+        }
+        else
+        {
+            wm_sdin_0;
+        }
+        wm_sclk_1;
+        s_data <<= 1;
+        wm_sclk_0;
+    }
+
+    wm_csb_1;
+}
+
+static rt_err_t wm8978_init (rt_device_t dev)
+{
+    wm_send(0<<9 | 0xFF); // reset
+
+    /* POWER manager */
+    wm_send(1<<9 | (0<<8) | (0<<7) | (0<<6) | (0<<5) | (1<<4) | (1<<3) | (1<<2) | 3 );
+    wm_send(2<<9 | (1<<8) | (1<<7) | (1<<5) | (1<<4) );
+    wm_send(3<<9 | (0<<8) | (0<<7) | (1<<6) | (1<<5) | (1<<3) | (1<<2) | (1<<1) | 1 );
+
+    /* IIS DAC test */
+    wm_send(4<<9 | 0 | (2<<3) );//IIS 16BIT
+#if 0
+    wm_send(6<<9  | (3<<5) | (3<<2)| 1);//0: slave 1: master  | (3<<5) | (3<<2)
+    wm_send(43<<9 | (1<<4) );//INVROUT2
+#else
+    // 12.288/3 = 4.096M 4.096M / 8 = 512K == (16K *2??)*16?
+    wm_send(6<<9  | (3<<5) | (3<<2)| 1); //16K MCLK/3/8
+    wm_send(6<<9  | (0<<5) | (3<<2)| 1); //48K MCLK/1/8
+#endif
+
+    return RT_EOK;
+}
+
+#include <finsh.h>
+#if 0
+void vol(int v)
+{
+    wm_send(40<<9 | 0<<8 | 1<<7 | v);
+    wm_send(41<<9 | 1<<8 | 1<<7 | v);
+
+    wm_send(42<<9 | 0<<8 | 1<<7 | v);
+    wm_send(43<<9 | 1<<8 | 1<<7 | v);
+}
+FINSH_FUNCTION_EXPORT(vol, set volume)
+#endif
+
+static rt_err_t wm8978_open(rt_device_t dev, rt_uint16_t oflag)
+{
+    /* enable I2S */
+    I2S_Cmd(SPI3, ENABLE);
+
+    return RT_EOK;
+}
+
+static rt_err_t wm8978_close(rt_device_t dev)
+{
+    /* interrupt mode */
+    if (dev->flag & RT_DEVICE_FLAG_INT_TX)
+    {
+        /* Disable the I2S2 */
+        I2S_Cmd(SPI3, DISABLE);
+    }
+
+    /* remove all data node */
+
+    return RT_EOK;
+}
+
+static rt_err_t wm8978_control(rt_device_t dev, rt_uint8_t cmd, void *args)
+{
+    /* rate control */
+    return RT_EOK;
+}
+
+static rt_size_t wm8978_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
+{
+    struct wm8978_device* device;
+    struct wm8978_data_node* node;
+    rt_uint32_t level;
+    rt_uint16_t next_index;
+
+    device = (struct wm8978_device*)dev;
+    RT_ASSERT(device != RT_NULL);
+
+    next_index = device->put_index + 1;
+    if (next_index >= DATA_NODE_MAX) next_index = 0;
+
+    /* check data_list full */
+    if (next_index == device->read_index)
+    {
+        rt_set_errno(-RT_EFULL);
+        return 0;
+    }
+
+    level = rt_hw_interrupt_disable();
+    node = &device->data_list[device->put_index];
+    device->put_index = next_index;
+
+    // rt_kprintf("+\n");
+    /* set node attribute */
+    node->data_ptr = (rt_uint16_t*)buffer;
+    node->data_size = size >> 1; /* size is byte unit, convert to half word unit */
+
+    next_index = device->read_index + 1;
+    if (next_index >= DATA_NODE_MAX) next_index = 0;
+
+    /* check data list whether is empty */
+    if (next_index == device->put_index)
+    {
+        if (dev->flag & RT_DEVICE_FLAG_INT_TX)
+        {
+            device->offset = 0;
+            /* enable I2S interrupt */
+            SPI_I2S_ITConfig(SPI3, SPI_I2S_IT_TXE, ENABLE);
+        }
+        else if (dev->flag & RT_DEVICE_FLAG_DMA_TX)
+        {
+            DMA_Configuration((rt_uint32_t)node->data_ptr, node->data_size);
+        }
+    }
+    rt_hw_interrupt_enable(level);
+
+    return size;
+}
+
+rt_err_t wm8978_hw_init(void)
+{
+    rt_device_t dev;
+
+    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
+    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE);
+    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);
+
+    NVIC_Configuration();
+    GPIO_Configuration();
+    I2S_Configuration();
+
+    dev = (rt_device_t)&wm8978;
+    dev->type			= RT_Device_Class_Unknown;
+    dev->rx_indicate 	= RT_NULL;
+    dev->tx_complete 	= RT_NULL;
+    dev->init 			= wm8978_init;
+    dev->open			= wm8978_open;
+    dev->close			= wm8978_close;
+    dev->read 			= RT_NULL;
+    dev->write 			= wm8978_write;
+    dev->control 		= wm8978_control;
+    dev->private		= RT_NULL;
+
+    /* set read_index and put index to 0 */
+    wm8978.read_index	= 0;
+    wm8978.put_index 	= 0;
+
+    wm_sclk_0;
+    wm_sclk_1;
+    wm_sclk_0;
+
+    wm_sdin_0;
+    wm_sdin_1;
+    wm_sdin_0;
+
+    wm_csb_1;
+    wm_csb_0;
+    wm_csb_1;
+
+    /* register the device */
+    return rt_device_register(&wm8978.parent, "snd",
+                              RT_DEVICE_FLAG_WRONLY | RT_DEVICE_FLAG_DMA_TX);
+}
+
+void wm8978_isr()
+{
+    struct wm8978_data_node* node;
+    node = &wm8978.data_list[wm8978.read_index]; /* get current data node */
+
+    if (SPI_I2S_GetITStatus(SPI3, SPI_I2S_IT_TXE) == SET)
+    {
+        SPI_I2S_SendData(SPI3, node->data_ptr[wm8978.offset++]);
+    }
+
+    if (wm8978.offset == node->data_size)
+    {
+        /* move to next node */
+        rt_uint16_t next_index;
+
+        next_index = wm8978.read_index + 1;
+        if (next_index >= DATA_NODE_MAX) next_index = 0;
+
+        /* notify transmitted complete. */
+        if (wm8978.parent.tx_complete != RT_NULL)
+        {
+            wm8978.parent.tx_complete (&wm8978.parent, wm8978.data_list[wm8978.read_index].data_ptr);
+            rt_kprintf("-\n");
+        }
+
+        wm8978.offset = 0;
+        wm8978.read_index = next_index;
+        if (next_index == wm8978.put_index)
+        {
+            /* no data on the list, disable I2S interrupt */
+            SPI_I2S_ITConfig(SPI3, SPI_I2S_IT_TXE, DISABLE);
+
+            rt_kprintf("*\n");
+        }
+    }
+}
+
+void wm8978_dma_isr()
+{
+    /* switch to next buffer */
+    rt_uint16_t next_index;
+    void* data_ptr;
+
+    next_index = wm8978.read_index + 1;
+    if (next_index >= DATA_NODE_MAX) next_index = 0;
+
+    /* save current data pointer */
+    data_ptr = wm8978.data_list[wm8978.read_index].data_ptr;
+
+    wm8978.read_index = next_index;
+    if (next_index != wm8978.put_index)
+    {
+        /* enable next dma request */
+        DMA_Configuration((rt_uint32_t)wm8978.data_list[wm8978.read_index].data_ptr,
+                          wm8978.data_list[wm8978.read_index].data_size);
+    }
+    else
+    {
+        rt_kprintf("*\n");
+    }
+
+    /* notify transmitted complete. */
+    if (wm8978.parent.tx_complete != RT_NULL)
+    {
+        wm8978.parent.tx_complete (&wm8978.parent, data_ptr);
+        // rt_kprintf("-\n");
+    }
+}
+