之前兩篇都是在說(shuō)與手機(jī)的連接,,連接方法,和主動(dòng)配對(duì)連接,,都是手機(jī)與手機(jī)的操作,,做起來(lái)還是沒(méi)問(wèn)題的,但是最終的目的是與單片機(jī)的藍(lán)牙模塊的通信,。
下面是到目前為止嘗試的與單片機(jī)的通信方法,,沒(méi)有成功,但是從思路上來(lái)說(shuō)沒(méi)有問(wèn)題,,最大的問(wèn)題是與單片機(jī)配對(duì)的時(shí)候,,單片機(jī)的藍(lán)牙模塊的PIN配對(duì)碼是寫(xiě)死的,固定為1234,, 而手機(jī)這邊連接配對(duì)都是自動(dòng)生成的PIN配對(duì)碼,,這種方式在手機(jī)與手機(jī)配對(duì)的時(shí)候是極為方便的,但是在這里與單片機(jī)連接卻成了最大的問(wèn)題,,因?yàn)槭謾C(jī)自動(dòng)生成而且每次都不一樣,,所以沒(méi)法與單片機(jī)藍(lán)牙模塊的1234相同也就沒(méi)法陪對(duì)了。下面只是介紹的到目前為止我們的大題思路,,具體代碼很多,,而且涉及到項(xiàng)目也就沒(méi)有貼。 如果關(guān)于上面的問(wèn)題哪位同學(xué)有思路或者做過(guò)類似的項(xiàng)目還請(qǐng)指點(diǎn),。
首先,,如何開(kāi)啟藍(lán)牙設(shè)備和設(shè)置可見(jiàn)時(shí)間: private void search() { BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); if (!adapter.isEnabled()) { adapter.enable(); } Intent enable = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); enable.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 3600); //3600為藍(lán)牙設(shè)備可見(jiàn)時(shí)間 startActivity(enable); Intent searchIntent = new Intent(this, ComminuteActivity.class); startActivity(searchIntent); }
public class ComminuteActivity extends Activity { private BluetoothReceiver receiver; private BluetoothAdapter bluetoothAdapter; private List<String> devices; private List<BluetoothDevice> deviceList; private Bluetooth client; private final String lockName = 'YESYOU'; private String message = '000001'; private ListView listView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.search_layout); listView = (ListView) this.findViewById(R.id.list); deviceList = new ArrayList<BluetoothDevice>(); devices = new ArrayList<String>(); bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); bluetoothAdapter.startDiscovery(); IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); receiver = new BluetoothReceiver(); registerReceiver(receiver, filter); listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { setContentView(R.layout.connect_layout); BluetoothDevice device = deviceList.get(position); client = new Bluetooth(device, handler); try { client.connect(message); } catch (Exception e) { Log.e('TAG', e.toString()); } } }); } @Override protected void onDestroy() { unregisterReceiver(receiver); super.onDestroy(); } private final Handler handler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case Bluetooth.CONNECT_FAILED: Toast.makeText(ComminuteActivity.this, '連接失敗', Toast.LENGTH_LONG).show(); try { client.connect(message); } catch (Exception e) { Log.e('TAG', e.toString()); } break; case Bluetooth.CONNECT_SUCCESS: Toast.makeText(ComminuteActivity.this, '連接成功', Toast.LENGTH_LONG).show(); break; case Bluetooth.READ_FAILED: Toast.makeText(ComminuteActivity.this, '讀取失敗', Toast.LENGTH_LONG).show(); break; case Bluetooth.WRITE_FAILED: Toast.makeText(ComminuteActivity.this, '寫(xiě)入失敗', Toast.LENGTH_LONG).show(); break; case Bluetooth.DATA: Toast.makeText(ComminuteActivity.this, msg.arg1 + '', Toast.LENGTH_LONG).show(); break; } } }; private class BluetoothReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (BluetoothDevice.ACTION_FOUND.equals(action)) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); if (isLock(device)) { devices.add(device.getName()); } deviceList.add(device); } showDevices(); } } private boolean isLock(BluetoothDevice device) { boolean isLockName = (device.getName()).equals(lockName); boolean isSingleDevice = devices.indexOf(device.getName()) == -1; return isLockName && isSingleDevice; } private void showDevices() { ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, devices); listView.setAdapter(adapter); }} 這里需要提一下的是,,startDiscovery()這個(gè)方法和它的返回值,它是一個(gè)異步方法,,會(huì)對(duì)其他藍(lán)牙設(shè)備進(jìn)行搜索,,持續(xù)時(shí)間為12秒。 搜索過(guò)程其實(shí)是在System Service中進(jìn)行,,我們可以通過(guò)cancelDiscovery()方法來(lái)停止這個(gè)搜索,。在系統(tǒng)搜索藍(lán)牙設(shè)備的過(guò)程中,系統(tǒng)可能會(huì)發(fā)送以下三個(gè)廣播:ACTION_DISCOVERY_START(開(kāi)始搜索),, ACTION_DISCOVERY_FINISHED(搜索結(jié)束) 和ACTION_FOUND(找到設(shè)備),。 ACTION_FOUND這個(gè)才是我們想要的,這個(gè)Intent中包含兩個(gè)extra fields: EXTRA_DEVICE和EXTRA_CLASS,, 包含的分別是BluetoothDevice和BluetoothClass,, EXTRA_DEVICE中的BluetoothDevice就是我們搜索到的設(shè)備對(duì)象,從中獲得設(shè)備的名稱和地址,。 而EXTRA_CLASS中的BluetoothClass是搜索到的設(shè)備的類型,,比如搜索到的是手機(jī)還是耳機(jī)或者其他,之后我會(huì)寫(xiě)一篇關(guān)于它的介紹,。 在這個(gè)上面我現(xiàn)在在想,,是否通過(guò)判斷搜索到的設(shè)備類型來(lái)識(shí)別單片機(jī)藍(lán)牙模塊與手機(jī)藍(lán)牙的不同,采取不一樣的配對(duì)方式,,從而不自動(dòng)生成配對(duì)碼,。不知是否可行,一會(huì)嘗試,。
搜索到該設(shè)備后,,我們就要對(duì)該設(shè)備進(jìn)行連接和通信。 public void connect(final String message) { Thread thread = new Thread(new Runnable() { public void run() { BluetoothSocket tmp = null; Method method; try { method = device.getClass().getMethod('createRfcommSocket', new Class[]{int.class}); tmp = (BluetoothSocket) method.invoke(device, 1); } catch (Exception e) { setState(CONNECT_FAILED); Log.e('TAG', e.toString()); } socket = tmp; try { socket.connect(); isConnect = true; } catch (Exception e) { setState(CONNECT_FAILED); Log.e('TAG', e.toString()); } if (isConnect) { try { OutputStream outStream = socket.getOutputStream(); outStream.write(getHexBytes(message)); } catch (IOException e) { setState(WRITE_FAILED); Log.e('TAG', e.toString()); } try { InputStream inputStream = socket.getInputStream(); int data; while (true) { try { data = inputStream.read(); Message msg = handler.obtainMessage(); msg.what = DATA; msg.arg1 = data; handler.sendMessage(msg); } catch (IOException e) { setState(READ_FAILED); Log.e('TAG', e.toString()); break; } } } catch (IOException e) { setState(WRITE_FAILED); Log.e('TAG', e.toString()); } } if (socket != null) { try { socket.close(); } catch (IOException e) { Log.e('TAG', e.toString()); } } }} 這里包括寫(xiě)入和讀取,,用法和基本的Socket是一樣的,,但是寫(xiě)入的時(shí)候,需要將字符串轉(zhuǎn)化為16進(jìn)制: private byte[] getHexBytes(String message) { int len = message.length() / 2; char[] chars = message.toCharArray(); String[] hexStr = new String[len]; byte[] bytes = new byte[len]; for (int i = 0, j = 0; j < len; i += 2, j++) { hexStr[j] = '' + chars[i] + chars[i + 1]; bytes[j] = (byte) Integer.parseInt(hexStr[j], 16); } return bytes; }
連接設(shè)備之前需要UUID,,所謂的UUID,,就是用來(lái)進(jìn)行配對(duì)的,全稱是Universally Unique Identifier,,是一個(gè)128位的字符串ID,,用于進(jìn)行唯一標(biāo)識(shí)。網(wǎng)上的例子,,包括谷歌的例子提供的uuid,,通用的'00001101-0000-1000-8000-00805F9B34FB'也試過(guò)了,在配對(duì)的時(shí)候都是自動(dòng)生成了配對(duì)碼,,也無(wú)法正常與單片機(jī)的藍(lán)牙模塊連接,,所以,,我就利用反射的原理,讓設(shè)備自己提供UUID嘗試,。到這里其實(shí)我有點(diǎn)懷疑自己對(duì)于UUID的理解是否正確了,。 在谷歌提供的例子中,我們可以看到谷歌的程序員的程序水平很高,,一些好的編碼習(xí)慣我們可以學(xué)習(xí)一下,,像是在try..catch中才定義的變量,我們應(yīng)該在try...catch之前聲明一個(gè)臨時(shí)變量,,然后再在try...catch后賦值給我們真正要使用的變量,。這種做法的好處就是:如果我們直接就是使用真正的變量,,當(dāng)出現(xiàn)異常的時(shí)候,,該變量的使用就會(huì)出現(xiàn)問(wèn)題,而且很難進(jìn)行排查,,如果是臨時(shí)變量,,我么可以通過(guò)檢查變量的值來(lái)確定是否是賦值時(shí)出錯(cuò)。
作者:jason0539 微博:http://weibo.com/2553717707 博客:http://blog.csdn.net/jason0539(轉(zhuǎn)載請(qǐng)說(shuō)明出處) |
|
來(lái)自: 迎著風(fēng)兒看星星 > 《待分類》