Bài giảng Lập trình hồng ngoại Blutoo OBEX

OBEX LÀ GÌ?  
OBEX (OBject EXchange) là giao thức trao đổi dữ liệu giữa các thiết bị dùng cổng hồng  
ngoại được hiệp hội IrDA (Infrared Data Association) đưa ra lần đầu tiên năm 1997. Ban  
đầu, giao thức này chỉ giới hạn cho các thiết bị sử dụng môi trường ánh sáng hồng ngoại,  
nhưng rất nhanh sau đó nó được tổ chức Bluetooth SIG (Bluetooth Special Interest  
Group) đưa vào hầu hết các thiết bị Bluetooth của mình.  
1. Vị trí OBEX trong mô hình OSI  
Cũng giống như các giao thức khác, giao thức OBEX được xây dựng trên nền mô hình  
OSI (Open Systems Interconnection) bao gồm hai thành phần chính:  
• OBEX session protocol (giao thức phiên OBEX): mô tả cấu trúc gói tin trong phiên  
làm việc giữa hai thiết bị.  
• OBEX application framework: tập các dịch vụ OBEX cung cấp cho các ứng dụng đầu  
cuối như truyền file, in ảnh...  
Ù
Tầng ứng dụng  
OBEX Application  
ication  
OBEX Framework  
OBEX Session  
Tầng phiên  
Tầng trình diễn  
Tầng giao vận  
Tầng mạng  
Tiny TP RFCOMM  
IrLMP  
IrLAP  
L2CAP  
Link  
Manager  
Tầng liên kết dữ liệu  
IrPHY Baseband  
IrDA Bluetooth  
Tầng vật lý  
OSI  
Hình 1: Giao thức OBEX trong mô hình OSI  
2. Cấu trúc gói tin trong giao thức phiên OBEX  
Giao thức OBEX được sử dụng chủ yếu trong các ứng dụng kiểu "đẩy" (Push) hoặc "kéo"  
(Pull), cho phép máy khách (client) "đẩy" dữ liệu lên máy chủ (server) hoặc "kéo" dữ liệu  
từ server xuống. Để thực hiện điều này, các gói tin trao đổi giữa client và server phải tuân  
thủ chặt chẽ cấu trúc đề ra. Dưới đây là một vài cấu trúc được sử dụng trong quá trình  
truyền file giữa client và server (chi tiết có thể tham khảo tài liệu IrOBEX1.3 trên website  
http://www.hitekgroup.net).  
2.1 Gói tin yêu cầu  
Mọi gói tin yêu cầu đều có cấu trúc như sau:  
Byte 0  
opcode  
Byte 1, 2  
Byte 3 đến n  
packet length  
Headers  
Opcode: Mã lệnh ứng với từng yêu cầu (Bảng 1). Bit cao nhất gọi là Final bit.  
Packet length: Độ dài của gói tin  
Header: Thông tin đầu có cấu trúc như sau:  
Byte 0  
Byte 1, 2  
Byte 3 đến n  
header  
identifier  
length (tuỳ  
chọn)  
value  
Bảng 1: Mã lệnh yêu cầu  
Mã lệnh  
Kiểu  
Mô tả  
Thiết lập phiên  
giao dịch  
0x80  
CONNECT  
Ngừng phiên giao  
dịch  
Gửi dữ liệu lên  
server  
0x81  
DISCONNECT  
PUT  
0x02  
(0x82)  
0x03  
(0x83)  
Lấy dữ liệu từ  
server  
GET  
Hủy bỏ phiên  
giao dịch  
0xFF  
ABORT  
Bảng 2: Thông tin đầu  
Định  
Tên  
Mô tả  
danh  
0x01  
0xC3  
0x48  
0x49  
NAME  
Tên file (mã Unicode)  
Kích thước file theo  
byte  
LENGTH  
BODY  
Đoạn dữ liệu của file  
END OF  
BODY  
Đoạn dữ liệu cuối  
cùng của file  
2.2 Gói tin trả lời  
Giống như gói tin yêu cầu, gói tin trả lời có cấu trúc như sau:  
Byte 0  
Byte 1, 2  
Byte 3 to n  
response  
opcode  
response  
length  
response data  
Một số mã trả lời (response opcode) thường gặp:  
Bảng 3: Mã trả lời  
Mã trả lời  
Mô tả  
0x10 (0x90)  
Tiếp tục yêu cầu hoặc trả lời  
Xác nhận kết thúc yêu cầu  
hoặc trả lời  
0x20 (0xA0)  
0x40 (0xC0)  
0x41 (0xC1)  
Lỗi yêu cầu  
Lỗi do không có quyền  
0x43 (0xC3)  
0x44 (0xC4)  
Phiên giao dịch bị huỷ bỏ  
Không tìm thấy file  
3. Cùng giải quyết  
Quá trình trao đổi file giữa client và server được chia làm 3 giai đoạn:  
• Thiết lập phiên: CONNECT  
• Nhận/gửi file: GET/PUT  
• Ngừng phiên: DISCONNECT  
3.1 Thiết lập phiên (CONNECT)  
Gói tin CONNECT có cấu trúc như sau:  
Byte Byte 1,  
Byte  
4
Byte 7  
to n  
Byte 3  
Byte 5, 6  
0 0  
2
maximum  
OBEX  
packet  
OBEX  
version  
number  
packet  
length  
optional  
headers  
0x80  
flags  
length  
OBEX version number: Phiên bản giao thức OBEX gồm major number lưu tại 4 bit cao,  
minor number lưu tại 4 bit thấp. Phiên bản hiện tại là 1.0, do đó giá trị này là 0x10.  
Flags: Giá trị này luôn là 0x00 trong phiên bản hiện tại.  
Maximum OBEX packet length: Giá trị lớn nhất của gói tin trong giao thức OBEX mà  
thiết bị có thể nhận hoặc gửi. Giá trị này ở client và server có thể khác nhau. Do đó khi  
thiết lập phiên, client cần gửi giá trị này lên server để kiểm tra xem kích thước gói tin lớn  
nhất mà server có thể nhận hoặc gửi là bao nhiêu?  
Optional headers: Thông tin đầu được tùy chọn ứng với mục đích của mỗi phiên giao  
dịch. Trong ví dụ dưới đây, giá trị này có thể bỏ qua.  
Yêu cầu từ  
client  
Mã yêu cầu  
byte  
Ý nghĩa  
CONNECT  
0x80  
0x000  
7
Độ dài gói tin = 7 bytes  
Phiên bản OBEX 1.0  
0x10  
0x00  
Flags đối với phiên bản  
hiện tại  
0x200 Kích thước lớn nhất của  
0
gói tin là 8K  
Trả lời từ server  
Mã trả  
0xA0  
lời  
SUCCESS  
0x0007 Độ dài gói tin = 7 bytes  
0x10  
0x00  
Phiên bản OBEX 1.0  
Flags đối với phiên bản hiện  
tại  
Kích thước lớn nhất của gói  
0x0200 tin mà server có thể nhận  
hoặc gửi là 512 bytes  
3.2 Gửi file (PUT)  
Không giống như gói tin CONNECT, gói tin PUT có thêm một số thông tin đầu sau:  
NAME: Thông tin về tên file  
LENGTH: Thông tin về kích thước file  
BODY: Đoạn dữ liệu file  
END OF BODY: Đoạn dữ liệu cuối cùng của file  
Dưới đây là ví dụ gửi 1 file hello.gif có kích thước 721 bytes từ client (PC) lên server  
(ĐTDĐ). Do kích thước của file lớn hơn kích thước gói tin lớn nhất mà server có thể  
nhận (với Sony Ericsson T610 là 512 bytes) nên client sẽ chia file thành hai gói tin để  
gửi. Gói tin 1 có mã yêu cầu PUT là 0x02 (không thiết lập Final bit). Gói tin 2 có mã yêu  
cầu PUT là 0x82 (thiết lập Final bit).  
Yêu cầu từ  
client  
byte  
Ý nghĩa  
PUT, Final bit không  
thiết lập để chỉ cho  
server biết client còn gửi  
yêu cầu tiếp theo  
Độ dài gói tin = 482  
bytes  
Mã yêu cầu  
0x02  
0x01E2  
0x01  
Định danh thông tin đầu  
NAME (tên file)  
Độ dài của thông tin đầu  
NAME = 20+3 = 23  
bytes  
Tên file (unicode) có ký  
tự kết thúc NULL (20  
bytes)  
Định danh thông tin đầu  
LENGTH (kích thước  
file)  
0x0017  
hello.gif  
0xC3  
0x000002D  
1
Kích thước file = 721  
bytes  
Định danh thông tin đầu  
BODY (dữ liệu file)  
Độ dài của thông tin đầu  
BODY = 448+3 = 451  
bytes  
0x48  
0x01C3  
0x...  
Đoạn dữ liệu file có kích  
thước 448 bytes  
Trả lời từ server  
CONTINUE, tiếp tục  
nhận yêu cầu từ client  
Mã trả lời  
0x90  
0x0003  
độ dài gói tin = 3 bytes  
Yêu cầu từ client  
PUT, Final bit được thiết  
lập để chỉ cho server biết  
đây là gói tin cuối cùng  
Độ dài gói tin = 279  
bytes  
Mã yêu cầu 0x82  
0x0117  
0x49  
Định danh thông tin đầu  
END OF BODY  
Độ dài của thông tin đầu  
END OF BODY = 276  
bytes  
Đoạn dữ liệu file có kích  
thước 721-448 = 273  
bytes  
0x0114  
0x...  
Trả lời từ server  
Mã trả lời 0xA0  
0x0003  
SUCCESS  
độ dài gói tin = 3 bytes  
3.3 Nhận file (GET)  
Khác với gói tin PUT, gói tin GET chỉ có thông tin đầu NAME. Ví dụ sau sẽ mô tả quá  
trình nhận file hello.gif có kích thước 721 bytes từ server. Trước tiên client (PC) sẽ gửi  
yêu cầu GET đến server (ĐTDĐ) với thông tin đầu NAME là tên file. Do kích thước của  
file yêu cầu lớn hơn 512 bytes (với Sony Ericsson T610) nên gói tin trả lời đầu tiên có mã  
trả lời là 0x90 (CONTINUE) cùng với một phần dữ liệu của file. Khi nhận được mã trả  
lời là CONTINUE, client biết rằng đây chưa phải là đoạn dữ liệu cuối cùng của file nên  
tiếp tục gửi yêu cầu (không cần thông tin đầu NAME) cho đến khi nhận được mã trả lời  
là 0xA0 (SUCCESS).  
Yêu cầu từ  
client  
byte  
Ý nghĩa  
GET, Final bit được thiết  
lập  
0x83  
0x001A Độ dài gói tin = 26 bytes  
Định danh thông tin đầu  
NAME (tên file)  
0x01  
Mã yêu cầu  
Độ dài của thông tin đầu  
NAME = 20+3 = 23 bytes  
0x0017  
hello.gi Tên file (unicode) có ký tự  
f
kết thúc NULL (20 bytes)  
Trả lời từ server  
CONTINUE, còn dữ liệu  
trên server  
0x90  
0x01C6 Độ dài gói tin = 454 bytes  
Định danh thông tin đầu  
0x48  
BODY (dữ liệu file)  
Mã trả lời  
Độ dài của thông tin đầu  
0x01C3 BODY = 448+3 = 451  
bytes  
Đoạn dữ liệu file có kích  
thước 448 bytes  
0x...  
Yêu cầu từ client  
PUT, tiếp tục yêu cầu nhận  
file  
0x83  
Mã yêu cầu  
0x0003 Độ dài gói tin = 3 bytes  
Trả lời từ server  
SUCCESS, đoạn dữ liệu  
cuối cùng  
Mã trả lời  
0xA0  
0x0117 Độ dài gói tin = 279 bytes  
Định danh thông tin đầu  
END OF BODY  
0x49  
0x0114 Độ dài của thông tin đầu  
END OF BODY = 276  
bytes  
Đoạn dữ liệu file có kích  
thước 273 bytes  
0x...  
3.4 Ngừng phiên (DISCONNECT)  
Để kết thúc phiên giao dịch, client cần gửi gói tin DISCONNECT tới server.  
Yêu cầu từ  
client  
byte  
Ý nghĩa  
Mã yêu cầu  
0x81  
DISCONNECT  
0x0003  
Độ dài gói tin = 3 bytes  
Trả lời từ server  
Mã trả lời  
0xA0  
0x0003  
SUCCESS  
Độ dài gói tin = 3 bytes  
OBEX trong điện thoại di động  
Ngày nay, ĐTDĐ không chỉ là phương tiện liên lạc đơn thuần mà còn là một thiết bị giải  
trí với nhiều chức năng như nghe nhạc, chụp ảnh, chơi game. Điều này đồng nghĩa với  
việc người dùng luôn có nhu cầu cập nhật những bản nhạc hay, những trò chơi yêu thích  
hoặc lưu lại những khoảnh khắc đáng nhớ trên chiếc điện thoại của mình. Dưới đây tôi  
xin giới thiệu hai kiểu kết nối phổ biến nhất trên hầu hết các ĐTDĐ đời mới hiện nay là  
cổng hồng ngoại và Bluetooth; đồng thời hướng dẫn cách lập trình trao đổi dữ liệu giữa  
PC và ĐTDĐ sử dụng giao thức OBEX qua hai loại kết nối này.  
1. Kết nối qua hồng ngoại bằng C#  
Giao thức IrDA được hiệp hội IrDA giới thiệu lần đầu  
tiên năm 1994 với mục đích tăng cường khả năng kết nối  
không dây giữa các thiết bị qua ánh sáng hồng ngoại. Với  
phạm vi hoạt động lên tới 1 m, góc mở từ 15 đến 30 độ,  
tốc độ có thể đạt 4Mbps, cổng hồng ngoại nhanh chóng  
được đưa vào trong hầu hết các thiết bị không dây như  
ĐTDĐ, PDA...  
Trước đây, việc lập trình với cổng hồng ngoại là một rào  
cản đối với những ai chưa quen với giao diện lập trình API (Application Programming  
Interface) của Windows, còn ngày nay, với phiên bản .NET 2.0, Microsoft đã đưa vào bộ  
Framework này lớp thư viện IrDA, cho phép người lập trình viết mã dễ dàng và nhanh  
chóng hơn. Giống như giao thức TCP/IP, client có thể thiết lập kết nối IrDA tới server  
bằng việc chỉ ra địa chỉ của server (tương tự như địa chỉ IP) và tên dịch vụ trên server  
(tương tự như TCP Port).  
Mỗi chiếc ĐTDĐ đều được gắn một địa chỉ duy nhất tương ứng với cổng hồng ngoại trên  
đó. Đoạn mã sau cho phép xác định địa chỉ này:  
using System.Net.Sockets;  
void Form1_Load(object sender, EventArgs e)  
{
/* Khởi tạo client */  
IrDAClient irClient = new IrDAClient();  
/* Tìm kiếm tối đa 2 thiết bị */  
IrDADeviceInfo[] irDevices = irClient.DiscoverDevices(2);  
/* In thông báo khi không tìm thấy thiết bị nào */  
if (irDevices.Length == 0) {  
Console.WriteLine("Không tìm thấy thiết bị hồng ngoại");  
}
else {  
/* In tên và địa chỉ của từng thiết bị tìm thấy */  
for (int i = 0; i < irDevices.Length; i++) {  
Console.WriteLine("Device Name:{0}",irDevices[i].DeviceName);  
Console.WriteLine("Device ID:{0}",irDevices[i].DeviceID);  
}
}
}
Các dịch vụ IrDA được xây dựng sẵn (built-in) trong ĐTDĐ có thể khác nhau mỗi nhà  
sản xuất. Tuy nhiên, nhìn chung hầu hết các ĐTDĐ hiện nay đều cung cấp hai dịch vụ  
chính là: IrDA:IrCOMM và IrDA:OBEX. Trong phạm vi bài viết này tôi chỉ đề cập đến  
dịch vụ IrDA:OBEX, dịch vụ cho phép PC và ĐTDĐ trao đổi dữ liệu qua giao thức  
OBEX. Việc kết nối tới dịch vụ này được thực hiện thông qua đoạn mã dưới đây:  
using System.Net;  
using System.Net.Sockets;  
void Form1_Load(object sender, EventArgs e)  
{
...  
/* Thiết lập EndPoint */  
IrDAEndPoint irEndPoint = new IrDAEndPoint(irDevices[0].DeviceID,  
"IrDA:OBEX");  
/* Khởi tạo socket */  
Socket irSocket = new Socket(AddressFamily.Irda, SocketType.Stream,  
ProtocolType.Unspecified);  
/* Kết nối tới ĐTDĐ qua dịch vụ OBEX*/  
irSocket.Connect(irEndPoint);  
}
Như vậy, từ giờ chúng ta có thể trao đổi dữ liệu giữa PC và ĐTDĐ qua irSocket bằng  
việc push/pull những gói tin OBEX thích hợp như đã đề cập ở phần trên.  
2. Kết nối qua Bluetooth bằng VC++  
Năm 1994, hãng cung cấp thiết bị viễn thông hàng đầu thế giới Ericsson đã nghiên cứu  
thành công công nghệ không dây cho phép ĐTDĐ có thể kết nối với các phụ kiện như tai  
nghe, microphone qua sóng radio. Sau đó 4 năm, tổ chức Bluetooth SIG được thành lập  
(bao gồm Ericsson, Intel, IBM, Nokia và Toshiba) đã chính thức đưa ra đặc tả kỹ thuật  
phiên bản 1.0A cho công nghệ Bluetooth vào năm 1999. Bluetooth hay còn có cái tên  
IEEE 802.15.1 hoạt động ở tần số 2,4 GHz, phạm vi phủ sóng lên tới 100 m (Class 1), tốc  
độ có thể đạt 3Mpbs đối với phiên bản 2.0+EDR (Enhanced Data Rate).  
Kể từ phiên bản Windows XP SP1, Microsoft đã đưa vào hệ điều hành của mình mô hình  
lập trình Microsoft Bluetooth Stack cho phép kết nối với thiết bị Bluetooth thông qua  
Bluetooth socket. Một vấn đề nảy sinh là không phải tất cả các chipset Bluetooth đều hỗ  
trợ Microsoft Bluetooth Stack, mà phần lớn phải có driver đi kèm cũng như bộ SDK  
(Software Development Kit) riêng để phát triển. Chúng ta có thể tìm thấy chipset  
Bluetooth hỗ trợ Microsoft Bluetooth Stack trên các máy tính xách tay SONY VAIO,  
trong khi dòng IBM lại hỗ trợ Widcomm Bluetooth Stack (bộ SDK có giá tới 1400 USD).  
Để lập trình với Bluetooth socket chúng ta phải cài bộ SDK for Windows XP SP2  
m). Bộ SDK này sẽ cung cấp một số file header cũng như các thư viện cần thiết trong quá  
trình lập trình. Do phiên bản .NET 2.0 chưa hỗ trợ Bluetooth nên việc viết mã phải hoàn  
toàn thực hiện trên nền thư viện API có sẵn của Windows.  
Cách tiếp cận thiết bị Bluetooth hoàn toàn giống như thiết bị hồng ngoại, chỉ có điều,  
thay vì sử dụng hàm có sẵn của .NET, bạn phải tự thân vận động. Dưới đây là đoạn mã  
viết bằng VC++ 2005 cho phép tìm kiếm thiết bị Bluetooth, đồng thời in ra tên và địa chỉ  
của mỗi thiết bị tìm thấy:  
#include <winsock2.h>  
#include <Ws2bth.h>  
#include <BluetoothAPIs.h>  
#pragma comment(lib, "ws2_32.lib")  
#pragma comment(lib, "irprops.lib")  
/* compile with: /clr */  
using namespace System;  
void main()  
{
WORD wVersionRequested = 0x202;  
WSADATA m_data;  
/* Khởi tạo Windows Socket */  
if (WSAStartup(wVersionRequested, &m_data) == 0) {  
/* Thiết lập thông số tìm kiếm */  
WSAQUERYSET querySet;  
memset(&querySet, 0, sizeof(querySet));  
querySet.dwSize = sizeof(querySet);  
/* Xác lập phạm vi tìm kiếm là các thiết bị Bluetooth */  
querySet.dwNameSpace = NS_BTH;  
HANDLE hLookup;  
/* Thiết lập các thông tin trả về */  
DWORD flags = LUP_RETURN_NAME | LUP_CONTAINERS | LUP_RETURN_ADDR |  
LUP_FLUSHCACHE | LUP_RETURN_BLOB;  
/* Tìm kiếm tối đa 10 thiết bị */  
int maxDevices = 10;  
/* Bắt đầu quá trình tìm kiếm */  
int result = WSALookupServiceBegin(&querySet, flags, &hLookup);  
while (count < maxDevices && result == 0) {  
BYTE buffer[1000];  
DWORD bufferLength =  
sizeof(buffer);  
WSAQUERYSET *pResults=  
(WSAQUERYSET*)&buffer;  
result=WSALookupServiceNext(hLook  
up, flags, &bufferLength,  
pResults);  
Hình 2: Lựa chọn kết nối Bluetooth  
/* In tên và địa chỉ của từng  
thiết bị tìm thấy */  
if (result == 0) {  
CSADDR_INFO *pCSAddr = (CSADDR_INFO*)pResults->lpcsaBuffer;  
SOCKADDR_BTH *bts=(SOCKADDR_BTH*)pCSAddr->RemoteAddr.lpSockaddr;  
Console::WriteLine(pResults->lpszServiceInstanceName);  
Console::WriteLine("Device ID:{0}", bts->btAddr);  
count++;  
}
}
/* Kết thúc quá trình tìm kiếm */  
result = WSALookupServiceEnd(hLookup);  
WSACleanup();  
}
}
Trên ĐTDĐ hiện nay, các dịch vụ Bluetooth ngày càng phong phú đáp ứng đầy đủ nhu  
cầu kết nối không dây của người dùng như: truyền file, in ảnh, tai nghe... Những dịch vụ  
này đều có một định danh duy nhất (UUID) và được định nghĩa sẵn trong file header  
bthdef.h. Trong đó dịch vụ OBEX Object Push có vai trò tương tự như dịch vụ  
IrDA:OBEX của thiết bị hồng ngoại. Dưới đây là đoạn mã cho phép kết nối tới dịch vụ  
này:  
#include <bthdef.h>  
void main()  
{
...  
/* Khởi tạo Windows Socket */  
if (WSAStartup(wVersionRequested, &m_data) == 0) {  
/* Khởi tạo Bluetooth socket */  
SOCKET s = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);  
SOCKADDR_BTH sin;  
sin.addressFamily = AF_BTH;  
/* Địa chỉ thiết bị đã tìm thấy ở trên */  
sin.btAddr = bts->btAddr;  
/* định danh dịch vụ OBEX Object Push */  
sin.serviceClassId = OBEXObjectPushServiceClass_UUID;  
sin.port = 0;  
/* Kết nối tới dịch vụ OBEX Object Push */  
int result = connect(s, (SOCKADDR*) &sin, sizeof(sin));  
WSACleanup();  
}
}
Như vậy bằng việc sử dụng các hàm send() và recv() cùng với giao thức OBEX, chúng ta  
có thể dễ dàng gửi và nhận file giữa PC và ĐTDĐ.  
Hình 3: Các file trong thư mục điện thoại  
LỜI KẾT  
Trên đây, tôi vừa giới thiệu với các bạn hai cách kết nối không dây phổ biến nhất hiện  
nay phục vụ nhu cầu trao đổi dữ liệu giữa PC và ĐTDĐ. Để thuận tiện cho việc phát triển  
ứng dụng trên nền .NET, tôi đã viết lớp thư viện Bluetooth cho phép dễ dàng kết nối tới  
thiết bị Bluetooth tương tự như lớp thư viện IrDA của Microsoft (có thể tải về tại website  
www.hitekgroup.net). Chương trình demo do được viết riêng cho ĐTDĐ Sony Ericsson  
T610 nên có thể làm việc không hiệu quả trên các dòng máy khác. Hy vọng qua bài viết  
này, các bạn có thể tự xây dựng cho mình một ứng dụng quản lý file phù hợp với chiếc  
điện thoại của mình.  
Tài liệu và chương trình demo có thể tải tại website www.hitekgroup.net hoặc  
pdf 14 trang baolam 24080 Free
Bạn đang xem tài liệu "Bài giảng Lập trình hồng ngoại Blutoo OBEX", để tải tài liệu gốc về máy hãy click vào nút Download ở trên

File đính kèm:

  • pdfbai_giang_lap_trinh_hong_ngoai_blutoo_obex.pdf