2012年8月31日 星期五

Linux 用 USB 跟 NXT 通訊

之前在「Linux 用藍牙跟 NXT 通訊的程式」透過藍牙跟 NXT 通,其實最直接是接 USB,一樣使用 NXT Communication Protocol。

網路上就有現成可執行的程式 -- t2n (Talk To NXT),下載,放好 udev 規則讓一般使用者有權限,便可使用:C++,使用 USB
wget  http://www-verimag.imag.fr/~raymond/edu/lego/t2n/t2n-0.4.tgz
tar xvf t2n-0.4.tgz
sudo cp t2n-0.4/udev/71-lego.rules /etc/udev/rules.d/
開啟 NXT,接上 USB,執行
./t2n-0.4/t2n -b -i -ls
就可以取到電池電壓、NXT 資訊、檔案列表,如下:
battery level = 7948mV
#### NXT INFOS ###############
protocol version=1.124 firmware version=1.28
NXT Name: NXT
Blutooth address: 16:53:17:7f:ffffffcf:00
Blutooth signal: 0
Free user flash: 77180
FILE:"Untitled-1.rxe" SIZE:4768
FILE:"Program.tmp" SIZE:13
FILE:"a.rpg" SIZE:13
FILE:"NVConfig.sys" SIZE:6
FILE:"DemoV2.rxe" SIZE:3996
FILE:"RPGReader.sys" SIZE:5908
FILE:"faceclosed.ric" SIZE:316
FILE:"faceopen.ric" SIZE:316
FILE:"Woops.rso" SIZE:2232
FILE:"! Startup.rso" SIZE:4084
FILE:"! Attention.rso" SIZE:881
FILE:"! Click.rso" SIZE:229
FILE:"Try-Color.rtm" SIZE:4346
FILE:"Try-Touch.rtm" SIZE:1238
FILE:"Try-Light.rtm" SIZE:684
FILE:"Try-Ultrasonic.rtm" SIZE:1208
FILE:"Try-Motor.rtm" SIZE:676
FILE:"Try-Sound.rtm" SIZE:638
FILE:"" SIZE:0
另外還可以上載、下載檔案,執行參數是:
  • -put <檔名> : 上載檔案
  • -get <檔名> : 下載檔案
t2n 是 GPL 版權,有原始碼讓你研究,是用 C/C++ 寫的。


另外列出一些網路上找到的其它程式,不過我沒試就是。

順便列一些 NXT USB 資訊


lsusb 輸出:
Bus 003 Device 006: ID 0694:0002 Lego Group Mindstorms NXT

sudo cat /sys/kernel/debug/usb/devices 輸出:
T:  Bus=03 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  6 Spd=12   MxCh= 0
D:  Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
P:  Vendor=0694 ProdID=0002 Rev= 0.00
S:  SerialNumber=001653177FCF
C:* #Ifs= 1 Cfg#= 1 Atr=c0 MxPwr=  0mA
I:* If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
E:  Ad=01(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms
E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms

2012年8月26日 星期日

Linux 用藍牙跟 NXT 通訊的程式

遙控 NXT 車最簡單應該是用 NXT 內建的藍牙,上林老師教的 NXT 藍牙遙控車,是用一個 NXT 透過藍牙控制另一個 NXT 車,我想來搞一個不一樣的遙控車。但我只有一個 NXT,手機也沒有藍牙,就先由電腦來控制,剛好有一個幾年前申辦網路送的藍牙耳機附的 Dongle DBT-122T 可用。

Windows 下有現成的藍牙程式可以控制 NXT,例如 NXT Remote--使用電腦鍵盤遙控NXT。我平常用 Linux 電腦較多,NXT 在 Linux 的資源沒有 Windows 那麼豐富,不過找到了這份簡報,裡面有一個透過藍牙讀取 NXT 電池電壓的 C 程式,測試紀錄如後。
  1. 電腦安裝藍牙及編譯程式:我的電腦跑 Ubuntu 12.04,但不是標準的,很多套件被我移除了。bluez 包括 Linux 的藍牙程式及工具,libbluetooth-dev 含編譯藍牙用的標頭檔,gcc 是 C compiler。
    sudo apt-get install bluez libbluetooth-dev gcc
  2. 開啟 NXT 藍牙功能
  3. 搜尋藍牙設備:使用 hcitool scan,會顯示 NXT 的 MAC 位址及名稱。MAC 位址在下一步寫程式時會用到。
    $ hcitool scan
    Scanning ...
     00:16:53:17:7F:CF NXT
    
  4. 電腦藍牙程式:藍牙通訊也是用 socket,通訊協定依照 NXT Communication Protocol,可到 Bluetooth Developer Kit 下載,Mindstorms NXT 與 Arduino之間的藍牙通訊 有一些說明。複製簡報中的程式,填上 NXT 的 MAC 位址,並修正一些錯誤,如下。
    /* nxt_getbattery.c */
    #include <stdio.h>
    // Socket, used for Bluetooth socket
    #include <sys/socket.h>
    #include <sys/types.h>
    
    // Bluetooth headers
    #include <bluetooth/bluetooth.h>
    #include <bluetooth/rfcomm.h>
    
    // Global Variables
    int nxtSocket;
    int init_bluetooth(char *btAddress)
    {
     struct sockaddr_rc addr={0};
     int status;
    
     /*-----------------------------------------------------------
      * SOCK_STREAM
      * Provides sequenced, reliable, two-way, connection-based
      * byte streams. An out-of-band data transmission
      * mechanism may be supported.
      *----------------------------------------------------------*/
    
     // Allocate a socket
     nxtSocket = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
    
     // Set what type and who to connect to
     addr.rc_family = AF_BLUETOOTH;
     addr.rc_channel = (uint8_t) 1;
     str2ba(btAddress, &addr.rc_bdaddr);
    
     // Connect to the NXT
     status = connect(nxtSocket, (struct sockaddr *)&addr, sizeof(addr) );
     if (status < 0) {
      perror("Error connecting Bluetooth");
      return status;
     }
     return 0;
    }
    
    /****************************************************************
     * * nxt get battery level
     * * this will get the battery level on the nxt
     * * returns: the battery level as an integer
     * ***************************************************************/
    #define MAX_MESSAGE_SIZE 64
    int nxt_getbattery(void)
    {
     /*------------------------------------------------------
      * * direct command format:
      * * {length/lsb, length/msb, byte 0, byte 1... byte n}
      * *
      * * for getbatterylevel (see direct commands):
      * * byte 0: 0x00
      * * byte 1: 0x0b
      * * length/lsb: 0x02, the command length is 2 bytes
      * *----------------------------------------------------*/
     char cmd[4]={0x02, 0x00, 0x00, 0x0b};
     char reply[MAX_MESSAGE_SIZE];
     int result;
     int blevel;
     int replylength;
     int error = 0;
     //- send request -----------------------------------------
     if ( (result = write(nxtSocket, cmd, 4)) < 0 ) {
      perror("error sending getbatterylevel command ");
      return result;
     }
    
     //- read reply -----------------------------------------
     // get bluetooth message length
     if ( (result = read(nxtSocket, reply, 2)) < 0) {
      perror("error receiving getbatterylevel reply ");
      return result;
     }
     replylength = reply[0] + (reply[1] * 256);
    
     // get return package
     if ( (result = read(nxtSocket, reply, replylength)) < 0) {
      perror("error receiving getbatterylevel reply ");
      return result;
     }
    
     // quick check to make sure we got everything
     if (replylength != result) {
      fprintf(stderr,
       "getbatterylevel : lengths do not match : %d != %d\n",
       replylength, result);
     }
    
     /*------------------------------------------------------
      * * return package format:
      * * {length/lsb, length/msb, byte0, byte1..., byten}
      * * for getbatterylevel:
      * * byte0: 0x02
      * * byte1: 0x0b
      * * byte2: status byte
      * * byte3-4: voltage in millivolts (uword)
      * * length/lsb: 0x05
      * *----------------------------------------------------*/
     // byte 0
     if (reply[0] != 0x02) {
      fprintf(stderr, "getbatterylevel : byte 0 : %hhx != 0x02\n", reply[0]);
      error = 1;
     }
     // byte 1
     //if (reply[1] != 0x13) {
     if (reply[1] != 0x0b) {
      fprintf(stderr, "getbatterylevel : byte 1 : %hhx != 0x0b\n", reply[1]);
      error = 1;
     }
     // byte 2
     if (reply[2] != 0x00) {
      fprintf(stderr, "getbatterylevel : byte 2, status : %hhx \n", reply[2]);
      error = 1;
     }
     if (error) {
      return -1;
     }
     // byte 3-4
     blevel = reply[3] + (reply[4] * 256);
     return blevel;
    }
    
    int main (void) {
     // nxt brick alpha bluetooth address
     //char btaddress[18] = "00:16:53:01:2c:84";
     char btaddress[18] = "00:16:53:17:7F:CF";
     int blevel;
    
     // initiate bluetooth connection
     if (init_bluetooth(btaddress) < 0) {
      close(nxtSocket);
      return 1;
     }
     printf("bluetooth connected to %s \n", btaddress);
     // get battery level (direct command)
     blevel = nxt_getbattery();
     if (blevel < 0) {
      close(nxtSocket);
      return 1;
     }
     printf("battery level: %.3f\n", blevel/1000.0);
     close(nxtSocket);
     return 0;
    }
    
  5. 編譯
    gcc nxt_getbattery.c -o nxt_getbattery -lm -lbluetooth
  6. 執行程式,NXT 會「ㄅㄧ」一聲顯示 Passkey: 1234,按橘色鈕確認會發生 Permission denied 錯誤,原來藍牙需要先配對一次。
    $ ./nxt_getbattery
    Error connecting Bluetooth: Permission denied
    
  7. 藍牙配對 (只有第一次需要,配對過後就不需要了):正常安裝的 Linux 可能會出現小視窗讓你輸入就解決了,可是我的電腦較慢,用較陽春的 LXDE 桌面,並移除了許多套件,並不會自動出現輸入 Passkey 的小視窗。找到這篇,裡面提到許多方式,但我偏好指令行,開另一個終端機,執行:
    bluetooth-agent 1234
  8. 最後執行成功,電壓只有 6.9 V,有點低。
    $ ./nxt_getbattery 
    bluetooth connected to 00:16:53:xx:xx:xx 
    battery level: 6.903
    
雖然是個簡單的程式,但是其它應用重要的基礎。簡報裡後面還有一個 NXT Mailbox 範例,以後再研究。

2012年4月7日 星期六

VirtualBox 共用資料夾

建立客端跟主端間共用使用的資料夾。

首先,客端必須安裝好客端額外功能
再來,主端要建立共用資料夾
  • 透過視窗選單「裝置」→「共用資料夾」,加入共用資料夾,設定
    • 資料夾路徑:選擇在主端的一個目錄。
    • 資料夾名稱:給一個名稱識別,後面識別時會用此名稱,但都小寫。
    • 是否
      • 唯讀:在客端不能寫入
      • 自動掛載:自動掛載到 media/sf_資料夾名稱,vboxsf 群組才能使用。(所有檔在在客端變成可執行,這樣不太好)
      • 永久性:屬於「機器資料夾」,會記下來;否則屬於「暫時資料夾」,關機後就消失了
最後,客端連結共用資料夾 (不同客端作業系統方式不同,這裡是 Ubuntu 10.04 Server 的情形)
sudo mount -t vboxsf -o rw,uid=<your-uid>,gid=<your-gid> <資料夾名稱小寫> <掛載點>
或在 /etc/fstab 加一行
<資料夾名稱小寫> <掛載點> vboxsf rw,uid=<your-uid>,gid=<your-gid> 0 0
使得在開機時自動掛載。

VirtualBox 安裝客端額外功能

在客端 (guest) 作業系統安裝完成後,可以再安裝客端額外功能,包括一些驅動程式及系統應用程式,讓主客間有更好的整合及效能。功能包括 (依據 VirtualBox 官網文件):
  • 滑鼠整合
  • 共用資料夾:跟主端共用,這是我會去安裝客端額外功能就是為了這個功能。
  • 更佳顯示支援:包括較高解析度非標準顯示模式,可以調整視窗大小及解析度,並提供 2D/3D 加速。
  • 支援無痕視窗
  • 通用主客通信通道
  • 時間同步:同步主端時間。
  • 跟主端共享剪貼簿
  • 自動登入
每個 VirtualBox 版本都有其對應的客端額外功能,最好兩者能維持一致,所以要用每個 VirtualBox 版本附的 VBoxGuestAdditions.iso 來安裝。
  1. 安裝編譯外部 kernel 模組環境
    • sudo apt-get update
    • sudo apt-get upgrade
    • sudo apt-get dist-upgrade (有可能更新 kernel 版本)
    • sudo apt-get install dkms (安裝 Dynamic Kernel Module Support,我的客端是 Ubuntu 10.04 Server,安裝的套件計有 binutils dkms fakeroot gcc gcc-4.4 libc-dev-bin libc6-dev libgomp1 linux-headers-2.6.32-40 linux-headers-2.6.32-40-generic linux-headers-generic linux-libc-dev manpages-dev,最後可移除)
  2. 掛載 VBoxGuestAdditions.iso 並執行
    • [VirtualBox VM 視窗] 裝置 → 插入 Guest Additions CD 映像 (相當於放入 VBoxGuestAdditions.iso 光碟給客端用)
    • sudo mount /dev/cdrom /mnt
    • sh /mnt/VBoxLinuxAdditions.run (由於沒視窗環境,所以安裝視窗系統驅動程式會失敗)
    • 重啟生效
去查 kernel 模組多了 vboxguest 及 vboxsf。

註:fedora 10 安裝客端額外功能 [參考來源]
先安裝
yum -y update kernel
yum -y install kernel-devel kernel-headers dkms gcc gcc-c++

2012年3月6日 星期二

初識 iSCSI

Synology DS212j 有支援 iSCSI,來了解一下這是什麼。

iSCSI (Internet SCSI) 是將 SCSI 硬碟的指令在 IP 網路上跑,類似網路芳鄰的一種網路儲存空間的通訊協定,不同的是網路芳鄰看到的儲存空間是一個可放檔案的目錄,而 iSCSI 看到的是更底層的硬碟,無論是實體的或虛擬的硬碟,可以對它格式化,決定使用的檔案系統,就像本機硬碟一樣。我想如果 BIOS 有支援的話,應該可以用當開機碟。一個 iSCSI 硬碟群稱為 iSCSI Target,會有一個 IQN 名稱給使用端 iSCSI Initiator 識別連接用。

這篇的比較結果,iSCSI 速度比網路芳鄰慢,且我的分享以檔案為主,而不是硬碟分享,所以暫且就不考慮使用 iSCSI。

整理一下 Synology 的儲存架構,由下而上分別為:
  • 實體硬碟是最基本儲存硬體。
  • 硬碟群組 (Disk Group) 由數個硬碟組成。(我的沒有這一層)
  • 儲存空間 (Volume) 可能是一個實體硬碟,或一個硬碟群組的全部或部份。
  • iSCSI LUN 代表一顆 iSCSI 硬碟,可放在某個儲存空間裡 (Synology 支援機動空間配置),或是一個硬碟群組的全部或部份。
  • iSCSI Target 代表一個硬碟群,可有一個或數個 iSCSI LUN,並有一個 IQN 名稱給 iSCSI Initiator 連接其下所有硬碟用。
一個 iSCSI 硬碟可讓多個 iSCSI Initiator 連結使用,但一般檔案系統會有檔案完整性問題,要特定檔案系統,如「VMware 虛擬主機檔案系統 (VMFS)」或「Oracle Cluster 檔案系統 (OCFS)」才適合。

在 Linux 的 iSCSI Initiator 是 open-iscsi,可參考「在Ubuntu中使用iSCSI Initiator連接至iSCSI Target」或「在Ubuntu 使用 iSCSI Initiator」。

2012年3月2日 星期五

Synology DS212j 初次使用

此時最重要的參考是快速安裝指南
  1. 內部至少裝上一顆硬碟。
  2. 接上網路、電源,開機。
  3. 在電腦安裝 Synology Assistant 並執行,會自動搜尋 Synology 設備。要 DS212j 開機完成,此時藍色電源燈恆亮,才能搜尋到。
  4. 透過 Synology Assistant 安裝 DSM (版本 3.2_1955) 到 DS212j,等候完成。
  5. 完成後 DS212j 會重開機,此時  SynologyAssistant 還在等候,最後會寫入設定。然後可開啟網頁 GUI 登入,可看到它正在新增「儲存空間 1」,包括檢查硬碟中及建立檔案系統,這會相當久,去做其它事吧。
  6.  「儲存空間 1」正常後,到「控制台」→「共用資料夾」新增共用資料夾後,就可以透過網路芳鄰存取。
DS212j 算是 Synology NAS 產品裡最省電的,存取中 17.6W (我放一顆 640GB 硬碟 Seagate ST3640323AS,實測是 11W),硬碟休眠中 5.5W (實測 4W)。最省電當然是把它關掉,長按電源鍵就會啟動關機程序,最後關閉電源,是很友善的設計。

DS212j 沒有 WOL,應該是處理器 88F6281 不支援。但有定時開關機功能,以每週為排程週期,時間一到會自動關機,也會自動開機喔,神奇吧。如果可以設定一次性的關開機那就更好了,例如已經事先知道停電時間,設定好就可以在停電前關機,復電後自動開機,回復所有服務。

[2012/03/09 補充] 新增一顆 1TG 硬碟 WD10EARX
[2012/03/07 補充] 2012/03/06 Synology 釋出 DSM 4.0-2197
[2012/03/07 補充] DS212j 前身 DS211j 使用韌體 3.2beta 跟 QNap TS-212 詳盡的比較:QNap TS-212 NAS vs Synology DS-211j

2012年1月20日 星期五

Ubuntu 家目錄漢文目錄名稱改為英文

2013/12/3 補充:LANG=C xdg-user-dirs-gtk-update 勾選「Don't ask me this again」,然後按「Update Names」也可以

參考太武山人:改更 Ubuntu 中文目錄名稱,但作一些簡化,並借用 4$ 的圖來說明
1.進 Terminal 先把語系設成英文
export LANG=en_US
2. 執行更新名稱程式
xdg-user-dirs-gtk-update
出現如下圖,勾選 Don't ask me this again,然後按 Update Names (不是 Keep Old Names 喔)

SIP header Via

所有 SIP 訊息 都要有 Via,縮寫 v。一開始的 UAC 和後續途經的每個 proxy 都會疊加一個 Via 放傳送的位址,依序作為回應的路徑。 格式 sent-protocol sent-by [ ;branch= branch ][ ; 參數 ...] s...