星期五, 12月 30, 2005

有趣的作法

有自己的blog也不錯.........這一篇 因為不允許回應,所以只好連結回來,自己回應。

星期四, 12月 29, 2005

C 的隱藏structure

還是在廠商的code看到,----- 應該大家都已經知道。

這是為了隱藏structuer 的內部結構用的方法(應該不是甚麼好動機),通常用在廠商只願意提供object file (或library archive)讓RD link。又不願意release出 要用作library 參數用的stucture內部構造。
arg.h:

struct arg{
char data;
....
};

liba.c:
#include <arg.h>

int lib_get_arg(struct arg **pp)
{
*p=malloc(.....);
...
}

int lib_clean_arg(struct arg *p)
{
free(p);
...
}

libb.c:
#include %lt;arg.h%gt;

int operation(struct arg *p, int oprtation)
{
*p=.....
... = *p...
}
上面的例子, library中包含兩個module : liba.c, libb.c,一個作create working space用,一個依照working space的內容來操作。共同需要的就是workingspace : struct arg 這個structure。
但是這個structure屬於library module內部所需,不希望外界的code會access(Read/Write)到structure內部的資料。所以外部的code : application 主體(main.c) :
extern int lib_get_arg(struct arg **p);
extern int lib_clean_arg(struct arg *p);
extern int operation(struct arg *p,int operation);
這樣compile不會過,因為struct arg 沒有宣告,但是又不知道struct arg的內容到底是甚麼,所以就:
struct arg;
告訴compile 是一個structure,內容不知道,這樣就可以了。
因為C的structure 參數一律傳遞pointer,所以對structure內部結構了不了解不影響compile的動作。
在模組話程式設計裏,這樣的module設計是不好的,叫做??? coupled 。

C 的printf debug output , 使用 __FILE__和__LINE__

從廠商的code看到的。----- 或許很多programmer 都已經知道了。

沒有ICE的場合,常常要用printf將message送出去。
配合C 的predefined macro __FILE__ 和 __FILE__ 可以做出漂亮的debug output message。

__FILE__ 代表目前source code file name,是一個字串(char*)
__LINE__ 代表目前的行數,是integer。

所以用
 printf("[%s:%d] error here!!\n",__FILE__, __LINE__);
可以輸出:
[test.c:121] error here!!
這樣在多module (.c) file的場合,也可以迅速的知道message是由那一個module(.c) file送出的,乃至於是在source code中的第幾行,都可以知道。

上面的例子就是在test.c 的121行。

星期三, 12月 28, 2005

Copy 部份的binary 檔出來 -- 或說是 砍掉檔案的某一部份

因為有廠商送demo image,竟然將bootloader 和 kerenl + root 合在一起的rom image送過來,
這樣就沒辦法mount rootfs 進來看,而且也會破壞掉我原來的bootloader,
所以還是把他分開來。

本以為是用objdump, objcopy,但是這兩個tool好像能對有symbol table, sector information的檔案格式(obj) 操作。

最後,只有想到這個 : dd 這個command

dd 的man 說 option 有..
ibs=BYTES  每次讀取BYTES bytes
if=FILE 從FILE 讀入資料(如果沒指定,就是從stdin)
of=FILE 輸出到FILE (如果沒指定,就輸出到stdout)
skip=BLOCKS 跳過開頭BLOCKS ibs單位的資料不要copy
所以我要從file 的0x00280000 開始copy,copy到最後,command是...
$ dd if=orgimage of=kandr ibs=64k skip=40
因為0x10000 = 64k, 0x28 = 40.
這 樣就可以把orgimage的後半部份(從0x00280000開始)copy出來。
如果是要copy 前半段,就用count=
$dd if=orgimage of=head ibs=1M count=4
就是copy orgimage的前4M出來到head。


另外記一下,分割的方法..split
split -b 1m mySong.mp3  mySong
會把mySong.mp3 分成1M大小的mySone00,mySong01...

合併就用' cat' 啦
cat mySong00 mySong01 mySong02 > mySong.mp3

星期二, 12月 27, 2005

PAT, PMT in MPEG2 Stream :筆記

在做DVB播放時,出現的option和information,有這兩個字: PMT, PAT。所以google一下:
ES : Elementary Stream - 經過壓縮後的節目內容Audio ES,Video ES。
PES : Packetized Elememtary Stream,將ES由一個連續的stream分成一個一個packet後的packet。
TS : Transport Stream - 實際傳輸的Stream。由一連串的TS packet組成。
PID : TS Packet 中,用來代表這一個Packet 的資料ID的欄位。
Synch : TS Stream中用來代表TS Packet開頭的byte
PAT : Program Associate Table
PMT : Program Mapping Table


eedesign的這一篇有很好的概論,說明MPEG TS (Transport Stream)。

一般的攝影裝置,輸出都是BT601(270Mbps)。
利用ISO/IEC13818 作Video Coding,壓縮到3~5Mbps。

壓縮後的Video, Audio 資料都是Elementary Stream(Video ES, Audio ES)。

ES被切割成很多小小的packet。稱作Packetized Elementary Stream (Video PES, Audio PES)。

這 些PES,經由Multiplexer混在一起,成為單一的stream,就是Transport Stream (TS)。並且加上Information Packet (Table),例如EPG (Electronic Program Guide),PSI (Program Specific Information),SI (Service Informaion)再裡面,這些額外的資訊是提工接收端的demux將TS中的ES解出來用的。

一個TS並沒有規定只能包含多少節目,depends on 用來傳輸TS的頻寬(bandwidth)。
台灣的band width是6MHz,所以一個TS可以包含三個SDTV 節目。

ref中有一張圖(圖四)。是很好的說明。

-----
Video PES-->| |
Audio PES-->| mux |------ TS1..------------
Data PES--->| | |
PSI ------->| | | ----
------ -----| |
/|\ PCR(Program Clock TS2..--| |==>
| Reference ) TS3..--| | DVB
STC | |
(System Timer Clock) ----

一個TS可用的bandwidth是4Mbps ~ 7Mbps。內含
Video : 2~6Mbps
Audio : 32 ~ 384kbps
Data : -- depends--
PSI/SI : 0~1Mbps
目前DVB-C/S/T的bandwidh是
Cable : 38.153Mbps
Satelite : 38.015Mbps
Terrestrial : 4.98~31.67Mbps
Decoder的動作,ref 的圖五是很好的說明

找到TS中的同步byte 0x47
找到PSI的PAT, PAT中有所有PMT的PID,利用這個PID找到PMT,一個program有一個PMT。
經由PMT找到PES的PID。利用PID挑出TS中所需要觀看的Video/Audio PES。
挑出需要的PES後,開始Decode,decode時要參考Stream中的clock information : PCR, PTS和PES中的DTS(Decode Time Stamps)。

upsdn的這一篇有進一步的說明 :
TS的一個packet有188 bytes,分為head 和load。
Head 內含Synch byte,PID
Synch Byte(0x47)代表Packet的開頭
PID 代表這一個TS packet的內容類別。
Load 部份就是資料的實際內容。

解碼的動作就是先找到PAT 的packet,PAT封包的PID固定是0x00。
PAT 封包的內容(load)是每個program 的PMT 的PID。以下是一個PAT封包的例子:
Program index,  PID
0 122
1 60
,, ,,
20 200
其中program 0固定是NIT (Network Information Table)。從上面的例子看,NIC在PID=122的TS Packet中。
之後的就是各個program的PMT所在packet的PID。可以看到第20個program的PMT在PID=200的TS pocket中。
Decoder接著去找PID=200的TS pocket,其中包含的是program 20的節目內容,如:
PES    , PID
Video 500
Audio 510
Audio2 512
PCR 500
....
Private 540
這個例子說明節目20,內涵一個Video 資料,在PID=200的TS pocket中,有兩個語音信號(雙語音),各在PID 510, 512的TS pocket中。

Decoder知道Video, Audio 的PID後,就可以將收到的TS pocket,取出PID =500的部份,丟到Video decoder中,將PID=510的pocket丟到Audio decoder中。


Hardware support ,上一篇的內容會說到hardware support decoding的動作。
利用一個內建的lookup table,和TS pocket hardware分段的動作,解出PID。
並且利用look up table決定這個pid要處理的方式(送到Video, Audio decoder或是丟棄)。

PID=0,解出,更新look up table的Video,Audio PID。
PID=? 經果lookup table篩選出需要的PID,送到解壓縮模組。


這一頁是英文的說明,附TS pocket的圖解,和MPEG2 stream的部份。

ISO 文件要錢,這裡 有ISO 13818-1文件(pdf)可以下載。這一篇文件就是說明這些協定的實際格式。
當初google pmt pat 沒有很多資料,原來要google : pmt pat decode。
這樣資料就很多。

台灣的數位電視頻道,ChannelSpace是6MHz ?

DvbT不都是8MHz的嗎?
用廠商的sample program怎麼樣都無法播放。
但是3rd party的demo program竟然可以。

感謝Linux的open structure,用3rd party的program tune好後, suspend。
用sample program的player部份play是OK。
所以專注在tuner部份。

雖然Demo program的document真的少,又像猜謎一樣。
但是一個一個try,還是可以暸解是甚麼用途。
==<所以把Tuner的status print 出來...... ??? NoCarrier !!!!
真是高興呀。

再度感謝3rd party software rd有print msg的態度,和Linux platform的open structure。
從run time log中對照SDK的setting properties,一個一個的照著Set。
結果?
==>竟然是Channel Spacing !!
我本以為這是最無關的,大概是在甚麼Fft, Hierarchy,,,,的。
竟然。
所以設好後,Status就是Carrier OK------雖然有些Signel Strength是負值。

所以一個一個,照著 這個網站的表格tune一下各個頻道,結果:

533 : CTV (-1)
545 : 公視
557 : 民視(-8)
581 : 台視(-4)
593 : 華視(-12)
...很蠢的是,從網站的表格可以看出,channel spacing真的是6MHz。

星期四, 12月 22, 2005

NFS ROOT : Linux , 使用NFS 作為rootfs

在kernel source的Document中就有一篇nfsroot.txt。照著裡面作就可以。

因為nfsroot是要mount nfs 上的path作為root,所以在此之前,他的root filesystem是不存在的。
所以nfs file system support 要build in在kernel中,不可以用 Module (.0)的方式(因為,.o 要放在那?)。
當然,網路 driver 也要內建(例如,你用rtl8192too,就要選 '*',不可以選'M')。

kernel 有mount nfs的能力後,接著就要"通知"kenel 是要用nfs 作為rootfs,並且要到那裡去mount nfs。這要靠kernel command line來完成:
告訴kernel 使用nfs作為rootfs,server path = /nfsroot:
root=/dev/nfs
設定nfs server address和path:
nfsroot=10.3.5.166:/nfsroot
設定client的 ip=10.3.5.123
nfs server=10.3.5.166
gw=10.3.4.254
netmask=255.255.252.0
hostname=""
使用eth0
不使用autoconfig來取的ip
 ip=10.3.5.123:10.3.5.166:10.3.4.254:255.255.252.0::eth0:off
這樣kernel 的動作就算ok了。
rebuild kernel, config bootloader,用這個kernel boot。

以 這個embedd system來說,他的bootloader內建romfs filesystem,會在flash中找romfs signature,並且找到romfs中的linux.bin.gz來開機,所以就要把build好的kernel.bin壓縮後,再用 genromfs 產生一個裡面只有linux.bin.gz這個檔案的romfs image,燒在flash中。讓bootloader能用這個linux image來開機。


接著就是server端,要準備好rootfs(可以使用genext2fs)。
修改nfs server的exports file
10.3.5.123   /nfsroot(rw)
重新啟動nfs server:
#/etc/init.d/nfs-kernel-server resart
OK,現在可以叫client 開機。
就可以看到client以NFS 作為 rootfs 開機成功了。
所以重點只有...
設定好kernel參數,裝備好需要的driver。
讓kernel開機。
一切就OK了。

NFS export出去的folder也可以用symbolic link
# ln -s /nfsroot  /home/develop/release1
或是
# ln -s /nfsroot /home/develop/test
這樣就可以輕易的讓linux使用不同的rootfs。
但 是要注意每次變更link後要重新啟動nfs-kernel-server才行。
我以前總覺得疑惑,mount root的動作有點雞生蛋,蛋生雞的感覺。因為/dev 是在 root 下,但是 root都還沒起來,kernel又怎麼去找 root 的 /dev 來mount 呢?
看 了init 的source code 才知道,init 的do_mounts( )裡面已經建好了 device name 對 device major/minor number的table,不需要由/dev去找。所以在/dev還沒建立好以前,kernel已經可以知道device的major/minor number是甚麼了。
知道major/minor number後,就可以到driver table中找到正確的device driver 了。
一個問題:
exports:
/nfsroot 10.3.5.123(rw)
/home/charles/sgm 10.3.5.123(rw)
但是
nfsroot--> /home/charles/sgm/root
也就是說 nfsroot實際是另一個export path的sub folder。
這樣使用nfsroot開機的機器(10.3.5.123)要mount /home/charles/sgm時會出現error :
mount: nfs warning: mount version newer than kernel
NFS: mount program didn't pass remote address!
failed, reason given by server: Permission denied
mount: nfsmount failed: Bad file descriptor
mount: Mounting 10.3.5.166:/home/charles/sigma on /tmp/sigma failed: Invalid arg
ument
...雖然從fail message中看不出原因是這個...




另一個

從configure和Makefie看來,使用nfs 作為roorfs,只有kernel boot command 有關。
(當然,kernel要build nfs file system和network driver)

Memo : 紀錄一下能作的事..

  1. fb + QT embedded
  2. NFS root OK
  3. 用direct register read/write 看associate memory 和 parallel spi 的動作
  4. 用microwin + ir 寫file manager
  5. usb flash driver OK
  6. try UART1 GPIO 為什麼不能動
TUNER :
from tuner 的 sample application 開始。
一個一個試....
(document 實在是太少了呀....) OK - 原來是ChannelSpacing 的關係,應該要是6MHz(default是8MHz)。

切換每個PAT中的PMT。

另一個web base 的msn - e-messenger

好像功能比microsoft的web base msn 還多,
但是在不知名的網站中輸入password,總是有點毛毛的。

不曉得突破firewall 的能力有沒有比較強。

星期一, 12月 19, 2005

Linux : Enable USB device - Mass Storage.

USB device filesystem 有點像/proc filesystem。是在runtime create。
Kernel Config中,Preliminary USB Device Filesystem 要Enable。

linux啟動後,用mount 指令來create usb device filesystem:
#mount -t usbdevfs none /proc/bus/usb
none 只是為了顯示用,有些人為了好看,會用usbfs 代替
這樣/proc/bud下就會出usb 這一個folder,裡面會有devices,drivers兩個檔案。

Mass Storage Devices .....

順便紀錄一下,今天 ..
microwindow 測試OK,可以正常工作。
IR remote 測試OK,
usb 測試,因為板子上好像有一個transformer沒焊,所以....

星期五, 12月 16, 2005

uclinux : 再找一次,Kernel command line: 的地方

想知道Kernel 怎麼依照boot argument 去找root file system,其實是想要再試試 root NFS。
boot message 有一行:
Kernel command line : root=/dev/blkmem/0
所以先找到"Kernel command line" 這一行是從那裡出來的,因為是boot messsage,所以從init 開始找:
$ cd init
$ grep "Kernel command line" *.c
結果告訴我是main.c,less main.c 用 " /Kernel command" 找到..
        setup_arch(&command_line);
printk("Kernel command line: %s\n", saved_command_line);
command_line 是local variable。所以取得位置是在setup_arch(),找..一個一個目錄的找..
        $ grep setup_arch arch -r
出現真的在arch 目錄。到arch/arm
        $ grep setup_arch * -r
原 來是在kernel/setup.c.. parse_cmdline( )把meminfo 的資料處理後,交給cmdline_p,parse_cmdline 處理boot argument的 "mem="和"initrd=" 兩個argument。所以setup_arch只是將boot argument 從public static variable中取出,交給這個cmdline_p,並且處了他需要知道的幾個boot argument。
include/linux/init.h:  extern struct kernel_parm__setup_start, __setup_end;
然後在
arch/armnommu/vmlinux-arm0.lds.in:   __setup_start = .;
和vmlinux.lds , vmlinux-armv.lds.in 也有。 所以應該又是用類似boot loader一樣,在link時將init argument -- init function pair locate 在image特定位置。

因為是lds - link script,所以找Makefile ,看看最後的link command.....
Linux 分成boot, init 和 ? N 大塊target。最後link起來成為linux kernel。
Makefile 最後將這部份產生System.map 這個map file,所以查查這個map file 裡面的symbol table,是不是有__setup_start,__setup_end這兩個mark...
900a2300 ? __setup_start
900a2308 ? __setup_debug_kernel
900a2310 ? __setup_quiet_kernel
900a2318 ? __setup_load_ramdisk
900a2320 ? __setup_readonly
900a2328 ? __setup_readwrite
900a2330 ? __setup_root_dev_setup
900a2338 ? __setup_root_data_setup
900a2340 ? __setup_fs_names_setup
900a2348 ? __setup_nohlt_setup
900a2350 ? __setup_hlt_setup
900a2358 ? __setup_reboot_setup
.......
900a23e0 ? __setup_netdev_boot_setup
900a23e8 ? __setup_netdev_boot_setup
900a23f0 ? __initcall_alignment_init
900a23f0 ? __initcall_start
900a23f0 ? __setup_end
果 然有,找一下__setup_root_dev_setup 這一個symbol : 在init/do_mounts.c,要用root_dev_setup 來找,因為__setup_ 開頭字樣是在所有function 宣告完後,用__setup ( )macro重新安排過,產生一個kernel_param 的structure 資料,放在 .setup.init 節區。
在include/linux/int.h 中定義了..
#define __setup(str, fn)   static char __setup_str_##fn[]                            __initdata = str;    static struct kernel_param  __setup_##fn  __attribute__((unused)) __initsetup = { __setup_str_##fn, fn }
.....
#define __initsetup __attribute__ ((unused,__section__ (".setup.init")))
這樣的定義,配合do_mounts.c中的..
static int __init root_dev_setup(char *line)
{
int i;
char ch;

ROOT_DEV = name_to_kdev_t(line);
memset (root_device_name, 0, sizeof root_device_name);
if (strncmp (line, "/dev/", 5) == 0) line += 5;
for (i = 0; i < sizeof root_device_name - 1; ++i)
{
ch = line[i];
if ( isspace (ch) || (ch == ',') || (ch == '\0') ) break;
root_device_name[i] = ch;
}
return 1;
}

__setup("root=", root_dev_setup);
將root_dev_setup function和"root=" 字串放在 .setup.init 節區。這樣,所有boot argument 字串和setup function,自動就會形成一個array,排列在__setup_start, __setup_end 之間。
init/main.c 就可以用:
static int __init checksetup(char *line)
{
struct kernel_param *p;

p = &__setup_start;
do {
int n = strlen(p->str);
if (!strncmp(line,p->str,n)) {
if (p->setup_func(line+n))
return 1;
}
p++;
} while (p < &__setup_end);
return 0;
}
一一check boot command字串內容是否有符合,call 對應的function。
所以我要找的應該是"root="字串,function是 root_dev_setup ---- name_to_kdev_t ,
使用root_dev_names[],裡面第一項就是"nfs",也就是說boot argument 是"root=/dev/nfs"
查這個name_to_kdev_t function就是要找到boot device的device number。
交給root_dev_setup設定給ROOT_DEV這個變數。

這樣查code發現,經過linker 作安排的code,要trace比較不容易。但是很多code好像都是這樣,像LinuxBIOS的init function也是。用function array的方式,一個一個call。
這樣的方法有一個問題是,array中的function 不可以有依賴關係。也就是 先後次序。因為用loader script 沒法安排啟動的順序。

星期四, 12月 15, 2005

GEM318 : Guardian Enclosure Manager Controller

GEM318 是SCSI 介面的 SAF-TE controller。支援
有I2C interface 作master或slave用。
當master時,GEM318可以讀取I2C的週邊,如LM75,EEPROM。
當slave用時,host/master可以經由這個介面讀取GEM318偵測的資料。

解決問題的log : romfs signature 與romfs auto probe..

環境:loader + linux kernel in ROMFS.

flash 中:
46000000 LOADER
46010000 STAGE2
46030000 ROMFS
ROMFS 中有linux kernel image (gzipped),這個bootloader是將kernel image 放在romfs中,bootloader要"認識"romfs,所以可以在romfs中找到linux image,把他解開。放到ram中,執行。

bootloader : 在flash的特定區域找romfs 的開頭字串(signature),loader內涵romfs filesystem,找到romfs 中的linux image。

Linux boot後,從boot argument中知道是從/dev/blkmem0中找rootfs。(blkmem driver內建flash的address map),所以kernel 啟動後也一樣在flash 中找romfs 的signature,,但是bootloader知道romfs真的起始位置(因為romfs也是他燒進flash的)。linux kernel 就不知道,所以他是從flash的開始位置開始找.......
這樣就有問題了: 如果我在bootloader內含一個romfs signature字串?
如果loader的code image真的很巧的包含一個romfs signature ?
linux kernel就會搞錯了。

以下就是這個問題:

因為在bootloader中enable network功能,所以size增加了,0x10000不夠,所以我重新規劃
46000000 LOADER
46020000 STAGE2
46040000 ROMFS
bootloader boot OK。但是kernel boot時卻找錯romfs...他認為romfs在46030000....
這就是上一次燒錄的romfs 起始位置,
<STAGE2是空的>
因為bootloader在燒錄loader自己和ROMFS時,只有erase需要的部份。所以才造成這個"殘留"問題。
--- 後來手動(在loader中enable all function,增加了erase arbitrary region)erase 了46030000 - 4603FFFF這一個sector後,就正常boot 了。

Debian : Install tftp server - tftpd

tftp 是一個很簡單的file transfer protocol,他使用udp,並且沒有很多handshaking,authorization的機制,Client 所需要的code比較檢單,所以常常用在許多resource limited 的embedded system 中,或是用在開機的時候。
因為tftp 不是一個常常會使用的服務,所以以standalone dameon的方式執行會一直站住記憶體,所以建議使用inetd的方式來安裝。
tftpd 的default安裝方式也是這樣(tftpd好像沒有辦法用daemon的方式安裝)
#aptitude install tftpd
安裝完後,/etc/inetd.conf 檔會有一行是tftpd的invoke 命令。最後一個argument是tftp 的export 目錄。debian default是 /boot,一般是用/tftpboot,所以要修改一下:
tftp   dgram  udp   wait   nobody   /usr/sbin/tcpd   /usr/sbin/in.tftpd   /tftpboot
之後要reload inetd:# /etc/init.d/inetd reload這樣就OK了。

測 試,測試要安裝tftp (client)
#aptitude install tftp
將一些file放到/tftpboot中測試傳送,client已經可以開始連線:
$tftp 10.3.7.xxx
tftp>get xxxxxxx
OK
---實際上client這一端我沒測試。

星期二, 12月 13, 2005

領導人? Solution

從電子時報看到這次商周,對紐約人壽董事長的訪談中,他的回答..
你可以說我不喜歡這樣的數字,這樣的數字不好看,獲利應該成長多一些,但這不是有效的管理,有效的管理是指,跟你的經理人說,我不喜歡這數字,但有三、四種做法可以改變這數字。

領導者的責任不只是指出問題,還要跟員工一起合作解決問題。你不能只把球丟給其他人,站在一旁抱怨。
哇,天哪,你有遇過那一個領導者真的能給你 改進的作法?
(我本來想寫 "有效的改進作法",後來想想,好像連"沒效的改進作法"也沒聽過..)

領導人都在抱怨的話,下面的人不就要去死了?

USB to Serial adaptor : Linux driver

想要在Linux 上使用USB轉RS232的cable。Google一下,發現kernel已經支援很多chip了。在
driver/usb/serial
目錄下。
查ATEN USB的chip好像是prolific的pl2303。在driver folder下的pl2303.c。
所以 應該 有支援。

星期日, 12月 11, 2005

歷史的作用

讓決策者在作決定時,能夠參考。
所以?
歷史是有重現性的。

也為了讓決策者有"正確"的參考,有必要時時刻刻對當前的決策做出反應,
以免.....

錯誤一再發生。

星期五, 12月 09, 2005

又到日月潭....

上次因為龍王颱風,沒住成,只好再去一次。
這次一樣先到豐原買牛丫糖。就是這一家:
DSC00713
然後就出發往鹿港去....先到 龍山寺...
DSC00769
果然是古老的建築,可能是快不行了,所以開始整修..
DSC00728DSC00729
但是還是可以進去...
DSC00730
DSC00726
廁所也一樣有開放:
DSC00725
龍山寺有導覽,上面寫...該到摸乳巷去看看....這個擠滿排隊的人的地方,就是摸乳巷了
DSC00736
真的是很窄,而且中間一段更窄,
DSC00741
這是旁邊正在蓋得利停車場,這樣就不用到處找停車的地方..
DSC00742
繼續往前走,有一家店擠了很多人..
DSC00767
原來是玉珍齋...有賣很多糕餅類的東西..
DSC00748
下一個點,就是"隘門"..
DSC00749
一路上,都是奇怪的商店,
DSC00751
DSC00752
大家都往這裡去...鹿港天后宮的牌樓..
DSC00756
進去後,原來是小吃的聚集地。
DSC00757
路底就是媽祖廟
DSC00759
DSC00762
果然也是歷史悠久..
DSC00761
DSC00763
DSC00765
還有一個專門解說的阿伯...
DSC00764
....其實他只是遊客...
裡面還有鹿港故時候的地圖....當然,每次有甚麼照相的景點,就一定會有一個大頭,待在那兒不肯走....
DSC00760
古色古香的媽祖廟,廁所可是很現代化的喔...
DSC00766
鹿港的騎樓有統一規劃,地板上都會有一個圖樣..
DSC00768
這樣,鹿港的行程就結束了...接著,往集集去,因為要買梅子...
以往免費停車的好地點,被拿來當競選總部,所以沒的停了..
DSC00770
買完梅子,,,這是集集車站的廁所。
DSC00771
車站外,有一群黑衣人在辦音樂會...
DSC00772
所以小火車雕像變成這樣...
DSC00773
然後,,,,就到飯店了,到的時候已經是晚上了..
DSC00780
房間挺不錯的,
DSC00782
每個房間都有面湖的小陽台..
DSC00784
第二天,遊湖,一人200,先到玄光寺..
DSC00801
路半路上的小狗
DSC00804
路上可以看到待會要去的拉魯島
DSC00805
這就是玄光寺
DSC00807
這是玄光寺的....?
DSC00812
這個...就是Stanley一直不肯承認進去住過的飯店...
DSC00820
這一家人,要提的是那個小弟弟...到拉魯島要下船時,小弟很臭屁的說: 爸爸不要扶我,我自己會下...結果,在眾人的面前,小弟弟用力一跳,本以為很帥氣,結果.....鞋子掉了,掉到船下Q_Q......
船長還說: 小弟弟,日月潭的魚不吃鞋子喔....
這...小弟長大會有陰影吧。從此失去自信。好可憐。
DSC00821
拉魯島逛完後就回到德化社。
接著就是往慈恩塔,,,,570 公尺的階梯。
DSC00845
這個是慈恩塔...
DSC00823
有幾層?
DSC00824
這是可以爬上去的
DSC00841
從塔頂可以看到日月潭的全景
DSC00832
運氣好(?)還會看到想不開的老外..
DSC00831
他是想要到...這裡嗎?
DSC00840
其實還是蠻美麗的..
DSC00843
慈恩塔繼續往下走,就是常常在日曆看到的...文武廟.
DSC00846
因為921的關係,到處都是煥然一新....
DSC00848
DSC00850
也有像日本的廟宇一樣,買個風鈴(?),寫下心願,掛在妙的屋簷下..
DSC00849
因為到處都在整修..所以只好回家..經過清水休息站..看看現在魚缸養的是? 又換了。汰換率真高.
DSC00852

網誌存檔