2010年11月3日 星期三

Intent 用法大公開[轉]

轉自:http://ysl-paradise.blogspot.com/2008/12/intent.html
How to use Intent to send an email, SMS, open a web browser, show map, etc.?

Intent 應該算是 Andorid 中特有的東西。你可以在 Intent 中,指定要應用程式執行的動作 (view, edit, dial),以及應用程式執行該動作時,所需要的資料。都指定好後,只要透過 startActivity(),Android 系統會自動尋找,最符合你指定要求的應用程式,並喚起執行該應用程式。

不過,這部份的文件還不是很完整。Reference of Available Intents 有列一些。底下是我收集的一些用法,分享出來給有需要的你。有些還沒有實際驗證過,如果發現有錯誤,或有新的用法,也請告訴我。

顯示網頁

Uri uri = Uri.parse("http://google.com");
Intent it = new Intent(Intent.ACTION_VIEW, uri);
startActivity(it);
顯示地圖

Uri uri = Uri.parse("geo:38.899533,-77.036476");
Intent it = new Intent(Intent.ACTION_VIEW, uri);
startActivity(it);
//其他 geo URI 範例
//geo:latitude,longitude
//geo:latitude,longitude?z=zoom
//geo:0,0?q=my+street+address
//geo:0,0?q=business+near+city
//google.streetview:cbll=lat,lng&cbp=1,yaw,,pitch,zoom&mz=mapZoom
路徑規劃

Uri uri = Uri.parse("http://maps.google.com/maps?f=d&saddr=startLat%20startLng&daddr=endLat%20endLng&hl=en");
Intent it = new Intent(Intent.ACTION_VIEW, uri);
startActivity(it);
//where startLat, startLng, endLat, endLng are a long with 6 decimals like: 50.123456
撥打電話

//叫出撥號程式
Uri uri = Uri.parse("tel:0800000123");
Intent it = new Intent(Intent.ACTION_DIAL, uri);
startActivity(it);
//直接打電話出去
Uri uri = Uri.parse("tel:0800000123");
Intent it = new Intent(Intent.ACTION_CALL, uri);
startActivity(it);
//用這個,要在 AndroidManifest.xml 中,加上
//
傳送 SMS/MMS

//叫起簡訊程式
Intent it = new Intent(Intent.ACTION_VIEW);
it.putExtra("sms_body", "The SMS text");
it.setType("vnd.android-dir/mms-sms");
startActivity(it);
//傳送簡訊
Uri uri = Uri.parse("smsto:0800000123");
Intent it = new Intent(Intent.ACTION_SENDTO, uri);
it.putExtra("sms_body", "The SMS text");
startActivity(it);
//傳送 MMS
Uri uri = Uri.parse("content://media/external/images/media/23");
Intent it = new Intent(Intent.ACTION_SEND);
it.putExtra("sms_body", "some text");
it.putExtra(Intent.EXTRA_STREAM, uri);
it.setType("image/png");
startActivity(it);

//如果是 HTC Sense 手機,你要用
Intent sendIntent = new Intent("android.intent.action.SEND_MSG");
sendIntent.putExtra("address", toText);
sendIntent.putExtra(Intent.EXTRA_SUBJECT, "subject");
sendIntent.putExtra("sms_body", textMessage);
sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse(url));
sendIntent.setType("image/jpeg");
startActivity(sendIntent);

//底下這段更好,可在所有手機上用
//refer to http://stackoverflow.com/questions/2165516/sending-mms-into-different-android-devices
Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.parse("mmsto:");
intent.putExtra("address", );
intent.putExtra("subject", );
startActivity(intent);
傳送 Email

Uri uri = Uri.parse("mailto:xxx@abc.com");
Intent it = new Intent(Intent.ACTION_SENDTO, uri);
startActivity(it);
Intent it = new Intent(Intent.ACTION_SEND);
it.putExtra(Intent.EXTRA_EMAIL, "me@abc.com");
it.putExtra(Intent.EXTRA_TEXT, "The email body text");
it.setType("text/plain");
startActivity(Intent.createChooser(it, "Choose Email Client"));
Intent it=new Intent(Intent.ACTION_SEND);
String[] tos={"me@abc.com"};
String[] ccs={"you@abc.com"};
it.putExtra(Intent.EXTRA_EMAIL, tos);
it.putExtra(Intent.EXTRA_CC, ccs);
it.putExtra(Intent.EXTRA_TEXT, "The email body text");
it.putExtra(Intent.EXTRA_SUBJECT, "The email subject text");
it.setType("message/rfc822");
startActivity(Intent.createChooser(it, "Choose Email Client"));
//傳送影音附件檔
Intent it = new Intent(Intent.ACTION_SEND);
it.putExtra(Intent.EXTRA_SUBJECT, "The email subject text");
it.putExtra(Intent.EXTRA_STREAM, Uri.parse("file:///sdcard/mysong.mp3"));
it.setType("audio/mp3");
startActivity(Intent.createChooser(it, "Choose Email Client"));
//傳送圖片附件檔
Intent it = new Intent(Intent.ACTION_SEND);
it.putExtra(Intent.EXTRA_SUBJECT, "The email subject text");
it.putExtra(Intent.EXTRA_STREAM, Uri.parse("file:///sdcard/mypic.jpg"));
it.setType("image/jpeg");
startActivity(Intent.createChooser(it, "Choose Email Client"));
顯示聯絡人清單

Intent it = new Intent(Intent.ACTION_VIEW, People.CONTENT_URI);
startActivity(it);
顯示某個朋友的詳細資料

Uri uriPerson = ContentUris.withAppendedId(People.CONTENT_URI, 5); //5 是朋友的 ID
Intent it = new Intent(Intent.ACTION_VIEW, uriPerson);
startActivity(it);
播放多媒體

Intent it = new Intent(Intent.ACTION_VIEW);
Uri uri = Uri.parse("file:///sdcard/song.mp3");
it.setDataAndType(uri, "audio/mp3");
startActivity(it);
Uri uri = Uri.withAppendedPath(MediaStore.Audio.Media.INTERNAL_CONTENT_URI, "1");
Intent it = new Intent(Intent.ACTION_VIEW, uri);
startActivity(it);
從圖庫中回傳選到的圖片

Intent it = new Intent(Intent.ACTION_GET_CONTENT);
it.addCategory(Intent.CATEGORY_OPENABLE);
it.setType("image/*");
startActivityForResult(it, 0);
//回傳的圖片可透過 it.getData() 取得圖片之 Uri
啟動照相機,並將相片存在指定的檔案中

Intent it = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
//假設你要將相片存在 /sdcard/xxx.jpg 中
File f = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/xxx.jpg");
it.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
startActivity(it, 0);
Market 相關

//尋找某個應用程式
Uri uri = Uri.parse("market://search?q=pname:pkg_name");
Intent it = new Intent(Intent.ACTION_VIEW, uri);
startActivity(it);
//where pkg_name is the full package path for an application
//顯示某應用程式詳細畫面
Uri uri = Uri.parse("market://details?id=pkg_name_or_app_id");
Intent it = new Intent(Intent.ACTION_VIEW, uri);
startActivity(it);
//where app_id is the application ID, find the ID
//by clicking on your application on Market home
//page, and notice the ID from the address bar
Uninstall 應用程式

Uri uri = Uri.fromParts("package", strPackageName, null);
Intent it = new Intent(Intent.ACTION_DELETE, uri);
startActivity(it);
安裝 APK 檔

Uri uri = Uri.parse("url_of_apk_file");
Intent it = new Intent(Intent.ACTION_VIEW, uri);
it.setData(uri);
it.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
it.setClassName("com.android.packageinstaller",
"com.android.packageinstaller.PackageInstallerActivity");
startActivity(it);
//make sure the url_of_apk_file is readable for all users

2010年10月22日 星期五

計算cpu的速度,整數版

bogomis=`cat /proc/cpuinfo | egrep -i '^bogomips' | sed -e 's/^.*: //' -e 's/\..*//'`

2010年10月9日 星期六

Complier Qt 4.6.3軟體

[轉]http://hi.baidu.com/jinshiloveguai/blog/item/ca14360273d6448ae950cd06.html

0:安裝在unbutu上的軟體
apt-get install autoconf(或autoconf2.13)
apt-get install automake
apt-get install libtool


1.解壓qt-everywhere-opensource-src-4.6.3.tar.gz

#tar zxvf qt-everywhere-opensource-src-4.6.3.tar.gz
#mv qt-everywhere-opensource-src-4.6.3 qt-everywhere-opensource-src-4.6.3-arm

解压及编译触摸屏软件

解壓縮及編譯touch Pantslib1.4.tar.gz
A、安装编译过程需用到的程序

B、配置编译
tar xzvf tslib-1.4.tar.gz
cd tslib1.4

#vi build.sh
修改该脚本文件为如下:
#/bin/sh
export CC=arm-linux-gcc
./autogen.sh
echo "ac_cv_func_malloc_0_nonnull=yes" >arm-linux.cache
./configure --host=arm-linux --cache-file=arm-linux.cache -prefix=/usr/local/tslib

make
make install
推出保存后编译:
#./build.sh

3、编译QT/E库
#cd /usr/local/qt/qt-everywhere-opensource-src-4.6.3-arm

#cp -a /usr/localtslib/lib/* qt-everywhere-opensource-src-4.6.3-arm/lib/
#cp -a /usr/local/tslib/include/ts* qt-everywhere-opensource-src-4.6.3-arm/include/

QTE/configure时的参数
./configure -qt-kbd-tty -qt-gfx-linuxfb -no-gfx-transformed -no-gfx-multiscreen -qt-mouse-pc -no-gfx-qvfb -no-gfx-vnc -qt-kbd-tty -qt-gfx-linuxfb -no-gfx-qvfb -no-gfx-vnc -qt-mouse-tslib -no-glib -prefix /usr/local/Trolltech/QtE4.6.3-arm -embedded arm -release -shared -fast -no-largefile -qt-sql-sqlite -no-qt3support -no-xmlpatterns -no-mmx -no-3dnow -no-sse -no-sse2 -no-svg -no-webkit -qt-zlib -qt-gif -qt-libtiff -qt-libpng -qt-libmng -qt-libjpeg -make libs -nomake tools -nomake examples -nomake docs -nomake demo -no-nis -no-cups -no-iconv -no-dbus -no-openssl -xplatform qws/linux-arm-g++ -little-endian -qt-freetype -depths 16,18 -I/usr/local/tslib/include -L/usr/local/tslib/lib

使用4.3.2交叉编译器基本上没出现什么错误,但是使用3.4.6刚开始编译出现了以下错误:text/qfontengine_ft.cpp: In member function `bool QFontEngineFT::init(QFontEngine::FaceId, bool, QFontEngineFT::GlyphFormat)':
text/qfontengine_ft.cpp:696: warning: converting to `int' from `qreal'
{standard input}: Assembler messages:
{standard input}:781: Error: register or shift expression expected -- `orr r3,r2,lsl#16'
{standard input}:792: Error: register or shift expression expected -- `orr r2,r3,lsl#16'
{standard input}:7752: Error: register or shift expression expected -- `orr r3,r0,lsl#16'
{standard input}:7765: Error: register or shift expression expected -- `orr r1,r0,lsl#16'
make[1]: *** [.obj/release-shared-emb-arm/qfontengine_ft.o] 错误 1
make[1]:正在离开目录 `/usr/local/qt/qt-everywhere-opensource-src-4.6

苦思不得其解,最后还是上网查了查,发现解决方法为:

把~/qt-everywhere-opensource-src-4.6.0/src/3rdparty/freetype/include/freetype/config/ftconfig.h 这个文件的第330行改一下

原来是:

"orr %0, %2, lsl #16\n\t" /* %0 |= %2 << 16 */

改成:

"orr %0, %0, %2, lsl #16\n\t" /* %0 |= %2 << 16 */

这个问题解决了,删除原来的目录重新解压继续编译,又出现以下错误:../3rdparty/javascriptcore /JavaScriptCore/wtf/Platform.h:298:6: #error "Not supported ARM architecture"
make[1]: *** [obj/release/pcre_compile.o] 错误 1
make[1]:正在离开目录 `/usr/local/qt/qt-everywhere-opensource-src-4.6.3-arm/src/script'
make: *** [sub-script-make_defaulrgefile

解决方法:add a line in your ./configure parameters, such as "-D__ARM_ARCH_5TEJ__" , or whichever architecture definition that suits the platform.
就是在./configure参数后面增加一个"-D__ARM_ARCH_5TEJ__"

所以前面的配置参数应该为./configure -qt-kbd-tty -qt-gfx-linuxfb -no-gfx-transformed -no-gfx-multiscreen -qt-mouse-pc -no-gfx-qvfb -no-gfx-vnc -qt-kbd-tty -qt-gfx-linuxfb -no-gfx-qvfb -no-gfx-vnc -qt-mouse-tslib -no-glib -prefix /usr/local/Trolltech/qte4.6.3-arm -embedded arm -release -shared -fast -no-largefile -qt-sql-sqlite -no-qt3support -no-xmlpatterns -no-mmx -no-3dnow -no-sse -no-sse2 -no-svg -no-webkit -qt-zlib -qt-gif -qt-libtiff -qt-libpng -qt-libmng -qt-libjpeg -make libs -nomake tools -nomake examples -nomake docs -nomake demo -no-nis -no-cups -no-iconv -no-dbus -no-openssl -xplatform qws/linux-arm-g++ -little-endian -qt-freetype -depths 16,18 -I/usr/local/tslib/include -L/usr/local/tslib/lib -v -D__ARM_ARCH_5TEJ__

继续编译没有什么错误了,然后make install

最后是cp lib和字体,以及设置环境变量。到这里移植先告一段落!

2010年9月23日 星期四

Backtrace的方法

‧ 版權聲明:轉載時請以超鏈結形式標明文章原始出處和作者資訊及本聲明

http://chenzhuoyou.blogbus.com/logs/35484209.html

程式在得到一個Segmentation
fault這樣的錯誤資訊毫無保留地就跳出來了,遇到這樣的問題讓人很痛苦,查找問題不亞於你N多天辛苦勞累編寫代碼的難度。那麼有沒有更好的方法可以在產生SIGSEGV信號的時候得到調試可用的資訊呢?看看下面的常式吧!



sigsegv.h

#ifndef __sigsegv_h__

#define __sigsegv_h__

#ifdef __cplusplus

extern "C" {

#endif



int setup_sigsegv();



#ifdef __cplusplus

}

#endif



#endif /* __sigsegv_h__ */



sigsegv.c



#define _GNU_SOURCE

#include <memory.h>

#include <stdlib.h>

#include <stdio.h>

#include <signal.h>

#include <ucontext.h>

#include <dlfcn.h>

#include <execinfo.h>

#ifndef NO_CPP_DEMANGLE

#include <cxxabi.h>

#endif



#if defined(REG_RIP)

# define SIGSEGV_STACK_IA64

# define REGFORMAT "%016lx"

#elif defined(REG_EIP)

# define SIGSEGV_STACK_X86

# define REGFORMAT "%08x"

#else

# define SIGSEGV_STACK_GENERIC

# define REGFORMAT "%x"

#endif



static void signal_segv(int signum, siginfo_t* info, void*ptr) {

static const char *si_codes[3] = {"", "SEGV_MAPERR", "SEGV_ACCERR"};



size_t i;

ucontext_t *ucontext = (ucontext_t*)ptr;



#if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64)

int f = 0;

Dl_info dlinfo;

void **bp = 0;

void *ip = 0;

#else

void *bt[20];

char **strings;

size_t sz;

#endif



fprintf(stderr, "Segmentation Fault!\n");

fprintf(stderr, "info.si_signo = %d\n", signum);

fprintf(stderr, "info.si_errno = %d\n", info->si_errno);

fprintf(stderr, "info.si_code = %d (%s)\n", info->si_code, si_codes[info->si_code]);

fprintf(stderr, "info.si_addr = %p\n", info->si_addr);

for(i = 0; i &lt; NGREG; i++)

fprintf(stderr, "reg[%02d] = 0x" REGFORMAT "\n", i, ucontext->uc_mcontext.gregs[i]);



#if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64)

# if defined(SIGSEGV_STACK_IA64)

ip = (void*)ucontext->uc_mcontext.gregs[REG_RIP];

bp = (void**)ucontext->uc_mcontext.gregs[REG_RBP];

# elif defined(SIGSEGV_STACK_X86)

ip = (void*)ucontext->uc_mcontext.gregs[REG_EIP];

bp = (void**)ucontext->uc_mcontext.gregs[REG_EBP];

# endif



fprintf(stderr, "Stack trace:\n");

while(bp && ip) {

if(!dladdr(ip, &dlinfo))

break;



const char *symname = dlinfo.dli_sname;

#ifndef NO_CPP_DEMANGLE

int status;

char *tmp = __cxa_demangle(symname, NULL, 0, &status);



if(status == 0 && tmp)

symname = tmp;

#endif



fprintf(stderr, "% 2d: %p <%s+%u> (%s)\n",

++f,

ip,

symname,

(unsigned)(ip - dlinfo.dli_saddr),

dlinfo.dli_fname);



#ifndef NO_CPP_DEMANGLE

if(tmp)

free(tmp);

#endif



if(dlinfo.dli_sname && !strcmp(dlinfo.dli_sname, "main"))

break;



ip = bp[1];

bp = (void**)bp[0];

}

#else

fprintf(stderr, "Stack trace (non-dedicated):\n");

sz = backtrace(bt, 20);

strings = backtrace_symbols(bt, sz);



for(i = 0; i < sz; ++i)

fprintf(stderr, "%s\n", strings[i]);

#endif

fprintf(stderr, "End of stack trace\n");

exit (-1);

}



int setup_sigsegv() {

struct sigaction action;

memset(&action, 0, sizeof(action));

action.sa_sigaction = signal_segv;

action.sa_flags = SA_SIGINFO;

if(sigaction(SIGSEGV, &action, NULL) < 0) {

perror("sigaction");

return 0;

}



return 1;

}



#ifndef SIGSEGV_NO_AUTO_INIT

static void __attribute((constructor)) init(void) {

setup_sigsegv();

}

#endif



main.c



#include "sigsegv.h"

#include <string.h>



int die() {

char *err = NULL;

strcpy(err, "gonner");

return 0;

}



int main() {

return die();

}



下面來編譯上面的main.c程式看看將會產生什麼樣的資訊呢,不過要注意的就是如果要在你的程式裏引用sigsegv.h、sigsegv.c得到堆疊資訊的話記得加上-rdynamic
-ldl參數。



/data/codes/c/test/backtraces $ gcc -o test -rdynamic -ldl -ggdb -g sigsegv.c
main.c

/data/codes/c/test/backtraces $ ./test

Segmentation Fault!

info.si_signo = 11

info.si_errno = 0

info.si_code = 1 (SEGV_MAPERR)

info.si_addr = (nil)

reg[00] = 0x00000033

reg[01] = 0x00000000

reg[02] = 0xc010007b

reg[03] = 0x0000007b

reg[04] = 0x00000000

reg[05] = 0xb7fc8ca0

reg[06] = 0xbff04c2c

reg[07] = 0xbff04c1c

reg[08] = 0xb7f8cff4

reg[09] = 0x00000001

reg[10] = 0xbff04c50

reg[11] = 0x00000000

reg[12] = 0x0000000e

reg[13] = 0x00000006

reg[14] = 0x080489ec

reg[15] = 0x00000073

reg[16] = 0x00010282

reg[17] = 0xbff04c1c

reg[18] = 0x0000007b

Stack trace:

1: 0x80489ec <die+16> (/data/codes/c/test/backtraces/test)

2: 0x8048a16 <main+19> (/data/codes/c/test/backtraces/test)

End of stack trace

/data/codes/c/test/backtraces $



下面用gdb來看看出錯的地方左右的代碼:



/data/codes/c/test/backtraces $ gdb ./test

gdb> disassemble die+16

Dump of assembler code for function die:

0x080489dc <die+0>: push %ebp

0x080489dd <die+1>: mov %esp,%ebp

0x080489df <die+3>: sub $0x10,%esp

0x080489e2 <die+6>: movl $0x0,0xfffffffc(%ebp)

0x080489e9 <die+13>: mov 0xfffffffc(%ebp),%eax

0x080489ec <die+16>: movl $0x6e6e6f67,(%eax)

0x080489f2 <die+22>: movw $0x7265,0x4(%eax)

0x080489f8 <die+28>: movb $0x0,0x6(%eax)

0x080489fc <die+32>: mov $0x0,%eax

0x08048a01 <die+37>: leave

0x08048a02 <die+38>: ret

End of assembler dump.

gdb&gt;



也可以直接break *die+16進行調試,看看在出錯之前的堆疊情況,那麼下面我們再來看看代碼問題到底出在什麼地方了。



/data/codes/c/test/backtraces $ gdb ./test

gdb> break *die+16

Breakpoint 1 at 0x80489f2: file main.c, line 6.

gdb&gt; list *die+16

0x80489f2 is in die (main.c:6).

1 #include "sigsegv.h"

2 #include <string.h>

3

4 int die() {

5 char *err = NULL;

6 strcpy(err, "gonner");

7 return 0;

8 }

9

10 int main() {

gdb>



現在看看定位錯誤將會多麼方便,上面的調試指令中list之前break不是必須的,只是讓你可以看到break其實就已經指出了哪一行代碼導致
Segmentation fault了。如果你要發佈你的程式你一般會為了減少體積不會附帶調試資訊的(也就是不加-ggdb
-g參數),不過沒關係,你一樣可以得到上面stack-trace資訊,然後你調試之前只要加上調試資訊即可。



 

2010年9月6日 星期一

SKYPE安裝

Introduction

Skype is proprietary software that allows you to make calls over the Internet using your computer. Skype uses decentralized peer-to-peer technologies, so your calls do not go through a central server, but through distributed servers and other users. It uses its own proprietary communication protocol to achieve this. In addition, all communications are encrypted from end to end so that others cannot listen in. The Skype software is free to use, but it is not free software; the source code is proprietary and not available for modification.

General information about Skype can be found here at, Wikipedia. The official Skype website is Skype.com

SkypeEthics gives information on why some users do not use Skype.

Open alternatives Softphones using open protocols include Ekiga and Twinkle.

You need a working sound input and output configuration in order to use Skype. Most modern computers have sound output out of the box, but you need a microphone (or a headset, while you are out shopping) for the input. In order to broadcast video, you'll need a webcam.

Links to detailed information about Skype issues on Ubuntu can be found in the Resources section below.

Installing Skype

Since Ubuntu 10.04 (Lucid Lynx), Skype is part of the Canonical partner repository. To install Skype add the Canonical Partner Repository and install Skype via the Software-Center or via the Terminal.

sudo apt-get update && sudo apt-get install skype

Installing Skype on older Ubuntu versions.

Skype is not available in any Ubuntu software repository, and therefore cannot be installed with Ubuntu's package management software such as Synaptic or apt-get without adding a repository containing Skype. There is the official Skype repository: Skype Forum

You can add the Apt source like this

echo "deb http://download.skype.com/linux/repos/debian/ stable non-free #Skype" | sudo tee -a /etc/apt/sources.list > /dev/null

Import the Apt key, even it is not used, but may be useful in future:

sudo apt-key adv --keyserver pgp.mit.edu --recv-keys 0xd66b746e

Install Skype:

sudo apt-get update && sudo apt-get install skype

Using a repository, you will automatically receive future updates to the software. Please be aware that the repository is not signed, so when you try to install Skype, you will get a warning.

If you don't want to do that, or can't (for example, if you're on amd64), perhaps the easiest way to install is from the Debian (.deb) package available directly from the Skype website. The downside of this is that you won't automatically get future updates, you will have to download the new versions as they become available.

Debian Package

  1. Download Debian package from Get Skype

  2. Save and then open the file. It will open with the proper installer by default.
  3. Click on the install button.

AMD64

For Ubuntu 8.10 (Intrepid Ibex)-Ubuntu 10.04 (Lucid Lynx)

  1. Download http://www.skype.com/download/skype/linux/choose/ (choose your architecture).

  2. Install it by double-clicking the deb file and clicking "Install Package"

    Note : version 2.1 beta will work natively using PulseAudio server

    Note 2: For Ubuntu 10.04 you will need the nspluginwrapper package which is available from the multiverse. You can enable the multiverse by going to System > Administration > Software sources and enabling the "multiverse" channel.

For Ubuntu 8.04 (Hardy Heron):

  1. Download Ubuntu 64 bit Skype package

  2. Install it by double-clicking the deb file and clicking "Install package"

For Ubuntu 6.06 (Dapper Drake):

  1. Download the Debian package (http://skype.com/download/skype/linux/)

  2. Install skype: sudo dpkg -i --force-all

  3. Determine missing 32bit libs: ldd /usr/bin/skype | grep not
  4. Download the libs (the i386 version of course, hint: the package is named libqt3-mt): http://packages.ubuntu.com/

  5. mkdir ~/.32bitLibs (or use /lib32 and change last step to this directory)
  6. extract the *.deb files (dpkg-deb --extract )

  7. copy the necessary library files from the extracted packages to ~/.32bitLibs
  8. create a wrapper script: export LD_LIBRARY_PATH="/home//.32bitLibs/";skype

Running Skype

To start Skype, choose Applications->Internet->Skype. It usually takes a minute or two for Skype to get started, and you may think that nothing is happening, so be patient.

When the Skype window finally opens, sign up (if necessary) and log in to your Skype account. Test your configuration by selecting the Echo / Sound Test Service contact (if not there already, add contact echo123) and clicking on the large green button at the bottom of the Skype window. If the connection is made and you hear a voice, your sound configuration is fine. If you cannot hear a voice, see the troubleshooting section below.

Troubleshooting Skype

If you need help with troubleshooting Skype please take a look at the following page. TroubleShooting Skype

2010年9月5日 星期日

嵌入式Samba的設定檔-開一個分享檔案到/tmp

#全區域設定
[global]
#設定工作群組
workgroup = MYGROUP
#設定主機名秩
server string = Samba Server
#限制許可主機(白名單)
; hosts allow = 192.168.1. 192.168.2. 127.
#印表機設定
; load printers = yes
; printcap name = /etc/printcap
; printcap name = lpstat
; printing = bsd

#如果你要一個guest的帳號,你必需要加入/etc/passwd中否則使用者就會使用nobody
; guest account = pcguest

# 設定log檔輸出
log file = /dev/zero

# Put a capping on the size of the log files (in Kb).
max log size = 50

# Security mode. Most people will want user level security. See
# security_level.txt for details.
security = share
# Use password server option only with security = server
; password server =

# You may wish to use password encryption. Please read
# ENCRYPTION.txt, Win95.txt and WinNT.txt in the Samba documentation.
# Do not enable this option unless you have read those documents
; encrypt passwords = yes

# Using the following line enables you to customise your configuration
# on a per machine basis. The %m gets replaced with the netbios name
# of the machine that is connecting
; include = /usr/local/samba/lib/smb.conf.%m

# Most people will find that this option gives better performance.
# See speed.txt and the manual pages for details
socket options = TCP_NODELAY

# Configure Samba to use multiple interfaces
# If you have multiple network interfaces then you must list them
# here. See the man page for details.
; interfaces = 192.168.68.76/24
; interfaces = 192.168.12.2/24 192.168.13.2/24

# Browser Control Options:
# set local master to no if you don't want Samba to become a master
# browser on your network. Otherwise the normal election rules apply
; local master = no

# OS Level determines the precedence of this server in master browser
# elections. The default value should be reasonable
; os level = 33

# Domain Master specifies Samba to be the Domain Master Browser. This
# allows Samba to collate browse lists between subnets. Don't use this
# if you already have a Windows NT domain controller doing this job
; domain master = yes

# Preferred Master causes Samba to force a local browser election on startup
# and gives it a slightly higher chance of winning the election
; preferred master = yes

# Use only if you have an NT server on your network that has been
# configured at install time to be a primary domain controller.
; domain controller =

# Enable this if you want Samba to be a domain logon server for
# Windows95 workstations.
; domain logons = yes

# if you enable domain logons then you may want a per-machine or
# per user logon script
# run a specific logon batch file per workstation (machine)
; logon script = %m.bat
# run a specific logon batch file per username
; logon script = %U.bat

# Where to store roving profiles (only for Win95 and WinNT)
# %L substitutes for this servers netbios name, %U is username
# You must uncomment the [Profiles] share below
; logon path = \\%L\Profiles\%U

# Windows Internet Name Serving Support Section:
# WINS Support - Tells the NMBD component of Samba to enable it's WINS Server
; wins support = yes

# WINS Server - Tells the NMBD components of Samba to be a WINS Client
# Note: Samba can be either a WINS Server, or a WINS Client, but NOT both
; wins server = w.x.y.z

# WINS Proxy - Tells Samba to answer name resolution queries on
# behalf of a non WINS capable client, for this to work there must be
# at least one WINS Server on the network. The default is NO.
; wins proxy = yes

# DNS Proxy - tells Samba whether or not to try to resolve NetBIOS names
# via DNS nslookups. The built-in default for versions 1.9.17 is yes,
# this has been changed in version 1.9.18 to no.
dns proxy = no

#分享定議
#[homes]
# comment = Home Directories
# browseable = yes
# writable = yes

# Un-comment the following and create the netlogon directory for Domain Logons
; [netlogon]
; comment = Network Logon Service
; path = /usr/local/samba/lib/netlogon
; guest ok = yes
; writable = no
; share modes = no


# Un-comment the following to provide a specific roving profile share
# the default is to use the user's home directory
;[Profiles]
; path = /usr/local/samba/profiles
; browseable = no
; guest ok = yes


# NOTE: If you have a BSD-style print system there is no need to
# specifically define each individual printer
;[printers]
; comment = All Printers
; path = /usr/spool/samba
; browseable = no
# Set public = yes to allow user 'guest account' to print
; guest ok = no
; writable = no
; printable = yes

# This one is useful for people to share files
;[tmp]
; comment = Temporary file space
; path = /tmp
; read only = no
; public = yes

# A publicly accessible directory, but read only, except for people in
# the "staff" group
;[public]
; comment = Public Stuff
; path = /home/samba
; public = yes
; writable = yes
; printable = no
; write list = @staff

# Other examples.
#
# A private printer, usable only by fred. Spool data will be placed in fred's
# home directory. Note that fred must have write access to the spool directory,
# wherever it is.
;[fredsprn]
; comment = Fred's Printer
; valid users = fred
; path = /homes/fred
; printer = freds_printer
; public = no
; writable = no
; printable = yes

# A private directory, usable only by fred. Note that fred requires write
# access to the directory.
;[fredsdir]
; comment = Fred's Service
; path = /usr/somewhere/private
; valid users = fred
; public = no
; writable = yes
; printable = no

# a service which has a different directory for each machine that connects
# this allows you to tailor configurations to incoming machines. You could
# also use the %U option to tailor it by user name.
# The %m gets replaced with the machine name that is connecting.
;[pchome]
; comment = PC Directories
; path = /usr/pc/%m
; public = no
; writable = yes

# A publicly accessible directory, read/write to all users. Note that all files
# created in the directory by users will be owned by the default user, so
# any user with access can delete any other user's files. Obviously this
# directory must be writable by the default user. Another user could of course
# be specified, in which case all files would be owned by that user instead.
[public]
# path = /mnt/hda
# path = /mnt/mtd/
path = /tmp
public = yes
# only guest = yes
writable = yes
# printable = no

# The following two entries demonstrate how to share a directory so that two
# users can place files there that will be owned by the specific users. In this
# setup, the directory should be writable by both users and should have the
# sticky bit set on it to prevent abuse. Obviously this could be extended to
# as many users as required.
;[myshare]
; comment = Mary's and Fred's stuff
; path = /usr/somewhere/shared
; valid users = mary fred
; public = no
; writable = yes
; printable = no
; create mask = 0765


2010年9月2日 星期四

在ubuntu下執行sh shell有錯誤時可以使用下面指令改

sh在ubuntu上執行常常會發生語法錯誤的問題,
修改的方法如下

sudo dpkg-reconfigure dash

記得選否就可以了!

2010年8月17日 星期二

使用GDB來Debug

  • 編譯gdb主程式

    在gdb的程式碼目錄下,依照下列步驟編譯。

    #tar jxf gdb-6.8.tar.bz2 #cd gdb-6.8 #export PATH=/usr/local/arm/3.4.1/bin:$PATH (將arm-linux-gcc的路徑加入PATH環境變數) (作自動配置,指定目標平台為arm-linux,執行檔加上"arm-linux-"前置號,安裝於目錄/usr/lcal/arm/3.4.1) #./configure --target=arm-linux --program-prefix=arm-linux-  --prefix=/usr/local/arm/3.4.1 #make #make install 

    這樣就建立了可以除錯ARM架構的gdb工具,並將 arm-linux-gdb 執行程式置於 /usr/local/arm/3.4.1/bin 路徑下。

  • 編譯gdbserver程式

    gdbserver主要是在ARM Linux平台上執行,用來與PC端的gdb程式溝通,在gdb的程式碼下的 "gdb/gdbserver"目錄,有gdbserver的程式碼,可依照下列步驟編譯出ARM平台的gdbserver程式

    #cd gdb/gdbserver #./configure --host=arm-linux #make #arm-linux-strip -s gdbserver (去掉除錯資訊,減少code size) 將gdbserver複製到ARM的檔案系統中,並加上 x 屬性 

    這樣就建立了可與gdb主程式溝通的gdbserver,請將gdbserver放到ARM Linux的檔案系統中。

    //用來Debug的方法

    在PC上進行程式編譯,使用arm-linux-gcc編譯成ARM執行檔

    #arm-linux-gcc -g -O0 -o hello.gdb hello.c  (hello.gdb 包含debug資訊,供gdb做除錯用) #cp hello.gdb hello #arm-linux-strip -s hello (去除debug資料,減少code size,將hello放到ARM Linux系統中執行) 

    編譯時記得要加上 -g-O0 參數(第一個是字母'O',第二個是數字'0'),-g : 加上debug 資料到執行檔,-O0表示不要作最佳化,這樣才能讓Debug時的程式執行順序與我們的程式碼一致。之後複製一份hello執行檔,並去除debug資料,減少code size這個hello執行檔放到Embedded Linux的檔案中,之後可以使用gdbserver帶起hello程式。而hello.gdb留在PC端,透過gdb載入程式與Debug資料作除錯用。

    在ARM平台上執行gdbserver,開啟網路port:3333,並帶起hello執行檔,等待gdb主程式連線。port號碼可自訂,選一個不衝突的就可以了。

    (At ARM Linux) # gdbserver  :3333 hello Process hello created; pid = 390 Listening on port 3333 

    現在就可以在PC上執行gdb主程式,並透過網路作除錯。本文介紹使用ddd工具作除錯介面

    (At PC Linux) # ddd --debbugger arm-linux-gdb hello.gdb  (指定ddd使用arm-linux-gdb除錯,並載入具有Debug 資料的hello.gdb檔) 

    執行時會遇到的問題。
    1.一直出現Program received signal SIG32, Real-time event 32.這樣的訊息。
    找不到arm-linux-insight。直接在gdb模式下面入:
    handle SIG32 pass noprint nostop

    还有一种解决方法
    编译时不带--static选项,会出现SIG32警告
    $ arm-linux-gcc -g threads.c -o threads-shared -lpthread
    编译时使用--static选项,则不会
    $ arm-linux-gcc -g threads.c -o threads-static -lpthread --static
    这种方法我没有试过


    出現warning: `/lib/ld-linux.so.2': Shared library architecture unknown is not compatible with target architecture arm.
    可以使用add-symbol-file /home/winging/DVR8181/arm-linux-2.6/target/rootfs-cpio/lib/ld-linux.so.2 


  • 2010年7月8日 星期四

    查字碼的方法

    用Microsoft Word 查!
    先選取該漢字, 然後按Alt+X,
    那字就會自動變成Unicode 碼!

    2010年7月2日 星期五

    DVR的系統設計入門

    監控用DVR的設計方向,
    第一個,資料的安全保存,在監控中如果找不到資料這是天大的災難
    ,人家買一台DVR就是用來預防有一天發生事情了拿來佐證或是提供線索找到答案,如果資料不見了,那要怎麼向使用者交代呢?

    第二個,影片的清析度與硬碟媒體中資料保留時間,如果錄到了但是看不清楚,那對提供的資訊就大打折扣了,如果何留的時間不夠長,可能想要來找的時候就資料被覆寫了,那也是非常可惜。但是錄影機清析與媒體可存時間也是大大有關系,當然後端攝影機與安裝也有很大的關系。在同樣的影像壓縮儲存技術上,影像愈是清析自然要使用到的儲存空間也就愈大,所謂一分結果要一分的付出。所以尋找與研發錄影愈是清析,使用空間愈少的方法,也是DVR設計上重要的一項工作。




    2010年6月8日 星期二

    totem安裝方法

    出自Ubuntu 正體中文 Wiki
    跳轉到: 導航, 搜尋
    Totem

    Totem 播放音樂的截圖
    開發者
    授權 GNU GPL v2
    使用平台 Linux
    最新版本 2.23.0
    APT 套件名稱 totem
    官方網站 Totem 專案網址

    簡介

    Totem Movie Player是一套在類Unix操作系統上運行的多媒體播放器,也是Ubuntu系統的預設影片播放器。Totem依照其內建播放引擎的不同可分為兩個版 本,Ubuntu內建的版本建基於GStreamer(套件名稱為totem-gstreamer),套件庫內則另有一建基於Xine的版本(套件名稱為 totem-gstreamer)。Totem在得到Mandrake Linux(現在稱Mandriva Linux) 設為其預設的多媒體播放器後大受歡迎。

    特色

    • 可用Gstreamer或Xine作為引擎
    • 與GNOME及Nautilus緊密結合
    • 可播放DVD,VCD與數位CD (經由FreeDB支援 CDDB )
    • 可調整亮度,對比度,色調及飽和度
    • 可以在Xinerama上實現全螢幕,支援雙頭輸出及視口
    • 可改變長寬比,重新將影片的大小依比例改變
    • 支援多語系及字幕,而且自動載入外掛字幕
    • 支援4.0, 4.1, 5.0, 5.1聲道,立體聲與AC3音頻輸出
    • 可調校音量
    • 提供音頻視覺化外掛程式
    • 可設定電視輸出,而且可選擇解析度
    • 支持LIRC (英語:Linux Infrared Remote Control)
    • 支持SHOUTcast, m3u, asx, SMIL與 RealAudio 播放清單
    • 提供可重播及擱置模式的播放清單,可由滑鼠改變播放次序及儲存特色。
    • 可擷取截圖
    • 用Gromit來支持Telestrator [1]
    • 以圖示預覽動畫
    • Mozilla 外掛程式
    • 支持東亞右至左語言

    安裝

    一開始安裝完 Ubuntu 已經內建有了 Totem,但是沒辦法觀看多數的影片檔,這是由於尚未安裝影片的 Codec 所致。

    Ubuntu 9.04 的 totem 2.26.1 已經可以自動尋找 codec 來播放大部分的影片 (mpg, rm, rmvb),不需要進行下列繁雜的步驟。

    您可以使用國人開發的 Lazybuntu 進行 Codec 以及其他影片播放器的安裝。

    如果您想要手動安裝,您也可以選擇安裝 Totem-xine,這是一個基於 Xine 的播放外掛

    • 安裝 Totem-xine,請在終端機中鍵入或複製貼上以下指令執行:
     sudo apt-get install totem-xine
    (註:安裝時可能會警告你將移除 totem-gstreamer 套件,這是避免衝突的正常現象,請放心移除)
    • 安裝給 Firefox 的外掛模組及其他 Plugins,請在終端機中鍵入或複製貼上以下指令執行:
    sudo apt-get install totem-mozilla libxine1-ffmpeg ffmpeg lame faad sox mjpegtools
    按 Enter 鍵,安裝過程中可能會顯示有些 Plugins 已經安裝過了,不過還是要安裝其他的 Plugins,請繼續安裝,完成後關閉終端機,請先登出 Ubuntu 再登入,開啟 Firefox 或 Totem 來試試看可不可以瀏覽影片。
    • 安裝DVD影片區碼套件:
    加入 Medibuntu 套件庫,請在終端機中鍵入或複製貼上以下指令執行:
    sudo apt-get install libdvdcss2
    安裝完後應該就能看 DVD 影片了

    正體中文字幕播放

    圖片:Totem-偏好設定.png

    1. 開啟Totem 影片播放器→編輯(E)→偏好設定(N)→一般
    2. 載入影片後自動讀取字幕檔案(L)→打勾
    3. 編碼(E)→正體中文→正體中文(BIG5)
    4. 按 關閉(C) 離開 偏好設定
    5. 開啟影片時 檢視(V)→字幕→自動

    Ubuntu 播放 Youtube 影片

    totem-youtubeh264_0.0.1-2.deb--下載者個套件安裝,他並不會影響你totem的運作喔!!

    載點二

    載點三

    原文來自於

    Ubuntu 播放 Mpeg 4 影片

    留意是安裝了 totem-gstreamer 或是 totem-xine, 可以打

    dpkg -l totem-*

    看到 totem-gstreamer 前有出現 ii 表示你安裝了 totem-gstreamer , 按理只要安裝好 GStreamer 的 plugin 就可以播放 影片。

    有關 codec 在以下幾個package:

    • gstreamer0.10-ffmpeg
    • gstreamer0.10-plugins-good
    • gstreamer0.10-plugins-bad
    • gstreamer0.10-plugins-bad-multiverse
    • gstreamer0.10-plugins-ugly
    • gstreamer0.10-plugins-ugly-multiverse

    在終端機中下指令安裝:

    sudo apt-get install gstreamer0.10-ffmpeg gstreamer0.10-plugins-good \
    gstreamer0.10-plugins-bad gstreamer0.10-plugins-bad-multiverse \
    gstreamer0.10-plugins-ugly gstreamer0.10-plugins-ugly-multiverse

    Ubuntu 播放 Real Video

    在 Ubuntu 8.10 (totem 2.24) 以前推薦安裝 totem-xine 搭配 codec 來播放。

    在 Ubuntu 9.04 (totem 2.26) 已經可以自動地尋找適當的 codec 來播放影片囉!

    播放任意一部 Real Video 將會出現自動尋找插件的對話方塊

    自動尋找插件

    按下尋找 (Search) 之後將會開始尋找適合的插件

    尋找插件中

    搜尋完畢之後會建議您安裝 gstreamer0.10-plugins-ugly

    找到 gstreamer0.10-plugins-ugly

    按下安裝 (Install) 之後將會要求您確認

    確認安裝插件

    按下確認 (Confirm) 之後將會詢問您的密碼以安裝插件

    詢問密碼

    輸入密碼之後將會開始下載插件

    開始下載插件

    下載完畢之後將會開始安裝插件

    開始安裝插件

    安裝成功之後會出現提示對話方塊

    安裝成功

    按下確定之後卻無法播放影片,繼續尋找其他插件

    尋找更多插件

    按下尋找 (Search) 之後會找到 gstreamer0.10-ffmepg 和 gstreamer0.10-plugins-bad

    更多的插件清單

    按下安裝 (Install) 之後會要求您確認

    確認安裝更多插件

    按下確認 (Confirm) 之後將會開始下載更多插件

    下載更多插件

    下載完畢之後將會開始安裝插件

    安裝更多插件

    安裝成功之後會出現提示對話方塊

    安裝成功

    點擊確定之後將會自動播放影片,現在您已經可以觀賞 Real 影片了!

    其他類似主題

    參考資料

    http://www.ubuntu-tw.org/modules/newbb/viewtopic.php?topic_id=42&forum=10

    2010年5月27日 星期四

    SQL Data Type 資料型別,

    轉http://blog.xuite.net/tolarku/blog/20968398

    SQL Data Type 資料型別, 不是什麼高深知識純粹做個紀錄罷了, 型別包含 整數 精確位數 浮點數 字串 unicode字串 Binary字串 日期時間 貨幣 Timestamp

    整數 ( ^ 符號代表次方 )

    資料型別 位元數 資料範圍
    tinyint 1 Byte 0 ~ 2^8 -1
    ( 0 ~ 255 )
    smallint 2 Bytes -2^15 ~ 2^15-1
    ( -32738 ~ 32767 )
    int 4 Bytes

    -2^31 ~ 2^31 -1
    ( -2147483648 ~ 2147483467)

    bigint 8 Bytes -2^63~2^63 -1
    (-9223372036854775808 ~ 9223372036854776807 )
    bit 1 Byte 0 , 1 , Null

    精確位數與浮點數

    資料型別 位元數 資料範圍
    numeric 視精確度而定 -10^38 +1 ~ 10^38 -1
    decimal 視精確度而定 -10^38 +1 ~ 10^38 -1
    float 8 Bytes -1.79E+308 ~ 1.79E+308
    15 位數
    real 4 Bytes
    -3.40E+38 ~ 3.40E+38
    7 位數

    字串 - Unicode 字串 - Binary 字串

    資料型別 位元數 資料範圍
    char(n) 1字元 1Byte 1 ~ 8000 字元
    varchar(n) 1字元 1Byte 1 ~ 8000 字元
    varchar(max) 變動長度 max=2GB 1 ~ 2^31 -1 字元
    text 變動長度 max=2GB 1 ~ 2^31 -1 字元
    nchar(n) 1字元 2Byte 1 ~ 4000 字元
    nvarchar(n) 1字元 2Byte 1 ~ 4000 字元
    nvarchar(max) 1字元 2Byte
    變動長度 max=2GB
    1 ~ 2^30 -1 字元
    ntext 1字元 2Byte
    變動長度 max=2GB
    1 ~ 2^30 -1 字元
    binary(n) 固定長度 8000 Bytes,不足自動補上 0x00
    1 ~ 8000 Bytes
    varbinary(n) 變動長度 1 ~ 8000 Bytes
    varbinary(max) 變動長度 max=2GB 1 ~ 2^31 -1 Bytes
    image 變動長度 max=2GB 1 ~ 2^31 -1 Bytes

    日期 - 時間 - 貨幣 - Timestamp

    資料型別 位元數 資料範圍
    datatime 8 Bytes 1753/1/1 ~ 9999/12/31
    ex: 2008-11-27 08:08:08.888
    smalldatatime 4 Bytes
    1900/1/1 ~ 2079/6/6
    ex: 2008-11-24 15:11
    money 8 Bytes -2^63 ~ 2^63 -1 小數4位
    ( -922337203685477.5808 ~ 922337203685477.5807)
    smallmoney 4 Bytes
    -2^31 ~ 2^31 -1 小數4位
    ( -214748.3648 ~ 214748.3647)
    timestamp 8 Bytes 8 Bytes 的 16 進位值
    uniqueidentifier 16 Bytes
    16 Bytes 的 16 進位值

    2010年5月25日 星期二

    [轉]如何以 Java 取得衛星定位資訊 ?


    http://ccckmit.wikidot.com/gps

    許多程式設計人員一聽到要寫衛星定位程式,就覺得那一定很難,如果又要以 Java 寫成,那可能就會打退堂鼓了,本文即是要對此問題,提出一個極簡單的做法,只要利用 javax.comm 這個函式庫,可以在 20 行之內就寫完衛星的位的接收器,這個程式就是Gps.java

    簡介

    衛星定位系統的運作原理,雖然極為複雜,然而要寫一個衛星定位接收程式,卻是極為簡單的,其原因是市面上所販售的衛星定位接收器,有一套固定的規格,早已把複雜的部分處理好了,我們只要利用 MS Windows 中的 COM port,就可以接收到衛星定位資訊了,而在 Java 語言中接收與寫入 COM port 的方法,就是利用 SUN 所提出來的 communication API (javax.comm),在本文中、我們將說明 javax.comm 函式庫的用法,並實做一個不到 20 行的衛星定位程式。

    ==衛星定位的資訊格式
    市面上所販售的衛星定位器,會將衛星定位資訊,編碼成一種稱為 NMEA 的格式,這種格式是一種簡單的純文字格式,以下是其中的一小段範例:

    $GPGSA,A,1,,,,,,,,,,,,,50.0,50.0,50.0*05 $GPGSV,3,1,12,26,89,000,36,29,73,000,00,28,38,000,00,18,35,000,00*79 $GPGSV,3,2,12,09,27,000,00,21,27,000,41,15,23,000,00,10,18,000,00*79 $GPGSV,3,3,12,08,15,000,00,22,07,000,,19,07,000,,03,-01,000,*51 $GPRMC,113347.950,V,0000.0000,N,00000.0000,E,0.00,,120305,,*00 $GPGGA,113348.950,0000.0000,N,00000.0000,E,0,00,50.0,0.0,M,0.0,M,0.0,0000*76 $GPGSA,A,1,,,,,,,,,,,,,50.0,50.0,50.0*05 $GPRMC,113348.950,V,0000.0000,N,00000.0000,E,0.00,,120305,,*0F $GPGGA,113349.950,0000.0000,N,00000.0000,E,0,00,50.0,0.0,M,0.0,M,0.0,0000*77 $GPGSA,A,1,,,,,,,,,,,,,50.0,50.0,50.0*05 $GPRMC,113349.950,V,0000.0000,N,00000.0000,E,0.00,,120305,,*0E 

    其中,最重要的資訊是座標資訊,紀錄在以 GPSGGA 開頭的欄位中,以下是其欄位的說明:

    標頭  ,收訊時間點,經度座標,北或南,緯度座標  ,東或西,品質,衛星數量,.... $GPGGA,113348.950,0000.0000,N    ,00000.0000,E     ,0   ,00      ,50.0,0.0,M,0.0,M,0.0,0000*76 

    其中,一般的程式通常只需要 "經度座標,北或南,緯度座標,東或西,品質,衛星數量" 等資訊就夠了,以下我們將說明一個衛星定位接收的 Java 程式寫法。

    用Java收衛星資訊

    由於程式實在太簡單,因此、我們將直接用程式的註解來說明即可。

    import java.io.*; import javax.comm.*;  public class Gps {   public static void main( String[] args) throws Exception {      receive(args[0]);    // 接收來自指定的 COM port 的衛星訊號。   }    // 以下是衛星接收的主要程式。   public static void receive(String port) throws Exception {     // 開啟 COM port (在 Java 中稱為 Serial Port)。     SerialPort serialPort = ( SerialPort ) CommPortIdentifier.getPortIdentifier( port ).open( "GPS", 60 );     // 設定接收參數,包含頻率為 4800bps, 8個資料位元後接著一個停止位元,沒有同位位元(parity bit)等。     serialPort.setSerialPortParams( 4800, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE );     // 將該 Serial Port 當成檔案一樣開啟,然後不斷讀取即可。     BufferedReader in = new BufferedReader( new InputStreamReader(serialPort.getInputStream()) );     while (true ) {       String msg = in.readLine();       System.out.println(msg);     }   } } 

    Gps.java 程式的安裝與執行方法

    欲執行 Gps.java,請將 Gps.zip 下載後解壓縮,其中有兩個特殊的檔案,必須先複製到指定位置中才能順利執行本程式,這是由於我們在程式中使用到了 javax.comm 這個不在標準 JDK 中的函式庫,因此、必須加裝這個函式庫所使用到的資源於系統中,其安裝方法稍嫌複雜,在 MS Windows 系統中的安裝步驟如下:

    * 將 win32com.dll 檔案複製到 {JDK}\bin 的目錄下。  * 將 javax.comm.properties 檔案複製到 {JDK}\lib 的目錄下。 

    接著,請切換到解壓縮後的目錄 {…}\Gps 中,打上下列指令以編譯該程式,並接著執行之。

    javac -classpath comm.jar;. Gps.java java -classpath comm.jar;. Gps COM4 

    只要你的衛星定位接收器在 COM4 的位置,就可以看到類似下列的資訊:

    $GPGSA,A,1,,,,,,,,,,,,,50.0,50.0,50.0*05 $GPGSV,3,1,12,26,89,000,36,29,73,000,00,28,38,000,00,18,35,000,00*79 $GPGSV,3,2,12,09,27,000,00,21,27,000,41,15,23,000,00,10,18,000,00*79 $GPGSV,3,3,12,08,15,000,00,22,07,000,,19,07,000,,03,-01,000,*51 $GPRMC,113347.950,V,0000.0000,N,00000.0000,E,0.00,,120305,,*00 $GPGGA,113348.950,0000.0000,N,00000.0000,E,0,00,50.0,0.0,M,0.0,M,0.0,0000*76 $GPGSA,A,1,,,,,,,,,,,,,50.0,50.0,50.0*05 $GPRMC,113348.950,V,0000.0000,N,00000.0000,E,0.00,,120305,,*0F $GPGGA,113349.950,0000.0000,N,00000.0000,E,0,00,50.0,0.0,M,0.0,M,0.0,0000*77 $GPGSA,A,1,,,,,,,,,,,,,50.0,50.0,50.0*05 $GPRMC,113349.950,V,0000.0000,N,00000.0000,E,0.00,,120305,,*0E 

    當然、若 COM port 不是 COM4,則程式會收不到任何訊息,此時、請確定你的 GPS 所在的 COM port,假如是 COM2 則請重新執行下列命令即可。

    java -classpath comm.jar;. Gps COM2 

    然而,要如何得知衛星定位接收器被安裝於哪一個 COM port 呢 ? 你只要選取 MS windows 中的裝置管理員,看一下 連接埠(COM 和 LPT) 的項目中,GPS 在哪一個 port 上即可曉得,以下作者的電腦接上 GPS 於 COM4 後的裝置管理員畫面。

    ComPort.jpg

    (註:裝置管理員的位置位於: 開始/控制台/系統/硬體/裝置管理員 中)

    結語

    以 Java 撰寫衛星定位程式,其實相當簡單,然而用途卻非常大,在行動裝置普及率愈來愈高的狀況下,衛星定位的相關應用可望蓬勃發展,本文期望藉由簡單而清楚的說明,讓大家能很容易的開發出相關的應用程式,並了解衛星定位的程式設計方式。

    參考文獻

    1. Java(tm) Communications API Win32 Installation Instructions
    2. NMEA format.
    3. GPS tutorial

    2010年5月20日 星期四

    裝個telnetd吧!

    mount -t devpts devpts /dev/pts
    telnetd

    2010年5月18日 星期二

    轉載Who Call Me?

    Who Call Me?

    徐千洋
    timhsu@info.sayya.org
    2004/03/30

     


    誰叫我? 有用過 gdb 對 core 檔作 bt (backtrace) 嗎? 所謂 backtrace 是用來回溯檢查函式呼叫的關係, 以便了解是由那一個函式呼叫
    出問題的函式. 尢其是在許多錯綜複雜的龐大程式碼中, backtrace 是相當有用的 debug 技巧. 而這個題目則是用來討論如何在程式執行中
    作 backtrace.

    在實作這個技術前有兩個關鍵點要先解決:
    1. 如何取得此 function 返回位址.
    2. 如何依據返回位址查知函式名稱.



    關於第一點, 必須先了解堆疊(Stack) 和函式呼叫的處理關係. 堆疊是一個後進先出(Last-In-First-Out)的資料結構. 當呼叫某個函式時, 相關的暫存器(Register) 就會被存入堆疊. 而當函式返回時便會從堆疊裡取回返回位址以便回到原來呼叫的下一個指令繼續執行. 至於暫存器(Register), 其中 EIP 是 Instruction Pointer, 用來指出 CPU 將要執行指令的位址. ESP 暫存器則是用來指向目前堆壘的位址.

    我們先寫個小程式來觀察可行性.

    ----------- test.c -----------
    void test()
    {

    }

    int main()
    {

    test();
    }
    ------------------------------

    [tim@localhost whocallme]$ gcc -o test test.c
    [tim@localhost whocallme]$ gdb ./test
    GNU gdb 5.3-25mdk (Mandrake Linux)
    Copyright 2002 Free Software Foundation, Inc.
    GDB is free software, covered by the GNU General Public License, and you are
    welcome to change it and/or distribute copies of it under certain
    conditions.
    Type "show copying" to see the conditions.
    There is absolutely no warranty for GDB. Type "show warranty" for details.
    This GDB was configured as "i586-mandrake-linux-gnu"...
    (gdb) b test
    Breakpoint 1 at 0x804832f
    (gdb) r
    Starting program: /home/tim/research/whocallme/test

    Breakpoint 1, 0x0804832f in test ()
    (gdb) info reg
    eax 0x0 0
    ecx 0x1 1
    edx 0x4014fe50 1075117648
    ebx 0x4014e9a0 1075112352
    esp 0xbffff698 0xbffff698
    ebp 0xbffff698 0xbffff698
    esi 0x40013880 1073821824
    edi 0xbffff6f4 -1073744140
    eip 0x804832f 0x804832f

    (gdb) disas test
    Dump of assembler code for function test:
    0x804832c : push %ebp
    0x804832d : mov %esp,%ebp
    0x804832f : pop %ebp
    0x8048330 : ret
    End of assembler dump.

    ebp 暫存器值是 0xbffff698, 也就是原來的堆疊位址. 我們知道在呼叫函式時(call) CPU 會將返回位址存入堆疊, 因此可以從 ebp 暫存器的位址裡面找到我們需要的返回位址:

    (gdb) p/x *0xbffff698
    $1 = 0xbffff6a8

    別忘了, 一進入此函式時 push $ebp 已被執行, 因此堆疊位址已被減 4, 所以要取得正確的值還得把 4 加回去才行:

    (gdb) p/x *(0xbffff698+4)
    $2 = 0x8048346

    這個值應該就是 test() 正確的返回位址, 來檢查看看:

    (gdb) disas main
    Dump of assembler code for function main:
    0x8048331
    : push %ebp
    0x8048332 : mov %esp,%ebp
    0x8048334 : sub $0x8,%esp
    0x8048337 : and $0xfffffff0,%esp
    0x804833a : mov $0x0,%eax
    0x804833f : sub %eax,%esp
    0x8048341 : call 0x804832c
    0x8048346 : leave
    0x8048347 : ret
    0x8048348 : nop
    0x8048349 : nop
    0x804834a : nop
    0x804834b : nop
    0x804834c : nop
    0x804834d : nop
    0x804834e : nop
    0x804834f : nop
    End of assembler dump.

    果然在 call 完後的下個指令是位於 0x8048346, 也就是 test() 返回位址.
    接下來我們就用 C 和一些 assembly 配合來實作.

    ------------- test-1.c ------------------
    void test()
    {
    unsigned long *stack;
    asm ("movl %%ebp, %0\n"
    : "=g"(stack));
    printf("ret address = 0x%x\n", *(stack+1));

    }

    int main()
    {

    test();
    }
    -----------------------------------------

    [tim@localhost whocallme]$ ./test-1
    ret address = 0x8048394
    [tim@localhost whocallme]$ gdb ./test-1
    (gdb) disas main
    Dump of assembler code for function main:
    0x804837f
    : push %ebp
    0x8048380 : mov %esp,%ebp
    0x8048382 : sub $0x8,%esp
    0x8048385 : and $0xfffffff0,%esp
    0x8048388 : mov $0x0,%eax
    0x804838d : sub %eax,%esp
    0x804838f : call 0x804835c
    0x8048394 : leave
    0x8048395 : ret
    0x8048396 : nop

    第一個關鍵點目前已解決, 再來要想想怎麼要能夠依記憶體位址查知所處的函式名稱呢?




    首先使用 objdump -t 來觀察執行檔的符號表:
    [tim@localhost whocallme]$ objdump -t ./test-1 | awk '{print $1" "$3" "$6}'|grep "F"
    080482c4 F call_gmon_start
    080482f0 F __do_global_dtors_aux
    08048330 F frame_dummy
    080484ac O __FRAME_END__
    08048450 F __do_global_ctors_aux
    080483f0 F __libc_csu_fini
    08048250 F _init
    0804835c F test
    080482a0 F _start
    080483a0 F __libc_csu_init
    0804837f F main
    08048474 F _fini
    08049598 O _GLOBAL_OFFSET_TABLE_

    既然 objdump -t 可以印出程式的函式名稱和記憶體位址, 那麼我們就試試利用 objdump 一樣的技巧吧.
    objdump 是利用 BFD Library(The Binary File Descriptor Library)來實作的, 底下的 bfd.c 也利用 BFD Library 來讀取符號表.

    --------------- bfd.c --------------------

    #include
    #include

    int main(int argc, char **argv[])
    {
    bfd *abfd;
    long storage_needed;
    asymbol **symbol_table;
    long number_of_symbols;
    long i;
    char **matching;
    struct sec *section;
    char *symbol_name;
    long symbol_offset;
    long section_vma;
    long symbol_address;

    if (argc < 2)
    return 0;
    printf("Open %s\n", argv[1]);
    bfd_init();
    abfd = bfd_openr(argv[1],NULL);
    if (abfd == (bfd *)0)
    {
    bfd_perror("bfd_openr");
    return -1;
    }
    if (!bfd_check_format_matches(abfd, bfd_object, &matching))
    {
    return -1;
    }
    if (!(bfd_get_file_flags (abfd) & HAS_SYMS))
    {
    printf("ERROR flag!\n");
    return -1;
    }
    /* 取得符號表大小 */
    storage_needed = bfd_get_symtab_upper_bound(abfd);
    if (storage_needed < 0)
    return -1;
    symbol_table = (asymbol **) xmalloc(storage_needed);
    /* 將符號表讀進所配置的記憶體裡(symbol_table), 並傳回符號表個數 */
    number_of_symbols = bfd_canonicalize_symtab(abfd, symbol_table);
    if (number_of_symbols < 0)
    return -1;
    for(i = 0; i < number_of_symbols; i++)
    {
    /* 檢查此符號是否為函式 */
    if (symbol_table[i]->flags & (BSF_FUNCTION|BSF_GLOBAL))
    {
    /* 反查此函式所處的區段(section) 及區段位址(section_vma)*/
    section = symbol_table[i]->section;
    section_vma = section->vma;
    /* 取得此函式的名稱(symbol_name), 偏移位址(symbol_offset) */
    symbol_name = symbol_table[i]->name;
    symbol_offset = symbol_table[i]->value;
    /* 將此函式的偏移位址加上區段位址則為此函式在執行時的記憶體位址(symbol_address */
    symbol_address = section_vma + symbol_offset;
    /* 檢查此函式是否處在程式本文區段 */
    if (section->flags & SEC_CODE)

    printf("<%s> 0x%x 0x%x 0x%x\n",
    symbol_name,
    section_vma,
    symbol_offset,
    symbol_address);

    }
    }
    bfd_close(abfd);
    }

    -----------------------------------------
    執行結果:
    [tim@localhost whocallme]$ ./bfd ./test-1
    Open ./test-1
    0x80482a0 0x24 0x80482c4
    <__do_global_dtors_aux> 0x80482a0 0x50 0x80482f0
    0x80482a0 0x90 0x8048330
    <__do_global_ctors_aux> 0x80482a0 0x1b0 0x8048450
    <__libc_csu_fini> 0x80482a0 0x150 0x80483f0
    <_init> 0x8048250 0x0 0x8048250
    0x80482a0 0xbc 0x804835c
    <_start> 0x80482a0 0x0 0x80482a0
    <__libc_csu_init> 0x80482a0 0x100 0x80483a0
    0x80482a0 0xdf 0x804837f
    <_fini> 0x8048474 0x0 0x8048474

    現在, 我們可以依照函式名稱及記憶體位址作對照表, 即可方便查詢. 不過這其中還有個小問題, 那就是我們雖然知道各函式的起始位址, 但是並不知道函式的結束位址, 也不知道各函式的大小. 要解決這個小問題就必須在作對照表時先作排序, 將位址越高的函式排在越後面,
    把下一個函式的起始位址當作結束位址.

    --------------- bfd_dumpfun.c --------------------
    /* bfd_dumpfun.c (GPL)
    * gcc -o bfd_dumpfun bfd_dumpfun.c -lbfd
    *
    * Usage: ./bfd_dumpfun [binary]
    * Note: Dump functions infomation of ELF-binary with BFD Library.
    *
    * by TimHsu(timhsu@info.sayya.org) 2004/03/31
    *
    */

    #include
    #include

    typedef struct function_table FUN_TABLE;

    /* 宣告一個包含函式名稱和位址的結構 */
    struct function_table
    {
    char name[80];
    unsigned long addr;
    };

    static FUN_TABLE *fun_table;
    static int table_count = 0; /* 函式個數 */

    static int compare_function(const void *a, const void *b)
    {
    FUN_TABLE *aa = (FUN_TABLE *) a;
    FUN_TABLE *bb = (FUN_TABLE *) b;
    if (aa->addr > bb->addr)
    return 1;
    else if (aa->addr <>addr)
    return -1;
    else
    return 0;
    }

    /* 增加一個函式資料至對照表 */
    static void add_function_table(char *name, unsigned long address)
    {

    strncpy(fun_table[table_count].name, name, 80);
    fun_table[table_count].addr = address;
    table_count++;
    }

    static void dump_function_table(void)
    {
    int i;
    for(i = 0; i < table_count; i++)
    {
    printf("%-30s 0x%x\n", fun_table[i].name,
    fun_table[i].addr);

    }
    }

    int main(int argc, char **argv[])
    {
    bfd *abfd;
    asection *text;
    long storage_needed;
    asymbol **symbol_table;
    long number_of_symbols;
    long i;
    char **matching;
    struct sec *section;
    char *symbol_name;
    long symbol_offset;
    long section_vma;
    long symbol_address;

    if (argc < 2)
    return 0;
    printf("Open %s\n", argv[1]);
    bfd_init();
    abfd = bfd_openr(argv[1],NULL);
    if (abfd == (bfd *)0)
    {
    bfd_perror("bfd_openr");
    return -1;
    }

    if (!bfd_check_format_matches(abfd, bfd_object, &matching))
    {
    return -1;
    }
    if (!(bfd_get_file_flags (abfd) & HAS_SYMS))
    {
    printf("ERROR flag!\n");
    return -1;
    }
    storage_needed = bfd_get_symtab_upper_bound(abfd);

    if (storage_needed < 0)
    return -1;
    symbol_table = (asymbol **) xmalloc(storage_needed);
    number_of_symbols = bfd_canonicalize_symtab(abfd, symbol_table);
    if (number_of_symbols < 0)
    return -1;
    fun_table = (FUN_TABLE **)malloc(sizeof(FUN_TABLE)*number_of_symbols);
    bzero(fun_table, sizeof(FUN_TABLE)*number_of_symbols);

    for(i = 0; i < number_of_symbols; i++)
    {
    if (symbol_table[i]->flags & (BSF_FUNCTION|BSF_GLOBAL))
    {
    section = symbol_table[i]->section;
    section_vma = section->vma;

    symbol_name = symbol_table[i]->name;
    symbol_offset = symbol_table[i]->value;
    symbol_address = section_vma + symbol_offset;
    if (section->flags & SEC_CODE)
    {
    add_function_table(symbol_name,
    }
    }
    }
    bfd_close(abfd);
    /* 將函式對照表作排序 */
    qsort(fun_table, table_count, sizeof(FUN_TABLE), compare_function);
    dump_function_table();
    }
    -----------------------------------------
    執行結果:
    [tim@localhost whocallme]$ ./bfd_dumpfun ./test-1
    Open ./test-1
    _init 0x8048250
    _start 0x80482a0
    call_gmon_start 0x80482c4
    __do_global_dtors_aux 0x80482f0
    frame_dummy 0x8048330
    test 0x804835c
    main 0x804837f
    __libc_csu_init 0x80483a0
    __libc_csu_fini 0x80483f0
    __do_global_ctors_aux 0x8048450
    _fini 0x8048474


    現在, 我們已經把技術的關鍵點都處理好了, 為了讓它能夠實用化, 最好是作成函式庫, 在有需要時能夠隨時呼叫.

    ------------- whocallme.h ------------------------
    #include

    #define FUNCTION_NAME_MAXLEN 80

    #define who_call_me() \
    do { \
    unsigned long *stack; \
    asm ("movl %%ebp, %0\n" \
    : "=g"(stack)); \
    fprintf(stderr, ": function <%s> call me <%s>!\n", \
    find_function_by_addr(*(stack+1)), who_am_i()); \
    } while(0)


    extern int init_function_table(char *);
    ----------------------------------------------------
    --------------- whocallme.c ------------------------
    /* whocallme.c (GPL)
    *
    * A runtime backtrace of function.
    * http://info.sayya.org/~timhsu/research/whocallme
    *
    *
    * by Timhsu(timhsu@sayya.org) 2004/03/31
    *
    */

    #include
    #include
    #include "whocallme.h"

    typedef struct function_table FUN_TABLE;
    /* 宣告一個包含函式名稱和位址的結構 */
    struct function_table
    {
    char name[FUNCTION_NAME_MAXLEN];
    unsigned long addr;
    };
    static int compare_function(const void *a, const void *b)
    {
    FUN_TABLE *aa = (FUN_TABLE *) a;
    FUN_TABLE *bb = (FUN_TABLE *) b;
    if (aa->addr > bb->addr)
    return 1;
    else if (aa->addr <>addr)
    return -1;
    else
    return 0;
    }
    /* 增加一個函式資料至對照表 */
    static void add_function_table(char *name, unsigned long address)
    {

    strncpy(fun_table[table_count].name, name, FUNCTION_NAME_MAXLEN);
    fun_table[table_count].addr = address;
    table_count++;
    }
    /* 顯示函式對照表的全部資料 */
    static void dump_function_table(void)
    {
    int i;
    for(i = 0; i < table_count; i++)
    {
    fprintf(stderr, "%-30s 0x%x\n",
    fun_table[i].name,
    fun_table[i].addr);

    }
    }
    /* 取得目前正在執行的函式名稱 */
    char * who_am_i(void)
    {
    unsigned long *stack; \
    asm ("movl %%ebp, %0\n" \
    : "=g"(stack));
    return find_function_by_addr(*(stack+1));
    }
    /* 依照位址取得函式名稱 */
    char *find_function_by_addr(unsigned long addr)
    {
    int i;
    for(i = 0; i < table_count; i++)
    {
    if (addr > fun_table[i].addr)
    {
    if (addr < fun_table[i+1].addr)
    return fun_table[i].name;
    }
    }

    }
    /* 初始化函式對照表 */
    int init_function_table(char *file)
    {
    bfd *abfd;
    long storage_needed;
    asymbol **symbol_table;
    long number_of_symbols;
    long i;
    char **matching;
    struct sec *section;
    char *symbol_name;
    long symbol_offset;
    long section_vma;
    long symbol_address;

    bfd_init();
    abfd = bfd_openr(file,NULL);
    if (abfd == (bfd *)0)
    {
    bfd_perror("bfd_openr");
    return -1;
    }
    if (!bfd_check_format_matches(abfd, bfd_object, &matching))
    {
    return -1;
    }
    if (!(bfd_get_file_flags (abfd) & HAS_SYMS))
    {
    printf("ERROR flag!\n");
    return -1;
    }
    /* 取得符號表大小 */
    storage_needed = bfd_get_symtab_upper_bound(abfd);
    if (storage_needed < 0)
    return -1;
    symbol_table = (asymbol **) xmalloc(storage_needed);
    /* 將符號表讀進所配置的記憶體裡(symbol_table), 並傳回符號表個數 */
    number_of_symbols = bfd_canonicalize_symtab(abfd, symbol_table);
    if (number_of_symbols < 0)
    return -1;
    /* 配置空間給函式對照表 */
    fun_table = (FUN_TABLE **)malloc(sizeof(FUN_TABLE)*number_of_symbols);
    bzero(fun_table, sizeof(FUN_TABLE)*number_of_symbols);

    for(i = 0; i < number_of_symbols; i++)
    {
    /* 檢查此符號是否為函式 */
    if (symbol_table[i]->flags & (BSF_FUNCTION|BSF_GLOBAL))
    {
    /* 反查此函式所處的區段(section) 及區段位址(section_vma)*/
    section = symbol_table[i]->section;
    section_vma = section->vma;
    /* 取得此函式的名稱(symbol_name), 偏移位址(symbol_offset) */

    symbol_name = symbol_table[i]->name;
    symbol_offset = symbol_table[i]->value;
    /* 將此函式的偏移位址加上區段位址則為此函式在執行時的記>憶體位址(symbol_address */
    symbol_address = section_vma + symbol_offset;
    /* 檢查此函式是否處在程式本文區段 */
    if (section->flags & SEC_CODE)
    {
    /* 將此函式名稱和位址加入至對照表 */
    add_function_table(symbol_name,
    symbol_address);
    }
    }
    }
    free(symbol_table);
    bfd_close(abfd);
    /* 將函式對照表作排序 */
    qsort(fun_table, table_count, sizeof(FUN_TABLE), compare_function);
    }

    ----------------------------------------------
    [tim@localhost whocallme]$ gcc -c whocallme.c
    [tim@localhost whocallme]$ ar -q libwhocallme.a whocallme.o

    來寫個小小的測試程式試試看:

    ---------------- test-2.c --------------------------

    #include "whocallme.h"

    void test()
    {
    who_call_me();
    }
    void test_a()
    {
    test_b();
    test_c();
    }
    void test_b()
    {
    test();
    }
    void test_c()
    {
    who_call_me();
    }
    int main(int argc, char *argv[])
    {
    init_function_table(argv[0]);
    test();
    test_a();
    test_b();
    test_c();
    }
    ----------------------------------------------
    執行結果:
    [tim@localhost whocallme]$ gcc -o test-2 test-2.c -lbfd -L. -lwhocallme
    [tim@localhost whocallme]$ ./test-2
    : function
    call me !
    : function call me !
    : function call me !
    : function call me !
    : function
    call me !