亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

用C#開發.NET CF 藍牙通信模塊

2019-11-18 19:22:56
字體:
來源:轉載
供稿:網友
  在Windows Mobile軟件開發中.Net正扮演著日益重要的角色,我們已經可以看到很多用.Net CF開發的軟件,這些軟件涉及到了日常應用的方方面面。在智能設備的軟件開發中,無線互聯是一個相當重要的一塊,我們可以看到,紅外幾乎是所有智能設備的標配,而藍牙也日益在越來越多的智能設備上出現,有了硬件,顯然要有相應的軟件相關的應用。

  我們也知道,用.NET CF開發紅外通信應用時相當輕松的,因為.NET CF中有一個命名空間System.Net.IrDA就是用于紅外通信的通信模塊。但是,.NET CF中還沒有關于藍牙通信的模塊,所以目前來講做這方面的開發還有一定的困難。下面,就談談如何用C#開發.NET CF藍牙通信模塊。

  一. 基本要點

  首先明確一點,因為涉及到驅動硬件的問題,所以僅靠了解C#開發的相關知識顯然是無法完成開發的,我們必須對C++開發有所了解。但是為了簡單起見,我們不希望用C++寫半行代碼,所有的編碼工作全部使用C#,也就是說,使用的開發環境只需要使用Visual Studio.net,不需要用其他的編輯器。

  作為開發這類驅動硬件的程序的知識準備,您需要了解C++的基本知識,知道頭文件是怎么一回事,知道托管代碼如何與非托管代碼交互。因為本文的核心是說明如何開發.net CF藍牙通信模塊,所以前述這些準備知識并不作講述。

  二. 關于藍牙

  做藍牙通信模塊開發,自然先要知道藍牙通信是怎么一回事。在我看來,藍牙通信應該和紅外通信模塊類似,當然我是從開發者的角度來講,抽象化以后應該就是這樣,當然藍牙和紅外通信也有很多不一樣的地方,這在面向對象設計里面怎么講,我想一定有很多人理解的比我透徹。好了,這就是我們的基本思路了。我曾經在網上查過關于藍牙開發的文章,很多人在.net CF開發中把藍牙通信當作一個串行通信來處理,這也是不錯的,但是我不是很喜歡,因為這樣做的話,并不是針對藍牙來開發的,換言之,在使用過程中,需要先手動開啟藍牙,配對,連接,建立串行通道,然后開啟應用程序使用,你還要在應用程序中設置串行端口,對最終用戶來講,這是非常麻煩的。我覺得,這樣的解決方案冠上藍牙通信的名頭簡直就是……不多說了,書歸正傳。

  在紅外通信中,我們知道,設備的DeviceID是一個Byte數組,那么藍牙設備的DeviceID什么樣子呢?我想這個大家都很清楚,是一串以“:”分隔的16進制數字。

  紅外通信中,一般而言紅外并沒有開啟、關閉之類的狀態,但是藍牙有開啟、關閉、可發現三種狀態。

  紅外沒有安全設置,而藍牙有安全設置,所以我們需要對藍牙設備進行配對,而紅外通信這部需要。

  我們查看.net的Socket地址族里有IrDA,但是沒有藍牙相關的地址族,這是我們需要解決的問題。

  三. 獲取設備ID

  1.獲取本地設備的ID

  我們查看Window CE 4.2的SDK文檔,得知獲取本地設備ID的函數是BthReadLocalAddr,在btdrt.dll中。SDK文檔中的英文原文是這樣的:“This function retrieves the Bluetooth address of the current device.”好了,知道了這個就好說了:

  首先封裝本地托管函數:

[DllImport("Btdrt.dll", SetLastError=true)]

public static extern int BthReadLocalAddr(byte[] pba);

  這個函數得到的本地DeviceID也是一組byte數組,為了向人們顯示出來,我們要把它變為String:

string text1 = "";

text1 = text1 + pba[5].ToString("X2") + ":";

text1 = text1 + pba [4].ToString("X2") + ":";

text1 = text1 + pba [3].ToString("X2") + ":";

text1 = text1 + pba [2].ToString("X2") + ":";

text1 = text1 + pba [1].ToString("X2") + ":";

return (text1 + pba [0].ToString("X2"));

  2.獲取遠程設備的ID

  其實談到獲取遠程設備的ID就涉及到如何去發現遠程設備了,所以這里就一并把發現設備的方法也說明了吧。 發現設備需要用到三個Winsock API,分別是WSALookupServiceBegin、WSALookupServiceNext和WSALookupServiceEnd,這三個API到底起什么作用可以去查看Windows CE 4.2的SDK,這里就不詳細解釋了,只談一下幾個需要注意的地方。

  WSALookupServiceBegin的函數原形是這樣的:

INT WSALookupServiceBegin(

LPWSAQUERYSET lpqsRestrictions,

DWord dwControlFlags,

LPHANDLE lphLookup

);

  我們用托管代碼進行包裝:

[DllImport("ws2.dll", EntryPoint="WSALookupServiceBegin", SetLastError=true)]

public static extern int CeLookupServiceBegin(byte[] pQuerySet, LookupFlags dwFlags, ref int lphLookup);

  可以看到,本來lpqsRestrictions是一個struct,經過包裝后在托管代碼中成為了byte[],我們計算好該struct大概要占用多少個byte,struct中每一個成員在byte數組中的位置是怎樣的,裝配出來就好了。

  由于是針對藍牙作的開發,所以我們要查看一下這些參數應該是哪些值。Windows CE 4.2的SDK中說,藍牙開發時,struct LPWSAQUERYSET中的如下成員應當為這些值:

The dwSize member must be sizeof(WSAQUERYSET).

The lpBlob member (itself a pointer to a BLOB structure) is optional, but if used, the device inquire parameters valid for LUP_FLUSHCACHE are the following:

The cbSize member of the BLOB structure must be sizeof(BTH_QUERY_DEVICE).

The pBlobData member is a pointer to a BTH_QUERY_DEVICE structure, for which the LAP member is the Bluetooth inquiry access code, and the length member is the length of the inquiry, in seconds.

The dwNameSpace member must be NS_BTH.

All other WSAQUERYSET members are ignored.

  具體什么意思各位可以自己去理解,我想比我翻譯出來要好些,畢竟我英語很差的。根據以上要求,我們這樣裝配pQuerySet:

byte[] buffer1 = new byte[0x400];

BitConverter.GetBytes(60).CopyTo(buffer1, 0);

GCHandle handle1 = GCHandle.Alloc(blob1.ToByteArray(), GCHandleType.Pinned);

IntPtr ptr1 = handle1.AddrOfPinnedObject();

BitConverter.GetBytes((int) (ptr1.ToInt32() + 4)).CopyTo(buffer1, 0x38);

  另外的兩個API也照類似方法調用即可。

  在調用了WSALookupServiceNext之后,bytes數組pQuerySet中便包含了遠程設備的地址信息,下面我們需要把它找出來。通過閱讀SDK中WSAQUERYSET結構的說明和計算每個成員的位置之后,我們寫出如下代碼:

int num5 = BitConverter.ToInt32(buffer1, 0x30);

int num6 = Marshal.ReadInt32((IntPtr) num5, 8);

int num7 = Marshal.ReadInt32((IntPtr) num5, 12);

SocketAddress address1 = new SocketAddress(AddressFamily.Unspecified, num7);


  因為.net框架的地址族里面沒有藍牙,所以我們這里用的是AddressFamily.Unspecified。

  然后的工作就是從中獲取遠程設備的ID了:

  前面我們已經計算出,這個Address里面的前六個字節是byte數組形式的設備ID,第七到第二十二個字節是藍牙的Service Guid,在后面四個字節是端口號,所以我們只需要分別提取出來即可。

  四. 監聽服務

  監聽服務調用的是非托管API WSASetService,其原型是

INT WSASetService(

LPWSAQUERYSET lpqsRegInfo,

WSAESETSERVICEOP essOperation,

DWORD dwControlFlags

);

  可以看到關鍵也是第一個參數,lpqsRegInfo,這也是一個struct,我們的包裝方法與前面的發現設備采用的方法類似,做藍牙通信時要注意其成員要如下設置:

lpqsRegInfodwSizesizeof(WSAQUERYSET)
 lpszServiceInstanceNameNot supported on Windows CE. Set to 0.
 lpServiceClassIdNot supported on Windows CE. Set to 0.
 dwNameSpaceNS_BTH.
 dwNumberOfCsAddrsNot supported on Windows CE. Set to 0.
 ipcsaBufferNot supported on Windows CE. Set to 0.
 lpBlobPoints to a BTHNS_SETBLOB structure, containing information about the service to be added.
 *
All other WSAQUERYSET fields are ignored.

  五. 連接

  我們知道,IrDA中連接遠程服務是使用方法System.Net.Sockets.IrDAClient類中的Connect方法。而這個方法又是調用的Socket類中的Connect方法。而Socket類是一個比較抽象的類,它并不綁定某個具體的地址族、SocketType和PRotocolType,所以在實例化的時候,需要指定這三個參數。我們也知道,在IrDA中,這三個參數分別是AddressFamily.Irda, SocketType.Stream,和ProtocolType.IP,那么在藍牙中這三個參數分別是什么呢?我們好像找不到。

  且慢,真是這樣嗎?

  我們知道在.net中,這三個參數都是枚舉值,而枚舉在默認情況下,你可以認為就是int值的替代表現。

  我們該如何知道這三個參數到底是什么呢?

  還是先看Socket類的Connect方法。

  我們查查有關資料,可以知道這個方法實際上是調用的一個非托管函數:

[DllImport("mscoree", EntryPoint="@339")]

public static extern int connect(int s, byte[] name, int namelen);

  也就是非托管的Socket API。

  我們看Windows CE 4.2的SDK,可以看到,在使用藍牙進行連接的時候,需要使用WinSock擴展。我們還可以看到,在使用藍牙進行連接的時候,三個參數分別應當是AF_BTH、SOCK_STREAM和BTHPROTO_RFCOMM,至于這三個參數分別代表什么,我們就要查看相關的頭文件了。

  我們找到ws2bth.h頭文件,可以看到AF_BTH代表十進制數32,而BTHPROTO_RFCOMM代表十六進制數0x0003,恰好和ProtocolType.Ggp代表的數值是一致的。所以,我們在實例化Socket時是這么寫的:

new Socket((AddressFamily) 0x20, SocketType.Stream, ProtocolType.Ggp);

  Socket實例化出來了,其他的當然就都好說了,這里不再贅述。

  六. 藍牙的安全設置

  藍牙比紅外多了安全方面的設置,所以就需要多一些代碼來處理這些。具體也就不多說了,其實也就是一些非托管代碼的包裝調用,這些API在Btdrt.dll中:

  獲取配對碼請求:

[DllImport("Btdrt.dll", SetLastError=true)]

public static extern int BthGetPINRequest(byte[] pba);

  設置配對碼:

[DllImport("btdrt.dll", SetLastError=true)]

public static extern int BthSetPIN(byte[] pba, int cPinLength, byte[] ppin);

  比較麻煩點的是配對,總共有三步操作:

  首先是創建ACL連接:

[DllImport("Btdrt.dll", SetLastError=true)]

public static extern int BthCreateACLConnection(byte[] pbt, ref ushort phandle);

  然后是配對碼驗證:

[DllImport("Btdrt.dll", SetLastError=true)]

public static extern int BthAuthenticate(byte[] pbt);

  然后一定要關閉連接:

[DllImport("Btdrt.dll", SetLastError=true)]

public static extern int BthCloseConnection(ushort handle);

  七. 設置藍牙無線電狀態

  我們知道,藍牙無線電有打開、關閉、可發現三種狀態,那么我們如何實現編程控制呢?

  我想這個一定大家都知道了,因為網上有很多關于這個的文章:

  先寫一個枚舉:

public enum RadioMode
{
 Connectable = 1,
 Discoverable = 2,
 PowerOff = 0
}

  然后寫一個函數調用非托管代碼即可:

[DllImport("BthUtil.dll", SetLastError=true)]

public static extern int BthSetMode(RadioMode dwMode);

  獲取無線電狀態的話就用下面的函數:

[DllImport("BthUtil.dll", SetLastError=true)]

public static extern int BthGetMode(ref RadioMode dwMode);

  八. 已知的問題

  可能是因為藍牙控制軟件還沒有實現標準化或者還是其他的問題,我們發現根據Windows CE 4.2 SDK 使用Winsock 擴展做的藍牙開發有一個問題,而且不論是本文中所述的托管代碼還是其他的非托管代碼,只要是用的這種思路用Winsock 2做的開發都會存在這樣一個問題,那就是不是在所有的Windows Mobile設備上都能正常運行。經過我的測試,我發現在很多使用另行開發的藍牙控制軟件的設備上,如聯想ET560、華碩MyPAL A730上都無法運行,而在沒有另行開發藍牙控制軟件的設備上是可以正常運行的,我不知道這是什么原因,初步推測可能是廠商另行開發的藍牙控制軟件屏蔽了微軟的API的緣故,到底是不是這樣,還得請高人指點。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
在线观看不卡av| 欧美日韩中文字幕综合视频| 伊人久久久久久久久久久久久| 一区二区中文字幕| 久久中国妇女中文字幕| 亚洲性视频网址| 98精品国产高清在线xxxx天堂| 欧美电影《睫毛膏》| 国产经典一区二区| 久久九九热免费视频| 91免费国产视频| 国产欧美在线观看| 国产精品第一区| 美女啪啪无遮挡免费久久网站| 日韩亚洲精品视频| 亚洲欧美另类国产| 欧美xxxx18性欧美| 欧美另类极品videosbest最新版本| 日韩国产在线看| 国产日韩在线精品av| 久久亚洲精品国产亚洲老地址| 欧美日韩国产第一页| 欧美国产激情18| 成人免费看片视频| 日韩美女视频在线观看| 国外成人在线直播| 日韩三级成人av网| 久久久女人电视剧免费播放下载| 日韩欧美高清视频| 成人免费网站在线观看| 成人免费午夜电影| 亚洲白虎美女被爆操| 日韩欧美在线视频观看| 永久免费毛片在线播放不卡| 国产精品三级久久久久久电影| 国产精品丝袜一区二区三区| 精品国产区一区二区三区在线观看| 在线不卡国产精品| 亚洲一区二区三区在线视频| 亚洲综合成人婷婷小说| 成人写真福利网| 国产一区视频在线| 亚洲全黄一级网站| 亚洲欧美日韩精品| 亚洲精品98久久久久久中文字幕| 中文字幕日韩在线观看| 国产精品自拍网| 97婷婷涩涩精品一区| 久久精品夜夜夜夜夜久久| 色久欧美在线视频观看| 68精品久久久久久欧美| 亚洲一区二区免费| 欧美又大又硬又粗bbbbb| 欧美福利视频网站| 日韩中文字幕在线看| 日韩欧美中文字幕在线观看| 亚洲图片在线综合| 青青在线视频一区二区三区| 亚洲精品欧美日韩专区| 两个人的视频www国产精品| 欧美性xxxxxxxxx| 日本亚洲欧洲色α| 亚洲人在线视频| 国产精品成av人在线视午夜片| 欧美视频免费在线观看| 久久影视电视剧免费网站清宫辞电视| 日本电影亚洲天堂| 992tv成人免费视频| 色噜噜国产精品视频一区二区| 欧美精品久久久久久久| 精品亚洲国产成av人片传媒| 日韩小视频在线| 久久久久久午夜| 亚洲国产美女精品久久久久∴| 色哟哟入口国产精品| 成人在线免费观看视视频| 久久久精品影院| 久久免费国产精品1| 狠狠躁天天躁日日躁欧美| 亚洲天堂一区二区三区| 欧洲永久精品大片ww免费漫画| 日韩美女福利视频| 91精品国产自产在线观看永久| 91麻豆桃色免费看| 久久久久五月天| 国产一区二区三区久久精品| 欧美午夜丰满在线18影院| 亚洲午夜女主播在线直播| 亚洲2020天天堂在线观看| 成人字幕网zmw| 中文字幕亚洲天堂| 国外成人在线直播| 欧美中文在线字幕| 亚洲欧美中文字幕在线一区| 亚洲精品欧美极品| 亚洲人成啪啪网站| 超在线视频97| 97久久国产精品| 亚洲美女中文字幕| www欧美日韩| 日韩高清电影免费观看完整版| 国产成人亚洲综合| 不卡中文字幕av| 日韩欧美中文字幕在线观看| 欧美日韩国产精品一区| 精品一区精品二区| 黑人极品videos精品欧美裸| 成人免费看片视频| 精品国产区一区二区三区在线观看| 狠狠躁天天躁日日躁欧美| 亚洲男子天堂网| 欧美一级大胆视频| 国产精品www色诱视频| 91免费人成网站在线观看18| 国产精品高清免费在线观看| 黄色成人在线免费| 日产日韩在线亚洲欧美| 亚洲天堂成人在线| 欧美日韩国产综合视频在线观看中文| 日韩激情视频在线| 久久影院中文字幕| 最近免费中文字幕视频2019| 精品久久久久久| 亚洲天堂一区二区三区| 992tv在线成人免费观看| 亚洲va久久久噜噜噜| 国产精品第8页| 国产精品18久久久久久首页狼| 亚洲美女又黄又爽在线观看| 成人亚洲激情网| 久久九九全国免费精品观看| 中文字幕精品一区久久久久| 91在线中文字幕| 精品精品国产国产自在线| 亚洲理论电影网| 久久99久久亚洲国产| 黑人与娇小精品av专区| 在线日韩日本国产亚洲| www日韩中文字幕在线看| 91av在线播放视频| 亚洲欧美日韩一区在线| 亚洲综合大片69999| 91香蕉嫩草影院入口| 成人淫片在线看| 91久久精品日日躁夜夜躁国产| 亚洲欧美国产va在线影院| 亚洲综合在线小说| 亚洲天天在线日亚洲洲精| www.亚洲男人天堂| 国产91精品久久久久久| 欧美在线激情视频| 久久色精品视频| 久久久噜噜噜久久| 久久免费视频在线| 国产精品黄视频| 亚洲аv电影天堂网| 福利视频导航一区| 亚洲午夜未删减在线观看| 亚洲一品av免费观看| 精品亚洲一区二区三区四区五区| 欧美人与物videos| 久久噜噜噜精品国产亚洲综合| xx视频.9999.com| 热99在线视频|