2012年10月6日 星期六

OpenWrt LED

無線路由器有許多 LED 顯示狀態。在 OpenWrt 下,如何控制 LED 呢?

除了電源狀態 (PWR) 是有電就亮,及一些 Ethernet 狀態 (WAN 和 LAN 1 2 3 4) 是 Ethernet Controller 直接控制外,其它 LED 是接到 SoC 的 GPIO,Linux Kernel 有個 platform 子系統,並有一些針對 GPIO 的現成驅動程式,例如驅動程式 leds-gpio 用來控制 LED。只要把 GPIO 的位置,所使用的驅動程式及功能在編譯前設定好,編譯後的 Linux Kernel 就能支援這些 GPIO。
  • 準備資料結構 struct gpio_led,內含每個 LED 名稱、GPIO 接腳、是否 low 動作等。例如:
    static struct gpio_led tl_wr1043nd_leds_gpio[] __initdata = {
        {
            .name        = "tl-wr1043nd:green:wlan",
            .gpio        = TL_WR1043ND_GPIO_LED_WLAN,
            .active_low    = 1,
        }
    };
    不清楚 LED 名稱為何要取 tl-wr1043nd:green:wlan 這麼一長串
  • 透過 platform_device_alloc() 取得使用 "leds-gpio" 的資料結構 struct platform_device。(相反是 platform_device_put())
  • 建構資料結構 struct gpio_led_platform_data,包括 LED 數目,及 leds 欄位指到 struct gpio_led
  • 透過 platform_device_add_data() 加進 struct gpio_led_platform_data
  • 透過 platform_device_add() 登記到 Linux Kernel
上述例子是在 Linux 的 arch/mips/ar71xx/mach-tl-wr1043nd.c 執行 arch/mips/ar71xx/dev-leds-gpio.c 裡的 ar71xx_add_device_leds_gpio() 完成的。

編譯後的 Linux 就會有 /sys/class/leds/tl_wr1043nd:green:wlan/  目錄。使用方式,例如
點亮 LED:
echo 1 > /sys/class/leds/tl_wr1043nd:green:wlan/brightness
熄滅 LED
echo 0 > /sys/class/leds/tl_wr1043nd:green:wlan/brightness
應該還有其它用法,待了解。

2012年9月21日 星期五

FXS 轉 UART

連接話機的界面是 FXS (Foreign eXchange Station),連接局端的界面是 (FXO, Foreign eXchange Office),FXS 或 FXO 轉換成其它界面叫 ATA (Analog Telephone Adaptor)。網路上可以找到兩個將 FXS 轉成 UART 的專題,都是 David Rowe 的傑作:一開始的「 $10 ATA」跟構想延伸的「Mesh Potato 的 FXS 界面」,想在無線路由器加 FXS 界面,而 UART 是無線路由器都有的界面,只藏在裡面的電路板上,baud rate 115 kbit/s 就夠 64 kbit/s 的語音使用。

「$10 ATA」後來也受到 Mesh Potato 影響,但最後資訊是去年三月,之後可能沒有進展,或者作者未公佈,主要缺如何一起在 UART 傳振鈴及 hook 資訊,跟整合測試。其架構如下:
     +---------------+   +--------------------+
     |     Hybrid    |<->|ADC/PWM             |
話機-| DC-DC/ringing |<->|PWM/ADC  ATmega328P |--UART
     | hook detector |-->|PWM                 |
     +---------------+   +--------------------+
ATmega328P 是 AVR 八位元微處理器,也用於 Arduino,可以處理類比訊號,用其 ADC 及 PWM 來轉換類比訊號。作者一系列文章:
Mesh Potato 已經是一個產品了,是一個含有 FXS 界面的戶外型 802.11bg mesh router,相當特別。架構如下:
     +--------+   +--------------------+  +------------+
     |        |<--|SPI                 |<-|GPIOs       |
話機-| Si3210 |   |       CPLD         |  |     AR2317 |
     |        |<->|TDM                 |->|UART Rx     |
     +--------+   +--------------------+  |            |
                  | ATmega8L(16B FIFO) |<-|UART Tx     |
                  +--------------------+  +------------+
AR2317 是 Atheros 的無線 MIPS 4KEc SoC,用於 AIR-300 等無線路由器。Si3210 是 FXS 界面晶片,包括 hybrid、DC-DC converter、振鈴、hook 偵測等,語音走 TDM,控制走 SPI。CPLD 主要是要轉換 UART 跟 TDM,但可能是內部 buffer 不夠,所以加 ATmega8L。

參考

  • Silvertel Ag2130 PSTN 界面模組。(RT03106)
  • USB FXS

FT232R

FT232R 是一個 USB 轉 UART 的晶片,整合 clock 及 EEPROM 等,讓線路非常簡單。有些 Arduino 含有 FT232R 來提供 USB 界面,例如 DuemilanoveDiecimila,但新的 Leonardo 使用 ATmega32u4 處理器已經內建 USB 了。FT232R 除了 UART 功能外,亦可作為 Clock 產生器,透過 bit bang 模式提供 GPIO 或 SPI 功能,或者作為 FTDIChip-ID™ security dongle 功能。
  • 相關文件:DatasheetBit Bang Application NoteFTDIChip-ID™ Application Note
  • 內建 128 bytes EEPROM 作為設定用,其中 Manufacturer, ManufacturerId, Description, SerialNumber 字串最長 96 bytes,沒用完的可作為 user area 或 FTDIChip-ID 使用。
  • 可產生 6/12/24/48 MHz clock
  • Big Band I/O
    • Asynchronous:UART 8 IO 作為 8-bit data,CBUS 提供 RD# 跟 WR# 訊號
    • Synchronous:同上
    • CBUS Mode:CBUS0~CBUS3 4-bit GPIO
  • 內建 3.3V 電源轉換,最大提供 50mA。
  • 驅動程式
    • Virtaul Com Port (VCP):變成一般序列埠使用
      • Linux: ftdi_sio → usbserial
    • Direct (D2XX):設定 EEPROM 及 bit bang 需要
    • libFTDI for Linux
      • 裡面的 ftdi_eeprom_build() 或 ftdi_eeprom_decode() 可看出 EEPROM 內容每個位址的定義。

FT232RL IO 訊號
PinName預設功能Bit Bang
CBUS modeAsynchronous / Synchronous
1TXD 輸出D0
5RXD 輸入D1
3RTS# 輸出 (Arduino Reset)D2
11CTS# 輸入D3
2DTR# 輸出 (Arduino Reset)D4
9DSR# 輸入D5
10DCD# 輸入D6
6RI# 輸入D7
23CBUS0TXLED# 輸出4-bit GPIO其中兩個作為 RD# 及 WR#
22CBUS1RXLED# 輸出
13CBUS2TXDEN 輸出,RS-485 用。
14CBUS3PWREN# 輸出,需外加 10kΩ pull high,USB 設定完 low,USB suspend 時 high。
12CBUS4SLEEP# 輸出,USB suspend 時 low。
CBUSx 都可以設定成任何 CBUS 功能,除了表列五種外,尚有 TX&RXLED#、6/12/24/48 MHz clock 輸出。

內部 EEPROM,整理自 datasheet 及 libFTDI。
parameteraddressvalue說明
High Current I/Os0.20
10x40IN endpoint size
Vendor ID3~20403hFTDI default VID
Product ID5~46001hFTDI default PID
Device Type7~60x06000x0600=FT232R
Battery Powered8.40
Remote Wake Up8.51RI# low → wake up USB Host Controller in 20 ms
Bus Powered 8.61
Load VCP Driver8.71Make the host to load VCP driver。此位置是猜測的。
Max Bus Power Current990mA以 2 mA 為單位
IN endpoint is isochronous0x0a.00
OUT endpoint is isochronous0x0a.10
Enable suspend I/O power down0x0a.20
Use serial number string0x0a.30
Change USB Version0x0a.40
Invert TXD0x0b0
Invert RXD0
Invert RTS#0
Invert CTS#0
Invert DTR#0
Invert DSR#0
Invert DCD#0
Invert RI#0
USB Version0x0d~0x0c0x0200USB 2.0 Full Speed
Manufacturer Offset0x0e.6~00x18指向 10, 0x03, "FTDI"
Manufacturer Enabled0xe.71
Manufacturer Size0x0f10byte 數含結尾 0,因每個字佔 2 bytes,所以需乘二
Product Description Offset0x10.6~00x24指向 32, 0x03, "FT232R USB UART"
Product Description Enabled0x10.71
Product Description Size0x1132
Serial Number Offset0x12.6~00x46指向 18, 0x03, "A6001dHI",A unique serial number
Serial Number Enabled0x12.71
Serial Number Size0x1318
CBUS00x14.3~030=TXDEN, 1=PWREN#, 2=RXLED#, 3=TXLED#, 4=TXRXLED#, 5=SLEEP#, 6=CLK48, 7=CLK24, 8=CLK12, 9=CLK6, 10=Bitbang IO mode, 11=Bitbang WR#, 12=Bitbang RD#
CBUS10x14.7~42
CBUS20x15.3~00
CBUS30x15.7~41
CBUS40x16.3~05
Dynamic Content0x18~0x7f見說明預設應該是放 Manufacturer, Production Description, 及 Serial 字串。字串含 0,每字佔兩個 byte。格式依序是長度,0x03,字串本身。
10, 0x03, "FTDI"
32, 0x03, "FT232R USB UART"
18, 0x03, "A6001dHI"
ChipID0x86~0x89見說明

USB 的請求控制指令:
  • reset (0x00)
  • set baud rate (0x01)
  • set data (0x02):設定 RS-232 參數
  • set flow control (0x03)
  • modem control (0x04):設定 DTR, RTS 等。
  • poll modem status (0x05)
  • set event char (0x06)
  • set error char (0x07)
  • set latency timer (0x09)
  • get latency timer (0x0a)
  • set bit mode (0x0b)
  • read pins (0x0c)
  • read eeprom (0x90)
  • write eeprom (0x91)

實際應用

2012年9月14日 星期五

2012年8月31日 星期五

NXT-G 教育版 2.1 軟體修正

小蘿蔔把 Humanoid 做好,我把示範程式下載來試看看,結果 NXT-G 教育版 2.1 要上載到 NXT 時出現錯誤:
A required file is broken
Error code : 1003
但讀取 NXT 狀態是正常的。此後要上載任何程式到 NXT 都會同樣的錯誤,必須把整個 NXT-G 關掉再重新執行,使用其它本來可以的程式才會正常。這個問題需要 NXT EDU: 2.1f3 Patch for Windows 解決,說明檔提到有一項修正剛好就是:
Opening certain programs results in not being able to download any programs, error code 1003
(打開特定程式後無法下載,錯誤代碼 1003)
NXT EDU: 2.1f3 Patch for Windows 下載回來、解開、執行裡面的 setup.exe 便可修正。

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 範例,以後再研究。

SIP header Via

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