หน้าเว็บ

วันอาทิตย์ที่ 16 ตุลาคม พ.ศ. 2554

วิธีแก้บั๊ก TinyOS two source files specified (PLATFORM_MICAZ and BOARD_MICASB) make: *** [exe0] Error 1

ปัญหาเกิดจากผมทำการอัพเดท Ubuntu 11.04 ไปเป็น 11.10 พออัพเดทแล้วลองคอมไพล์โปรแกรมปรากฏว่าคอมไพล์ไม่ผ่านโดยขึ้น error ประมาณนี้ครับ

two source files specified (PLATFORM_MICAZ and BOARD_MICASB)
make: *** [sim-exe] Error 1


ซึ่งตัว PLATFORM_ กับ BOARD_ อาจเป็นอื่นๆได้ เช่น PLATFORM_IRIS เป็นต้น

ปัญหานี้เกิดจากการที่ gcc ถูกอัพเกรดเป็นเวอร์ชัน 4.6 ซึ่งจะถูกเรียกใช้ในขั้นตอนของการคอมไพล์ TinyOS โปรแกรม

ปัญหาคือ gcc 4.6 จะเพิ่ม space 1 ตัว ไประหว่าง option -D กับ argument ทำให้ปกติแล้วในของเก่า gcc จะสร้าง -DPLATFORM_MICAZ กับ -DBOARD_MICASB ออกมา เพื่อให้ nescc (nesC compiler) เอาไปใช้งานต่อ แต่ของใหม่จะสร้าง -D PLATFORM_MICAZ กับ -D BOARD_MICASB ออกมาแทน ซึ่งทำให้ nescc คอมไพล์ไม่ได้และเกิด error ดังข้างบน

วิธีแก้คือ
1) ดาวน์โหลด nescc ตัวใหม่มา (ของผมที่ใหม่สุดคือ 1.3.2) http://sourceforge.net/projects/nescc/files/nescc/v1.3.2/nesc-1.3.2.tar.gz/download?_test=goal

2) แตกไฟล์ออกมา แล้วไปแก้ source code ที่ไฟล์ nesc-1.3.2/src/nesc-compile

3) หาบรรทัด

($i, $idir) = &extractarg($i);
push @nesc_args, "-I$idir";
}
elsif (/^-o/) {
($i, $objtarget) = &extractarg($i);
}


แก้โดยเพิ่มอีกเงื่อนไขไปเป็น

($i, $idir) = &extractarg($i);
push @nesc_args, "-I$idir";
}
elsif (/^-D/) {
($i, $ddef) = &extractarg($i);
pop @nesc_args;
push @nesc_args, "-D$ddef";
}
elsif (/^-o/) {
($i, $objtarget) = &extractarg($i);
}


4) เสร็จแล้วให้ออกมาที่โฟลเดอร์หลัก nesc-1.3.2 ทำการคอมไพล์โค้ด

./configure
make
sudo make install


5) ลองทดสอบดูว่า nescc ตัวใหม่ติดตั้งแล้วหรือยังโดยสั่ง

ncc --version

ผลลัพธ์ควรจะแจ้งเวอร์ชันของ nescc ออกมาเป็น 1.3.2

ถ้ายังไม่เป็นให้เรา move binary ใหม่ไปแทนเอง

sudo cp /usr/bin/nescc /usr/bin/nescc.old
sudo cp /path/to/nesc-1.3.2/tools/nescc /usr/bin/nescc


6) เมื่อเสร็จแล้วก็ลองสั่งคอมไพล์ TinyOS โปรแกรมใหม่อีกรอบ เช่น

make micaz sim

ก็น่าจะคอมไพล์ผ่านเรียบร้อย

ระบบที่ทดสอบ
OS: Ubuntu 11.10
TinyOS: 2.1.1
ncc: 1.2.4
gcc: 4.6.1
nescc: 1.3.2

อ้างอิง
http://sourceforge.net/tracker/index.php?func=detail&aid=3153727&group_id=56288&atid=480036

วันจันทร์ที่ 9 สิงหาคม พ.ศ. 2553

ใช้ printf library กับ TinyOS ผ่าน SerialForwarder

วันนี้ผมลองใช้ MoteLab ของ Harvard เพื่อจะทำการทดลองโปรแกรม TinyOS บนอุปกรณ์จริงจำนวนมาก ซึ่งผมลองดูตัวอย่างโค้ดของทาง MoteLab นั้นจะแสดงวิธีการเรียกค่าเก็บไว้ใน Message ที่ส่งผ่าน Master Serial Port ของทาง MoteLab

แต่ปัญหาต่อมาของผมคือตัวอย่างเหล่านั้นเป็นการส่งค่าประเภทที่เป็นตัวเลข ไม่ใช่ array และไม่ใช่ string ซึ่งที่ผมต้องการนั้นผมอยากจะใช้ library printf ของ TinyOS เพื่อแสดง String (ซึ่งเป็น array ของ char) แล้วส่งผ่านออกมาทาง Serial Port

ดังนั้นวิธีการของผมคือลองแกะโค้ดตัวอย่างของเค้าก่อนว่ามันต้องใช้ utility อะไรมาช่วยบ้าง ซึ่งโค้ดเค้านั้นเป็นภาษา python และมีการเรียกใช้ TestSerialMsg.py ซึ่งเป็น class ที่เก็บโครงสร้าง Message ที่ต้องการเอาไว้ ดังนั้นทำให้ผมพอจะเดาได้ว่าเราต้องมีการสร้าง PrintfMsg.py ขึ้นมาเพื่อใช้จัดการกับ Message ของไลบรารี printf ที่จะถูกส่งออกมา

ผมลองดู TestSerialMsg.py แล้วพบว่า class นั้นถูกสร้างมาจาก MIG ซึ่งใช้ในการ generate คลาสสำหรับโครงสร้าง Message นั้น แต่ว่าที่ผมเคยลองทำคือเอามา generate ออกมาเป็น .class ของภาษา java เท่านั้น ซึ่งตอนนั้นทำใน Makefile

ผมเลยลองสั่ง mig ดิบๆใน shell ดูก็พบว่ามันมี option ที่รองรับภาษา python ด้วย ดังนั้นผมจึงเริ่มไปไฟล์ที่เป็น structure ของ Message เริ่มต้นที่เป็นภาษา nesC ก่อน ก็พบว่ามันอยู่ที่ $(TOSROOT)/tos/lib/printf/printf.h

ดังนั้นก็ให้ไปที่ $(TOSROOT)/tos/lib/printf แล้วสั่งคำสั่งดังนี้

mig python -python-classname=PrintfMsg printf.h printf_msg -o PrintfMsg.py

จะได้ไฟล์ PrintfMsg.py ซึ่งไฟล์คลาสที่เก็บโครงสร้างของ Message แบบภาษา python ออกมา

ซึ่ง String นั้น Message นี้จะเก็บอยู่ตัวแปรอาเรย์ที่ชื่อ buffer ดังนั้นผมจึงลองไปดูที่ฟังก์ชัน getString_buffer() ที่ generate ออกมา และพบว่ามัน generate ผิด ไม่สามารถเรียกใช้ได้เพราะจะเกิด index out of bound นอกจากนั้นค่าที่ได้ยังไม่ใช่ String อีกด้วย โดยผมทำการแก้ไข 3 จุด คือ 1. เปลี่ยนขอบเขตเป็น 28 (จริงๆแล้วขึ้นค่า PRINTF_MSG_LENGTH ที่ define ไว้ใน printf.h) 2. ทำการจัดรูปเป็นเลขฐาน 16 แบบ 2 หลัก 3. ทำการแปลงเลขฐาน 16 ให้เป็น ascii character ซึ่งสุดท้ายแล้วฟังก์ชัน getString_buffer จะได้เป็นแบบนี้

import tinyos.message.Message
import binascii
...
...
def getString_buffer(self):
carr = "";
#for i in range(0, 4000):
for i in range(0, 28):
if self.getElement_buffer(i) == chr(0):
break
c = "%x" % (self.getElement_buffer(i) & 0xFF)
if (len(c) < 2):
carr += "0" + c
else:
carr += c
return binascii.unhexlify(carr)

*หมายเหตุ blog ผม indent มันเพี้ยน เวลาใช้จริงอย่าลืมจัด indent ให้ถูกต้อง

คราวนี้เวลานำไปใช้ก็ให้ลองดูตามตัวอย่าง TestSerial.py ของเค้า แล้วให้เพ่ิม

import PrintfMsg

แล้วเพิ่ม

self.mif.addListener(self, PrintfMsg.PrintfMsg)

และเวลาเรียกค่าออกมาให้ใช้

s = m.getString_buffer()

ก็จะได้ String ที่เกิดจากไลบรารี printf แล้วครับ แต่ว่าจะมีปัญหาเล็กน้อยคือถึงแม้เรา printf ออกมาเป็น String ยาวๆ แต่ว่าการส่งข้อมูลออกมาแต่ละครั้งจะเท่ากับความยาวที่กำหนดไว้เท่านั้น (ค่า default คือ 28) ดังนั้นมันจะตัดส่งออกมาทีละ 28 ตัวอักษร ถ้าต้องการให้มากกว่านั้นก็ลองไป compile ไลบรารี Printf กันใหม่ได้ครับ

ถ้าใครยังไม่เคยใช้ MoteLab เดี๋ยวว่างๆผมจะมาเขียนวิธีไว้ด้วยครับ

ระบบที่ทดสอบ
OS: Ubuntu 10.04
TinyOS: 2.1.1
Device: Harvard MoteLab

วันจันทร์ที่ 12 กรกฎาคม พ.ศ. 2553

วิธี get ค่า local time บน TinyOS

เราสามารถเรียกค่าเวลาของโหนดๆหนึ่งตั้งแต่มันเริ่มทำงานได้โดยใช้ component HilTimerMilliC
component นี้จะ provides interface LocalTime ก็ให้จัดการ wiring ให้เรียบร้อย
เวลาจะเรียกดูค่าก็ให้ใช้คำสั่ง call LocalTime.get()

ระบบที่ทดสอบ
OS: TinyOS 2.1.1

วันอาทิตย์ที่ 21 มิถุนายน พ.ศ. 2552

compile TinyOS-2.1.0 แบบ TOSSIM ไม่ได้

อันนี้อาจมีหลายสาเหตุ แต่สาเหตุที่ผมเพิ่งเจอล่าสุดคือ upgrade เป็น ubuntu 9.04 แล้วจากที่เคย compile ได้ก็ไม่ได้ซะงั้น
โดยอาการแรกของผมคือ มันฟ้อง หา g++ ไม่ได้
อันนี้แก้ง่ายมาก
sudo apt-get install g++
เป็นอันเรียบร้อย (g++ เป็น GNU C++ Compiler)

พอพ้น error แรกไปได้ติดปัญหาต่อไปคือ มันงอแงว่า หาไฟล์ Python.h ไม่เจอ
อันดับแรกเลยลองเช็คว่าเรามี file นี้อยู่ในเครื่องรึเปล่า โดยลองสั่ง
sudo find / -name Python.h
เพื่อใช้หา find ดูก็ได้ ถ้าเกิดมันบอกว่าไม่เจอ ซึ่งอาจเกิดจากการที่เราไม่มี python development package หรือไม่ก็เคยมี แแต่เป็นเวอร์ชันเก่า พอ upgrade เป็น 9.04 แล้วมันจะเปลี่ยน python เป็น 2.6 แล้วทำการ remove package ของเวอร์ชันเก่าทิ้ง ก็ให้แก้ download มาลงก่อนด้วย
sudo apt-get install python-dev
หรือถ้าต้องการระบุ version ของ python ก็ใช้เป็น
sudo apt-get install python2.5-dev
โดยเปลี่ยนเลข version ตามอัธยาศัย (ของผมคือลง python2.5 เพิ่มเข้าไปด้วย)

หลังจากลองใช้คำสั่งเดิมในการหาว่า Python.h อยู่ที่ไหนใหม่อีกครั้ง แบบของผมจะไปอยู่ที่
/usr/include/python2.5
ซึ่งให้จำ path นี้ไว้ แล้วไปแก้ในไฟล์ sim.extra ที่อยู่ใน $TOSROOT/support/make โดยให้เติมบรรทัดนี้เข้าไปใต้บรรทัด PFLAGS
CFLAGS += -I/usr/include/python2.5
และเปลี่ยนค่าของ PYTHON_VERSION ให้เป็นตัวที่เราใช้อยู่ ทั้งในไฟล์ sim.extra และ sim-fast.extra
PYTHON_VERSION=2.5
ซึ่งถ้าใครไม่รู้ว่า python ตัวเองเป็น version อะไรสามารถดูได้ด้วยคำสั่ง python -V

แล้วคราวนี้ลอง compile โปรแกรมให้เป็น tossim ใหม่อีกครั้ง ก็น่าจะผ่าน

ระบบที่ทดสอบ

TinyOS: 2.1.0 (via apt-get)
OS: Ubuntu 9.04

ที่มา
http://docs.tinyos.net/index.php/TOSSIM#Appendix_A:_Troubleshooting_TOSSIM_compilation

วันเสาร์ที่ 18 ตุลาคม พ.ศ. 2551

การกำหนดค่าที่เซนเซอร์แต่ละตัวอ่านได้ใน TinyDB บน TOSSIM

โดยปกติแล้วถ้า run TinyDB ด้วย TOSSIM นั้น ค่าที่เซนเซอร์แต่ละตัวอ่านได้ในแต่ละช่วงเวลานั้นจะเป็นค่าที่ random ขึ้นมา ซึ่งในบางสถานการณ์เราอาจต้องการ fix ค่า หรือต้องการให้ค่าที่อ่านได้เป็นไปตามสมการที่เรากำหนด (เช่น ในธีสิสผมเป็นต้นที่ต้องการ evaluate ว่าข้อมูลที่อ่านได้ กับข้อมูลที่มีอยู่ในระบบจริงนั้น ถูกต้องขนาดไหน เป็นต้น)

ซึ่ง TinyDB ถ้า compile แบบ make pc เพื่อให้ใช้ TOSSIM แล้วจะเห็นว่าใน Makefile นั้นมีการใช้ Micasb เป็น sensorboard ดังนั้นวิธีที่ผมแก้ง่ายที่สุดคือ ไปสร้าง component ที่ provides interface StdControl และ ADC โดยใน module นั้นก็ให้ทำการสร้าง command async command result_t ADC.getData() แล้วใน command นั้น ก็อาจจะให้ทำการตรวจสอบ TOS_LOCAL_ADDRESS แล้วก็สั่ง signal ADC.dataReady(VALUEที่ต้องการ); เป็นอันเสร็จ

สมมติว่าเราต้องการกำหนดค่าของเซนเซอร์อุณหภูมิ ก็ให้ไปที่ Temp.nc แล้วแก้ไข components PhotoTemp ให้มาใช้ component ของเราแทน และเปลี่ยนการ assign interface StdControl กับ TempADC มาใช้เป็นของเราแทนเช่นเดียวกัน

แล้วก็ทำการ compile ใหม่ เป็นอันเสร็จพิธีครับ

TinyDB บน TOSSIM ไม่แสดงผล

ปัญหาคือลอง run TinyDB โดยใช้ TOSSIM แล้ว ปรากฎว่า พอส่งคิวรีเข้าไปในระบบแล้ว ไม่ได้คำตอบกลับมา คือในหน้าที่เป็นกราฟไม่มีอะไรเกิดขึ้น

จริงๆแล้วไม่รู้ว่าปัญหาคืออะไรเหมือนกัน แต่แก้โดยการคอมไพล์ใหม่ซะเลย

ขั้นแรก
ไปที่ folder tinyos-1.x/apps/TinyDBApp แล้วสั่ง
make clean
ขั้นสอง
ไปที่ tinyos-1.x/tools/java
make clean
ขั้นสาม
ไปที่ tinyos-1.x/tools/java/net/tinyos/tinydb
make -f MakePC
ขั้นสี่
ไปที่ tinyos-1.x/apps/TinyDBApp อีกครั้ง
make -f MakePC pc
เป็นอันเสร็จ พอจะทำงานก็เปิดสอง shell
shell แรกไปที่ /tinyos-1.x/apps/TinyDBApp
./build/pc/main.exe
shell ที่สองไปที่ /tinyos-1.x/tools/java
java net.tinyos.tinydb.TinyDBMain -sim
Environment ที่ทดสอบ
TinyOS: 1.1.15 snapshot
TinyDB: 1.1.3
OS: Cygwin on WIndows XP

วันอังคารที่ 29 กรกฎาคม พ.ศ. 2551

การสร้าง Java class เพื่อใช้กับประเภทข้อมูลของ TinyOS

ในการเขียนโปรแกรมภาษา nesC นั้นส่วนใหญ่จะมีการสร้างประเภทตัวแปรไว้สำหรับจัดการกับ message ที่ส่งในระบบ หรือมีการประกาศค่าคงที่ต่างๆที่จะนำไปใช้ได้ โดยมักจะประกาศในไฟล์ .h หรือ header ไฟล์ เช่นเดียวกับภาษา C
แต่ถ้าเราจะเขียนโปรแกรมภาษาจาวาเพื่อทำการติดต่อข้อมูลกับระบบ sensor network ที่เขียนด้วยภาษา nesC นั้น เราก็จะต้องมีการสร้าง class บนภาษา Java เพื่อมารองรับ message นั้นๆ
ซึ่งใน TinyOS นั้นจะมี tool ที่ช่วยให้เราทำงานนี้ได้สบายขึ้น คือ MIG และ NCG

MIG
- Message Interface Generator
ตัวนี้จะเป็นตัวที่ใช้สร้าง class Java เพื่อจะรองรับ message ที่เราสร้างขึ้น

NCG- NesC Constant Generator
ตัวนี้จะทำหน้าที่ดึงค่า constant ต่างๆที่เราประกาศไว้ออกมาใส่ใน class Java

ก่อนอื่นผมขอสมมติว่า ผมทำ nesC app ไว้ที่ /opt/tinyos-1.x/apps/MyApp
โดยใน MyApp มีโฟลเดอร์ชื่่อ types ที่ใช้เก็บ header file ที่ใช้ประกาศประเภทข้อมูล message เอาไว้
และใน types มีไฟล์ชื่อ MyMsg.h ซึ่งภายในไฟล์มีการประกาศค่าคงที่ AM_TYPE และ message ไว้ คือ
// ไฟล์ MyMsg.h
enum AM_TYPE
{
AM_PINGMSG = 20,
AM_PINGREPLYMSG = 21,
};

typedef struct PingMsg
{
uint16_t hostid;
uint16_t seqno;
} PingMsg;

typedef struct PingReplyMsg
{
uint16_t hostid;
uint16_t seqno;
uint16_t origin;
uint16_t parent;
uint16_t depth;
} PingReplyMsg;

คราวนี้เราจะมาสร้าง class java โดยใช้ structure จากค่าเหล่านี้กัน

สมมติว่าเราจะสร้าง class java เอาไว้ใน MyApp/java ให้ทำการสร้างไฟล์ชื่อ Makefile เอาไว้ใน MyApp/java โดยมีเนื้อหาดังนี้ (สำหรับใครที่อ่านแล้วงงๆ ลองศึกษาเรื่องมีวิธีการทำ Makefile http://frank.mtsu.edu/~csdept/FacilitiesAndResources/make.htm)
// ไฟล์ Makefile
TOS = $(shell ncc -print-tosdir)
APPDIR = $(TOS)/../apps/MyApp

MIG = mig java
NCG = ncg java

MSGS = PingMsg.java ReplyPingMsg.java
CONST = PingConst.java

INITIAL_TARGETS = $(MSGS) $(CONST)

OTHER_CLEAN = cleanmig

ROOT = ../../../tools/java
include $(ROOT)/Makefile.include

PingMsg.java:
$(MIG) -java-classname=PingMsg $(APPDIR)/types/MyMsg.h PingMsg -o $@
$(JAVAC) $@

PingReplyMsg.java:
$(MIG) -java-classname=PingReplyMsg $(APPDIR)/types/MyMsg.h PingReplyMsg -o $@
$(JAVAC) $@

PingConst.java:
$(NCG) -java-classname=PingConst $(APPDIR)/types/MyMsg.h AM_PINGMSG AM_PINGREPLYMSG -o $@
$(JAVAC) $@

cleanmig:
rm -f $(MSGS) $(CONST)

โดยมีส่วนที่สำคัญคือ
MIG = mig java
NCG = ncg java

จะเป็นการสร้างค่าเพื่อใช้เรียกคำสั่ง mig และ ncg โดยให้สร้างเป็น class ประเภท java
MSGS = PingMsg.java ReplyPingMsg.java
CONST = PingConst.java

เป็นการระบุว่าเราจะสร้าง class ชื่ออะไรออกมาบ้าง ในที่นี่คือ PingMsg.java, ReplyPingMsg.java และ PingConst.java เพื่อเป็นประโยชน์เวลาสั่ง clean จะได้ตามลบได้หมดทุกตัว นั่นคือมันจะทำการ clean ทุกไฟล์ที่มีการประกาศไว้ใน MSGS และ CONST (ดูในโค้ด makefile ส่วนที่เป็น cleanmig ด้านล่างสุด) เพราะเวลาเราสั่ง make clean มันจะดูที่ค่าคงที่ OTHER_CLEAN ที่ประกาศไว้ ซึ่งในที่นี้เราให้เป็น cleanmig มันก็จะไปทำ cleanmig ซึ่งลบทุกอย่างที่ประกาศไว้ใน MSGS และ CONST นั่นเอง

include $(ROOT)/Makefile.include
ใช้ในการระบุ makefile ที่จะใช้ในการ compile java โดยไฟล์นี้จะชี้ไปที่ /opt/tinyos-1.x/tools/java/Makefile.include

PingMsg.java:
$(MIG) -java-classname=PingMsg $(APPDIR)/types/MyMsg.h PingMsg -o $@
$(JAVAC) $@

ทำการสร้างไฟล์ชื่อ PingMsg.java โดย
-java-classname เป็นการระบุชื่อไฟล์ java
$(APPDIR)/types/MyMsg.h เป็นการระบุ nesC header ไฟล์ที่เราต้องการจะดึงค่าออกมา
PingMsg เป็นชื่อ struct ที่เราประกาศไว้ใน nesC ไฟล์และจะเอามาทำเป็น java class
-o $@ สร้าง output ชื่อว่า PingMsg.java (@ คือชื่อที่เขียนไว้ที่บรรทัด PingMsg.java:)
$(JAVAC) $@ ทำการคอมไพล์ (ข้อควรระวัง เว้นวรรคด้านหน้านั้น ให้ใช้ tab(\t) หนึ่งครั้ง ห้ามเป็นเครื่องหมาย space ต่อกันหลายครั้ง)

ส่วนกรณีของ NCG นั้นก็จะคล้ายกัน แต่เปลียนจาก MIG เป็น NCG และสามารถระบุค่าคงที่ได้หลายตัวว่าจะเอาค่าอะไรออกมาบ้าง

พอสุดท้ายเราก็จะได้ PingMsg.java PingMsg.class PingReplyMsg.java PingReplyMsg.class PingConst.java และ PingConst.class เพื่อเอาไปใช้ในโปรแกรม java ของเราได้

ระบบที่ใช้ทดสอบ
TinyOS: 1.1.15 on cygwin