链接蓝牙设备小程序源码(微信小程序蓝牙接口协议)
本文目录一览:
C# 控制蓝牙设备?
C#开发控制蓝牙设备的方法如下链接蓝牙设备小程序源码:
制作一个PDA的程序链接蓝牙设备小程序源码,其中一个功能是:实现监测蓝牙设备,有就连上它的功能。我找到一个这方面的文章,但是不会用他说的,求高手解答。下面是文章内容:由于太长 我删除一些闲话
在红外通信中,我们知道,设备的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,我们的包装方法与前面的发现设备采用的方法类似,做蓝牙通信时要注意其成员要如下设置:
lpqsRegInfo
dwSize
sizeof(WSAQUERYSET)
lpszServiceInstanceName
Not supported on Windows CE. Set to 0.
lpServiceClassId
Not supported on Windows CE. Set to 0.
dwNameSpace
NS_BTH.
dwNumberOfCsAddrs
Not supported on Windows CE. Set to 0.
IpcsaBuffer
Not supported on Windows CE. Set to 0.
lpBlob
Points 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);
多个蓝牙设备的情况下,小程序怎么去连接指定的某个蓝牙设备
根据具体链接蓝牙设备小程序源码的型号号码进行配对
android_studio手机蓝牙串口通信源代码
初涉android的蓝牙操作,按照固定MAC地址连接获取Device时,程序始终是异常终止,查了好多天代码都没查出原因。今天改了一下API版本,突然就成功连接了。总结之后发现果然是个坑爹之极的错误。
为了这种错误拼命查原因浪费大把时间是非常不值得的,但是问题不解决更是揪心。可惜我百度了那么多,都没有给出确切原因。今天特此mark,希望后来者遇到这个问题的时候能轻松解决。
下面是我的连接过程,中间崩溃原因及解决办法。
1:用AT指令获得蓝牙串口的MAC地址,地址是简写的,按照常理猜测可得标准格式。
2:开一个String adress= "************" //MAC地址, String MY_UUID= "************"//UUID根据通信而定,网上都有。
3:取得本地Adapter用getDefaultAdapter(); 远程的则用getRemoteDevice(adress); 之后便可用UUID开socket进行通信。
如果中途各种在getRemoteDevice处崩溃,大家可以查看一下当前的API版本,如果是2.1或以下版本的话,便能确定是API版本问题,只要换成2.2或者以上就都可以正常运行了~ 这么坑爹的错误的确很为难初学者。 唉·········· 为这种小trick浪费很多时间真是难过。
(另外有个重要地方,别忘了给manifest里面加以下两个蓝牙操作权限哦~)
uses-permission android:name="android.permission.BLUETOOTH"/uses-permission
uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/uses-permission
下面附上Android蓝牙操作中用固定MAC地址传输信息的模板,通用搜索模式日后再补删模板:
private BluetoothAdapter mBluetoothAdapter = null;
private BluetoothSocket btSocket = null;
private OutputStream outStream = null;
private InputStream inStream = null;
private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); //这条是蓝牙串口通用的UUID,不要更改
private static String address = "00:12:02:22:06:61"; // ==要连接的蓝牙设备MAC地址
/*获得通信线路过程*/
/*1:获取本地BlueToothAdapter*/
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if(mBluetoothAdapter == null)
{
Toast.makeText(this, "Bluetooth is not available.", Toast.LENGTH_LONG).show();
finish();
return;
}
if(!mBluetoothAdapter.isEnabled())
{
Toast.makeText(this, "Please enable your Bluetooth and re-run this program.", Toast.LENGTH_LONG).show();
finish();
return;
}
/*2:获取远程BlueToothDevice*/
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if(mBluetoothAdapter == null)
{
Toast.makeText(this, "Can't get remote device.", Toast.LENGTH_LONG).show();
finish();
return;
}
/*3:获得Socket*/
try {
btSocket = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) {
Log.e(TAG, "ON RESUME: Socket creation failed.", e);
}
/*4:取消discovered节省资源*/
mBluetoothAdapter.cancelDiscovery();
/*5:连接*/
try {
btSocket.connect();
Log.e(TAG, "ON RESUME: BT connection established, data transfer link open.");
} catch (IOException e) {
try {
btSocket.close();
} catch (IOException e2) {
Log .e(TAG,"ON RESUME: Unable to close socket during connection failure", e2);
}
}
/*此时可以通信了,放在任意函数中*/
/* try {
outStream = btSocket.getOutputStream();
inStream = btSocket.getInputStream(); //可在TextView里显示
} catch (IOException e) {
Log.e(TAG, "ON RESUME: Output stream creation failed.", e);
}
String message = "1";
byte[] msgBuffer = message.getBytes();
try {
outStream.write(msgBuffer);
} catch (IOException e) {
Log.e(TAG, "ON RESUME: Exception during write.", e);
}
*/
通用搜索模式代码模板:
简洁简洁方式1 demo
作用: 用VerticalSeekBar控制一个 LED屏幕的亮暗。
直接上码咯~
package com.example.seed2;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.os.Bundle;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.DialogInterface;
import android.util.Log;
import android.view.KeyEvent;
import android.widget.Toast;
public class MetalSeed extends Activity {
private static final String TAG = "BluetoothTest";
private BluetoothAdapter mBluetoothAdapter = null;
private BluetoothSocket btSocket = null;
private OutputStream outStream = null;
private InputStream inStream = null;
private VerticalSeekBar vskb = null;
private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); //这条是蓝牙串口通用的UUID,不要更改
private static String address = "00:12:02:22:06:61"; // ==要连接的蓝牙设备MAC地址
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
this.vskb = (VerticalSeekBar)super.findViewById(R.id.mskb);
this.vskb.setOnSeekBarChangeListener(new OnSeekBarChangeListenerX());
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if(mBluetoothAdapter == null)
{
Toast.makeText(this, "Bluetooth is not available.", Toast.LENGTH_LONG).show();
finish();
return;
}
if(!mBluetoothAdapter.isEnabled())
{
Toast.makeText(this, "Please enable your Bluetooth and re-run this program.", Toast.LENGTH_LONG).show();
finish();
return;
}
}
private class OnSeekBarChangeListenerX implements VerticalSeekBar.OnSeekBarChangeListener {
public void onProgressChanged(VerticalSeekBar seekBar, int progress, boolean fromUser) {
//Main.this.clue.setText(seekBar.getProgress());
/* String message;
byte [] msgBuffer;
try {
outStream = btSocket.getOutputStream();
} catch (IOException e) {
Log.e(TAG,"ON RESUME : Output Stream creation failed.", e);
}
message =Integer.toString( seekBar.getProgress() );
msgBuffer = message.getBytes();
try{
outStream.write(msgBuffer);
} catch (IOException e) {
Log.e (TAG, "ON RESUME : Exception during write.", e);
} */
}
public void onStartTrackingTouch(VerticalSeekBar seekBar) {
String message;
byte [] msgBuffer;
try {
outStream = btSocket.getOutputStream();
} catch (IOException e) {
Log.e(TAG,"ON RESUME : Output Stream creation failed.", e);
}
message =Integer.toString( seekBar.getProgress() );
msgBuffer = message.getBytes();
try{
outStream.write(msgBuffer);
} catch (IOException e) {
Log.e (TAG, "ON RESUME : Exception during write.", e);
}
}
public void onStopTrackingTouch(VerticalSeekBar seekBar) {
String message;
byte [] msgBuffer;
try {
outStream = btSocket.getOutputStream();
} catch (IOException e) {
Log.e(TAG,"ON RESUME : Output Stream creation failed.", e);
}
message =Integer.toString( seekBar.getProgress() );
msgBuffer = message.getBytes();
try{
outStream.write(msgBuffer);
} catch (IOException e) {
Log.e (TAG, "ON RESUME : Exception during write.", e);
}
}
}
@Override
public void onStart()
{
super.onStart();
}
@Override
public void onResume()
{
super.onResume();
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
try {
btSocket = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) {
Log.e(TAG, "ON RESUME: Socket creation failed.", e);
}
mBluetoothAdapter.cancelDiscovery();
try {
btSocket.connect();
Log.e(TAG, "ON RESUME: BT connection established, data transfer link open.");
} catch (IOException e) {
try {
btSocket.close();
} catch (IOException e2) {
Log .e(TAG,"ON RESUME: Unable to close socket during connection failure", e2);
}
}
// Create a data stream so we can talk to server.
/* try {
outStream = btSocket.getOutputStream();
inStream = btSocket.getInputStream();
} catch (IOException e) {
Log.e(TAG, "ON RESUME: Output stream creation failed.", e);
}
String message = "read";
byte[] msgBuffer = message.getBytes();
try {
outStream.write(msgBuffer);
} catch (IOException e) {
Log.e(TAG, "ON RESUME: Exception during write.", e);
}
int ret = -1;
while( ret != -1)
{
try {
ret = inStream.read();
} catch (IOException e)
{
e.printStackTrace();
}
}
*/
}
@Override