编写Android中的蓝牙模块驱动和底层HART设备

ESP32智能咖啡机改造全解析:从硬件选型到固件开发 在物联网与嵌入式控制技术的推动下,利用ESP32等低成本MCU对传统家电进行智能化改造已成为热门实践。其核心原理是通过温度、压力等传感器采集物理参数,借助PID闭环控制算法让微控制器精确调节加热与泵动作,从而提升设备稳定性。搭配Wi-Fi与MQTT协议,设备数据可实时同步至手机App或Home Assistant,实现远程监控与智能联动。这一方案不仅能应用在咖啡机控温场景,也适用于恒温恒压等工业民用控制领域。文章以一台老式半自动意式咖啡机为例,完整呈现了基于ESP32的硬件选型、电路隔离、固件开发、PID调 阅读详情


【背景】

手上有个android设备:

现在希望可以在PAD上通过蓝牙去连接蓝牙的HART猫,然后再去操作HART的设备。

现在就是去android中写对应的蓝牙模块的程序,此处暂且叫做蓝牙驱动吧。

其中此处的开发环境是ADT。

【折腾过程】

1.参考:

Bluetooth | Android Developers

去添加权限:

add user permission android.permission.BLUETOOTH

添加好了:

added android.permission.BLUETOOTH and BLUETOOTH_ADMIN

2.

参考代码期间,遇到:

【已解决】Android的蓝牙实例代码中找不到REQUEST_ENABLE_BT

然后再去用BluetoothAdapter去检测是否支持蓝牙,且支持的话去打开:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
private final int REQUEST_ENABLE_BT = 1 ;
private BluetoothAdapter mBluetoothAdapter;
private void testBluetooth() {
     mBluetoothAdapter= BluetoothAdapter.getDefaultAdapter();
 
     if (mBluetoothAdapter == null ) {
         // Device does not support Bluetooth
         Toast.makeText(getApplicationContext(), "Device does not support Bluetooth" , Toast.LENGTH_LONG).show();
     }
     else {
         //android.bluetooth.BluetoothAdapter@211120b0
         Toast.makeText(getApplicationContext(), "Device support Bluetooth" , Toast.LENGTH_SHORT).show();
         
         if (!mBluetoothAdapter.isEnabled()) {
             Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
             startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
         }
         else {
             scanOrDiscoverBtDevices();
         }
     }
 
}
 
@Override
protected void onActivityResult( int requestCode, int resultCode, Intent data) {
     if (requestCode == REQUEST_ENABLE_BT)
     {
         if (resultCode == RESULT_OK){
             Toast.makeText(getApplicationContext(), "Enabled Bluetooth now" , Toast.LENGTH_LONG).show();
             scanOrDiscoverBtDevices();
         }
         else {
             Toast.makeText(getApplicationContext(), "Not enable Bluetooth !" , Toast.LENGTH_LONG).show();
         }
     }
}

3.关于检测蓝牙状态变化,而去实现蓝牙被打开还是关闭了,可以参考:

Optionally, your application can also listen for the ACTION_STATE_CHANGED broadcast Intent, which the system will broadcast whenever the Bluetooth state has changed. This broadcast contains the extra fields EXTRA_STATE and EXTRA_PREVIOUS_STATE, containing the new and old Bluetooth states, respectively. Possible values for these extra fields areSTATE_TURNING_ON, STATE_ON, STATE_TURNING_OFF, and STATE_OFF. Listening for this broadcast can be useful to detect changes made to the Bluetooth state while your app is running.

4.另外,看到提示了:

Tip: Enabling discoverability will automatically enable Bluetooth. If you plan to consistently enable device discoverability before performing Bluetooth activity, you can skip step 2 above. Read about enabling discoverability, below.

这也就是我之前疑惑的:

别的那个android的app,可以点击开启蓝牙,而无需弹出请求权限的对话框。

就是通过这个discovery功能实现的。

 

提示:

后来又遇到:

【已解决】Android中运行startActivityForResult后但是onActivityResult不执行

 

5.目前已经实现了,既可以scan那些paired,也可以discover搜寻当前附近的蓝牙设备。

代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
private final int REQUEST_ENABLE_BT = 1 ;
private BluetoothAdapter mBluetoothAdapter;
private void testBluetooth() {
     mBluetoothAdapter= BluetoothAdapter.getDefaultAdapter();
 
     if (mBluetoothAdapter == null ) {
         // Device does not support Bluetooth
         Toast.makeText(getApplicationContext(), "Device does not support Bluetooth" , Toast.LENGTH_LONG).show();
     }
     else {
         //android.bluetooth.BluetoothAdapter@211120b0
         Toast.makeText(getApplicationContext(), "Device support Bluetooth" , Toast.LENGTH_SHORT).show();
         
         if (!mBluetoothAdapter.isEnabled()) {
             Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
             startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
         }
         else {
             scanOrDiscoverBtDevices();
         }
     }
 
}
 
private void scanOrDiscoverBtDevices(){
     //scanBtDevices();
     
     discoverBtDevices();
}
 
// Create a BroadcastReceiver for ACTION_FOUND
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
     public void onReceive(Context context, Intent intent) {
         String action = intent.getAction();
         // When discovery finds a device
         if (BluetoothDevice.ACTION_FOUND.equals(action)) {
             // Get the BluetoothDevice object from the Intent
             BluetoothDevice btDev = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
             //mArrayAdapter.add(btDev.getName() + "\n" + btDev.getAddress());
             Toast.makeText(getApplicationContext(), btDev.getName() + "\n" + btDev.getAddress(), Toast.LENGTH_LONG).show();
         }
     }
};
 
private void discoverBtDevices(){
     // Register the BroadcastReceiver
     IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
     registerReceiver(mReceiver, filter); // Don't forget to unregister during onDestroy
     
     mBluetoothAdapter.startDiscovery();
}
 
private void scanBtDevices(){
     Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices(); //[BC:85:1F:96:99:C9, 00:06:66:4C:75:FE]
  // If there are paired devices
  if (pairedDevices.size() > 0 ) {
      //ArrayAdapter mArrayAdapter = new ArrayAdapter();
      
      // Loop through paired devices
      for (BluetoothDevice btDev : pairedDevices) {
          //mArrayAdapter.add(btDev.getName() + "\n" + btDev.getAddress());
          Toast.makeText(getApplicationContext(), btDev.getName() + "\n" + btDev.getAddress(), Toast.LENGTH_LONG).show();
      }
  }
}
 
@Override
protected void onActivityResult( int requestCode, int resultCode, Intent data) {
     if (requestCode == REQUEST_ENABLE_BT)
     {
         if (resultCode == RESULT_OK){
             Toast.makeText(getApplicationContext(), "Enabled Bluetooth now" , Toast.LENGTH_LONG).show();
             scanOrDiscoverBtDevices();
         }
         else {
             Toast.makeText(getApplicationContext(), "Not enable Bluetooth !" , Toast.LENGTH_LONG).show();
         }
     }
}

6.继续折腾。

对于可以被搜索“Enabling discoverability”暂时就不去关心了。毕竟当前android设备能搜到HART猫即可。暂时无需考虑被搜索到。

7.再去建立连接,期间出现UUID和connect失败方面的问题:

【已解决】Android中连接蓝牙设备时遇到createRfcommSocketToServiceRecord的UUID问题和BluetoothSocket的connect失败

最终,用如下代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
private String mactekHartModemName;
private UUID mactekHartModemUuid;
 
//void afterFoundBtHartModem(BluetoothDevice btDev, Parcelable[] btDevUuid){
void afterFoundBtHartModem(BluetoothDevice btDev, UUID btDevUuid){
     if ( null != btDevUuid){
                     
     }
     
     //mactekHartModemName = btDev.getName(); //"MACTekViator75FE"
     //mactekHartModemUuid = UUID.fromString(mactekHartModemName);
     
     String uuidValue;
     //uuidValue = "e214d9ae-c3ba-4e25-abb5-299041353bc3";
     
     //https://groups.google.com/forum/#!topic/android-developers/vyTEJOXELos
     //uuidValue = "00001101-0000-100­0-8000-00805F9B34FB";
     //uuidValue = "00000003-0000-100­0-8000-00805F9B34FB";
     uuidValue = "00001101-0000-1000-8000-00805F9B34FB" ;
 
     mactekHartModemUuid = UUID.fromString(uuidValue);
 
     ConnectThread connectBtThread = new ConnectThread(btDev);
     connectBtThread.start();
}
 
private class ConnectThread extends Thread {
     private final BluetoothSocket mmSocket;
     private final BluetoothDevice mmDevice;
  
     public ConnectThread(BluetoothDevice device) {
         // Use a temporary object that is later assigned to mmSocket,
         // because mmSocket is final
         BluetoothSocket tmp = null ;
         mmDevice = device;
  
         // Get a BluetoothSocket to connect with the given BluetoothDevice
         try {
             // MY_UUID is the app's UUID string, also used by the server code
             tmp = device.createRfcommSocketToServiceRecord(mactekHartModemUuid); //00001101-0000-1000-8000-00805F9B34FB
 
         } catch (IOException e) { }
         mmSocket = tmp;
     }
  
     public void run() {
         // Cancel discovery because it will slow down the connection
         mBluetoothAdapter.cancelDiscovery();
  
         try {
             // Connect the device through the socket. This will block
             // until it succeeds or throws an exception
             mmSocket.connect();
         } catch (IOException connectException) {
             // Unable to connect; close the socket and get out
             try {
                 mmSocket.close();
             } catch (IOException closeException) { }
             return ;
         }
  
         // Do work to manage the connection (in a separate thread)
         manageConnectedSocket(mmSocket);
     }
  
     /** Will cancel an in-progress connection, and close the socket */
     public void cancel() {
         try {
             mmSocket.close();
         } catch (IOException e) { }
     }
}

可以正常触发android系统打开配对窗口,输入密码:

pair with MACTekViator75FE bluetooth hart modem

后,是可以配对成功的:

use uuid 00001101-0000-1000-8000-00805F9B34FB then bluetooth connect will ok

8.然后接着再去试试发送数据给蓝牙HART猫是否成功,能否收到返回的数据。

最后所用代码为:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
     private final int REQUEST_ENABLE_BT = 1 ;
     private BluetoothAdapter mBluetoothAdapter;
     private void testBluetooth() {
         mBluetoothAdapter= BluetoothAdapter.getDefaultAdapter();
 
         if (mBluetoothAdapter == null ) {
             // Device does not support Bluetooth
             Toast.makeText(getApplicationContext(), "Device does not support Bluetooth" , Toast.LENGTH_LONG).show();
         }
         else {
             //android.bluetooth.BluetoothAdapter@211120b0
             Toast.makeText(getApplicationContext(), "Device support Bluetooth" , Toast.LENGTH_SHORT).show();
             
             if (!mBluetoothAdapter.isEnabled()) {
                 Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                 startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
             }
             else {
                 scanOrDiscoverBtDevices();
             }
         }
     }
 
     private void scanOrDiscoverBtDevices(){
         //scanBtDevices();
         
         discoverBtDevices();
     }
     
     // Create a BroadcastReceiver for ACTION_FOUND
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
             // When discovery finds a device
             if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                 // Get the BluetoothDevice object from the Intent
                 BluetoothDevice btDev = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
 
                 //mArrayAdapter.add(btDev.getName() + "\n" + btDev.getAddress());
                  String btDevName = btDev.getName();
                  String btDevMacAddr = btDev.getAddress();
                 Toast.makeText(getApplicationContext(), btDevName + "\n" + btDevMacAddr, Toast.LENGTH_LONG).show();
 
                 if (btDevName.contains( "MACTekViator" )){ //MACTekViator75FE
                     afterFoundBtHartModem(btDev);
                 }
             }
         }
     };
 
     private void discoverBtDevices(){
         // Register the BroadcastReceiver
         IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
         registerReceiver(mReceiver, filter); // Don't forget to unregister during onDestroy
         
         mBluetoothAdapter.startDiscovery();
     }
     
     private void scanBtDevices(){
         Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
         //[BC:85:1F:96:99:C9, 00:06:66:4C:75:FE]
 
          // If there are paired devices
          if (pairedDevices.size() > 0 ) {
 
              // Loop through paired devices
              for (BluetoothDevice btDev : pairedDevices) {
                  //mArrayAdapter.add(btDev.getName() + "\n" + btDev.getAddress());
                  //Toast.makeText(getApplicationContext(), btDev.getName() + "\n" + btDev.getAddress(), Toast.LENGTH_LONG).show();
                  
                  String btDevName = btDev.getName();
                  String btDevMacAddr = btDev.getAddress();
                  Toast.makeText(getApplicationContext(), btDevName + "\n" + btDevMacAddr, Toast.LENGTH_LONG).show();
     
                 if (btDevName.contains( "MACTekViator" )){ //found our concerned Bluetooth HART Modem
                     afterFoundBtHartModem(btDev);
                     break ;
                 }
              }
      }
     }
     
     @Override
     protected void onActivityResult( int requestCode, int resultCode, Intent data) {
         if (requestCode == REQUEST_ENABLE_BT)
         {
             if (resultCode == RESULT_OK){
                 Toast.makeText(getApplicationContext(), "Enabled Bluetooth now" , Toast.LENGTH_LONG).show();
                 scanOrDiscoverBtDevices();
             }
             else {
                 Toast.makeText(getApplicationContext(), "Not enable Bluetooth !" , Toast.LENGTH_LONG).show();
             }
         }
     }
     
     private UUID mactekHartModemUuid;
     
     void afterFoundBtHartModem(BluetoothDevice btDev){
         String sspUuid;
         
         //http://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#createRfcommSocketToServiceRecord%28java.util.UUID%29
         //Hint: If you are connecting to a Bluetooth serial board then try using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB.
         //However if you are connecting to an Android peer then please generate your own unique UUID.
         sspUuid = "00001101-0000-1000-8000-00805F9B34FB" ;
 
         mactekHartModemUuid = UUID.fromString(sspUuid);
 
         ConnectThread connectBtThread = new ConnectThread(btDev);
         connectBtThread.start();
     }
 
     private class ConnectThread extends Thread {
         private final BluetoothSocket mmSocket;
         private final BluetoothDevice mmDevice;
 
         public ConnectThread(BluetoothDevice device) {
             // Use a temporary object that is later assigned to mmSocket,
             // because mmSocket is final
             BluetoothSocket tmp = null ;
             mmDevice = device;
      
             // Get a BluetoothSocket to connect with the given BluetoothDevice
             try {
                 // MY_UUID is the app's UUID string, also used by the server code
                 tmp = device.createRfcommSocketToServiceRecord(mactekHartModemUuid); //00001101-0000-1000-8000-00805F9B34FB
 
             } catch (IOException e) { }
             mmSocket = tmp;
         }
      
         public void run() {
             // Cancel discovery because it will slow down the connection
             mBluetoothAdapter.cancelDiscovery();
      
             try {
                 // Connect the device through the socket. This will block
                 // until it succeeds or throws an exception
                 mmSocket.connect();
             } catch (IOException connectException) {
                 // Unable to connect; close the socket and get out
                 try {
                     mmSocket.close();
                 } catch (IOException closeException) { }
                 return ;
             }
      
             // Do work to manage the connection (in a separate thread)
             manageConnectedSocket(mmSocket);
         }
      
         /** Will cancel an in-progress connection, and close the socket */
         public void cancel() {
             try {
                 mmSocket.close();
             } catch (IOException e) { }
         }
     }   
 
     private void manageConnectedSocket(BluetoothSocket socket){
         //Toast.makeText(getApplicationContext(), "Bluetooth HART Modem Connected", Toast.LENGTH_LONG).show();
         ConnectedThread connectedThread = new ConnectedThread(socket);
         connectedThread.start();
 
         //command 0
         String command0Str = "FFFFFFFFFF0280000082" ;
         byte [] commnd0Bytes = HexString2Bytes(command0Str);
         connectedThread.write(commnd0Bytes);
         //read out command 0 response
         byte [] readoutBuffer = new byte [ 1024 ];
         
         //Note: here use DEBUG, so will take some time, so follow can read out real response data
         //if no DEBUG, just run through, will only get -1
         //readoutBuffer = connectedThread.read(); //[-1,
         readoutBuffer = connectedThread.read(); //[-1, -1, -1, -1, 6, -128, 0, 14, 0, 69, -2, 54, 2, 5, 5, 2, 13, 1, 3, 43, -11, -82, 122, 0, 0, 0, 0,
         parseHartCommand0Resp(readoutBuffer);
         //readoutBuffer = connectedThread.read();
     }
     
     private void parseHartCommand0Resp( byte [] command0RespBytes){
         //-1, -1, -1, -1, 6, -128, 0, 14, 0, 69, -2, 54, 2, 5, 5, 2, 13, 1, 3, 43, -11, -82, 122,
         //FF FF FF FF 06 80 00 0E 00 45 FE 36 02 05 02 0D 01 03 2B F5 AE 7A
         //(hex value) --->
         //FF FF FF FF 06 80 00 0E 00 45
         //FE ==254(expansion)
         //ManufactureIdentificationCode=36==Yamatake
         //ManufactureDeviceType=02
         //PreampleNumber=5
         //UniversalCommandRevision=5==HART5
         //DeviceSpecificCommandRevision=2
         //SoftwareRevision=13
         //HardwareRevision=1
         //DeviceFunctionFlag=3
         //DeviceIdNumber=2B F5 AE
         //CommonPracticeCommandRevision=7A
     }
 
     private boolean isReadoutRespOk = false ;
     
     private class ConnectedThread extends Thread {
         private final BluetoothSocket mmSocket;
         private final InputStream mmInStream;
         private final OutputStream mmOutStream;
      
         public ConnectedThread(BluetoothSocket socket) {
             mmSocket = socket;
             InputStream tmpIn = null ;
             OutputStream tmpOut = null ;
      
             // Get the input and output streams, using temp objects because
             // member streams are final
             try {
                 tmpIn = socket.getInputStream();
                 tmpOut = socket.getOutputStream();
             } catch (IOException e) { }
      
             mmInStream = tmpIn;
             mmOutStream = tmpOut;
         }
      
         public void run() {
//          byte[] buffer = new byte[1024];  // buffer store for the stream
//          int bytes; // bytes returned from read()
//  
//          // Keep listening to the InputStream until an exception occurs
//          while (true) {
//              try {
//                  // Read from the InputStream
//                  bytes = mmInStream.read(buffer);
//                  // Send the obtained bytes to the UI activity
//                  //mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer).sendToTarget();
//                  if(bytes > 0){
//                      //Toast.makeText(getApplicationContext(), "Got HART Command 0 resp data: " + buffer.toString(), Toast.LENGTH_LONG).show();
//                      isReadoutRespOk = true;
//                     
//                      //-1, -1, -1, -1, 6, -128, 0, 14, 0, 69, -2, 54, 2, 5, 5, 2, 13, 1, 3, 43, -11, -82, 122,
//                      //parseHartCommand0ResponseData();
//                  }
//                  else{
//                      isReadoutRespOk = false;
//                  }
//
//              } catch (IOException e) {
//                  break;
//              }
//          }
         }
      
         /* Call this from the main activity to send data to the remote device */
         public void write(byte[] bytes) {
             try {
                 mmOutStream.write(bytes);
             } catch (IOException e) { }
         }
      
         public byte[] read() {
             byte[] buffer = new byte[1024];  // buffer store for the stream
             int bytes;
             try {
                 bytes = mmInStream.read(buffer);
             } catch (IOException e) {
                 
             }
             return buffer;
         }
      
         /* Call this from the main activity to shutdown the connection */
         public void cancel() {
             try {
                 mmSocket.close();
             } catch (IOException e) { }
         }
     }
     
     //copy from other code
     // string to hex array
     public byte [] HexString2Bytes(String hexStr) {
         if ( null == hexStr || 0 == hexStr.length()) {
             return null ;
         }
         byte [] ret = new byte [hexStr.length() / 2 ];
         byte [] tmp = hexStr.getBytes();
         for ( int i = 0 ; i < (tmp.length / 2 ); i++) {
             ret[i] = uniteBytes(tmp[i * 2 ], tmp[i * 2 + 1 ]);
         }
         return ret;
     }
     
     private  byte uniteBytes( byte src0, byte src1) {
         byte _b0 = Byte.decode( "0x" + new String( new byte [] { src0 }))
                 .byteValue();
         _b0 = ( byte ) (_b0 << 4 );
         byte _b1 = Byte.decode( "0x" + new String( new byte [] { src1 }))
                 .byteValue();
         byte result = ( byte ) (_b0 | _b1);
         return result;
     }
?
1
  

 

【总结】

至此,终于算是跑通了,可以通过:

平板上面的蓝牙,扫描找到蓝牙HART猫,然后通过HART猫发送command 0给HART设备,获得对应的信息:

command 0 can response data bytes from mactek viator bluetooth hart modem

 

注:

此处所用的HART设备和这里:

【记录】试用通过蓝牙操作HART设备的Android的程序:teknikol COMMANDER

是一样的:

所以上述代码解析后的信息,也是和之前一致的。

提取Android盒子(CM201-1 YS)dtb文件 最近从某鱼上掏了一个CM201-1 YS的盒子,动手倒腾倒腾,准备安装Armbian,用来做矿机,但该型号的盒子ophub上面没有完全适配的镜像,故而想尝试下,看能否整个适配镜像出来。 阅读详情

相关推荐

基于Android8.1的博通bcm89342蓝牙驱动的驱动移植记录

基于Android 8.1 的博通蓝牙(BCM89342)的驱动移植记录说明一 、软硬件平台二、蓝牙移植流程2.1 kernel 对蓝牙的驱动支持配置2.2 kernel层编写蓝牙电源管理(bt rfkill)驱动2.3 android源码中把蓝牙这个宏定义给选上2.4 hal层修改和移植2.5 system/bt目录下相关源代码修改三 系统集成3.1 对主机端和蓝牙通信串口、固件存放路径等...

dream578521370的博客 6392

Android之蓝牙驱动开发总结

Android之蓝牙驱动开发总结 一Bluetooth基本概念 3 二AndroidBluetooth架构 3 2.1Bluetooth架构图 3 2.2Bluetooth代码层次结构 3 三Bluetooth协议栈分析 4 3.1蓝牙协议栈 4 3

manshq163com的专栏 1万+

【信息科学与工程学】【控制科学】第十二篇 微型计算机控制技术01

更精确的经典模型:I1在第5周期WB结束,I2最早可在第6周期进入EX,但I2在ID阶段就需要R1,因此I2的ID需在第6周期,而I1的WB在第5周期,所以I2的ID可以紧接在第6周期,但中间仍有一个stall(因为I1的EX结果要等到MEM之后才能转发给ID?有优先级继承后,Task_L被提升优先级,不会被Task_M抢占,阻塞时间缩短为Task_L剩余执行时间(9ms),仍可能超过10ms,但可通过调整任务周期或使用中断处理缓解。电感L=10μH,输出电容C=100μF,ESR=5mΩ。

weixin_49199313的博客 8624

android 4.4 蓝牙开发总结(电视盒子)

6.0的蓝牙已经开发完毕,因为可以得到系统6.0的jar包,so也就开发的快些,更好些。4.4因为代码部分在setting模块里,部分在系统中,so不方便打成jar包。所以就通过广播接受改变状态之类的。也算鼓捣出来一款。 4.4蓝牙效果 开发的思路: 1.开关蓝牙 2.扫描到蓝牙列表和得到配对列表     下面关于连接蓝牙: A2dp:这个是蓝牙音频传输协议 AVRCP:输入设...

SpringYang 1793

Android蓝牙内核级设备驱动设计

蓝牙驱动分析

xierong1的博客 757

Android 蓝牙驱动专题分析(1)--- 蓝牙驱动代码流程、kernel dump、tombstone问题分析

同学,别退出呀,我可是全网最牛逼的 Android 蓝牙分析博主,我写了上百篇蓝牙文章,请点击下面了解本专栏,进入本博主主页看看再走呗,一定不会让你后悔的,记得一定要去看主页置顶文章哦。不管我们使用什么操作系统,无论是 Windows、macOS,还是 Linux ,里面都安装了许多软件、驱动程序和固件。但是,这三者概念有什么区别?文字描述太抽象了,我们直接来看漫画吧! 好了,看完漫画,我们再来看正规的解释是怎样的。简单来讲,固件、驱动程序和软件之间的根本区别在于它们的设计目的。固件是赋予设备硬件生命的

手机-手表蓝牙开发工程师的博客 1438

Android中连接蓝牙设备时遇到createRfcommSocketToServiceRecord的UUID问题和BluetoothSocket的connect失败...

【问题】 折腾: 【记录】编写Android中的蓝牙模块驱动和底层HART设备 期间,参考: Bluetooth | Android Developers – ManagingAConnection 参考“Connecting as a client”中的: tmp = device.createRfcommSocketToServiceRecord(MY_UUID); 遇到UUID...

weixin_33872566的博客 3065

Android 蓝牙驱动专题分析(2)--- 蓝牙驱动代码流程、kernel dump、tombstone问题分析

作为蓝牙开发者,我们处理了解蓝牙framework、协议栈之外,还是要了解下蓝牙驱动流程的,因为在处理蓝牙开关打开失败等问题上,需要从log从查看蓝牙驱动是否打开,那么本文就分析下蓝牙驱动流程。当固件发生问题,就会走下面这个流程,我们一般需要熟悉这个流程,抓取到有效日志,提交给平台方;接下来就是追踪到固件等等一些处理函数中了, stp_btm_init_trigger_assert_timer如果蓝牙芯片发生 assert exception, 流程大概会是 1. trigger assert 2. cor

手机-手表蓝牙开发工程师的博客 1816

Android TV蓝牙模块

一、蓝牙总体架构     二、代码分布 1.应用 /packages/apps/Settings(原生的设置应用) /packages/apps/Bluetooth(原生的蓝牙应用) 2.蓝牙java框架 /frameworks/base/core/java/android/bluetooth(蓝牙部分对应的应用程序api) /frameworks/base/services

Android系统开发-VR OS-系统安全隐私 6623

Android平台蓝牙驱动调试指南与源代码

简介:在Android系统中,蓝牙驱动是连接操作系统与蓝牙硬件的桥梁,对其理解与调试是开发高效稳定蓝牙应用的基础。本文档深入介绍基于Linux内核的Android平台蓝牙驱动调试方法,包括日志分析、HCI命令交互、配置文件修改、模块加载和卸载等步骤,以及故障定位、代码审查和性能优化技巧。文档旨在帮助开发者全面掌握调试蓝牙驱动所需的技术知识,解决常见问题,提升调试能力。

weixin_42113456的博客 1377

Android之蓝牙驱动开发总结 - 全网唯一

一Bluetooth基本概念 二 Android Bluetooth架构 2.1 Bluetooth架构图 2.2 Bluetooth 代码层次结构 三 Bluetooth 协议栈分析 3.1 蓝牙协议栈 3.2 Android 与蓝牙协议栈的Bluetooth 之HCI层分析 .4.1HCI层与基带的通信方 4.2包的分析及研究 4.3通信过程的研究与分析 五Bluetooth之编程实现 5.1 HCI昙编程 5.2 L2CAP层编程 5.3 SDP层编程 六Bluetooth 之启动过程实 6.1 Bluetooth 启动步骤 6.2 Bluetooth 启动流程 6.3 Bluetooth数据流向 6.4 Bluez控制流程 .6.5 Bluetooth 启动过程分 七 Bluetooth 之驱动移植 7.1 android系统配置 7.2启动项修改

Android 蓝牙驱动 概要

http://blog.sina.com.cn/s/blog_6fba73770100nme8.html http://blog.youkuaiyun.com/jmq_0000/article/details/7379802 在linux中,蓝牙设备驱动是网络设备,使用网络接口。 蓝牙设备的网络协议,所定义的协议族为: AF_BLUETOOTH (31) 蓝牙协议部分

xbl1986的专栏 7309

Linux运维踩坑实录:手把手教你修复LVM中PV显示[unknown]的诡异问题

本文详细解析了Linux运维中LVM物理卷(PV)显示[unknown]的故障现象及修复方法。通过分析问题根源、提供标准修复流程和特殊场景处理方案,帮助运维人员快速解决VG容量异常、PV状态丢失等问题,并分享预防措施与最佳实践,确保LVM存储系统的稳定运行。

weixin_26869081的博客 347

【免费下载】 让Android设备蓝牙功能焕发新生:rtl8723du 蓝牙驱动推荐

在Android设备的使用过程中,蓝牙功能无疑是连接外部设备、传输数据的重要桥梁。然而,由于硬件差异和系统兼容性问题,部分设备在使用过程中可能会遇到蓝牙功能无法正常工作的情况。为了解决这一问题,我们推出了适用于Android系统的`rtl8723du`蓝牙驱动,该驱动已在Android 11系统上成功调通,确保了蓝牙功能的稳定运行。 ## 项目技术分析 `rtl8723du`蓝牙驱动是专为支持

gitblog_09808的博客 1623

基于资源预测的Agent弹性伸缩:在成本与响应延迟间寻找最佳平衡点

手动伸缩:完全由运维人员人工调整副本数或服务器数量,效率极低,现在基本只用于极小规模的业务。反应式伸缩:基于当前实时监控指标触发伸缩规则,比如CPU利用率超过70%就加2个副本,是目前应用最广泛的方案,典型代表是K8s HPA、KEDA。预测式伸缩:基于历史时序数据预测未来的负载,提前进行伸缩,解决反应式伸缩的滞后性问题,典型代表是AWS Predictive Scaling、阿里云预测式HPA。智能Agent伸缩。

SuperAGI2025 133

贴片二极管SOD封装详解:SOD-123/323/523尺寸焊盘设计要点

表面贴装技术中,二极管封装尺寸直接决定PCB布局与焊接可靠性。SOD封装作为小外形二极管的主流形态,其SOD-123、SOD-323、SOD-523三种规格分别对应不同的功耗与占板面积权衡。理解封装尺寸、焊盘设计计算逻辑和钢网开窗原理,是避免立碑、虚焊等工艺缺陷的关键。在可穿戴设备、电源保护等空间受限场景中,合理选择封装不仅能优化散热路径,还能提升量产良率。本文从焊盘计算、工艺要点到选型策略,全面解析SOD封装的工程实践。

weixin_42520780的博客 295

RK3588 Android12调试USB 蓝牙模块

system/bt目录下,蓝牙协议栈代码和加载libbt-vendor.so库的代码,通常情况下建议使用原生的蓝牙协议栈【在system/bt目录】,如果有厂商的协议栈对原生协议栈做过较大的修正而必须使用厂商自己的协议栈的情况下在 jni 层完成对不同厂商协议栈【一般在hardware目录下】的加载。在device/rockchip/common/wifi_bt_common.mk文件(一般rk平台代码已经添加),这个先关闭BCM的芯片,防止BCM的影响。强制使能A2DP,则将上述接口屏蔽即可。

franc521的博客 8859

别再只抄代码了!深入理解MQ2传感器数据手册,搞定ppm换算公式

本文深入解析MQ2烟雾传感器的工作原理与ppm换算公式,从数据手册解读到数学建模,提供详细的校准与优化方法。通过实际案例和代码示例,帮助开发者准确测量气体浓度,解决常见问题,提升传感器应用的可靠性。

weixin_42713608的博客 504

【亲测免费】 Android 系统 rtl8723du 蓝牙驱动

本仓库提供了一个适用于 Android 系统的 rtl8723du 蓝牙驱动资源文件。该驱动已在 Android 11 系统上成功调通,确保了蓝牙功能的正常使用。 ## 资源文件描述 - **文件名称**: rtl8723du 蓝牙驱动 - **适用系统**: Android 11 - **功能**: 支持 rtl8723du 芯片的蓝牙功能 ## 使用说明 1. 下载本仓库中的资源文件。

gitblog_09802的博客 665

CentOS7下Graylog3.0高效日志管理:从零搭建到实战应用

本文详细介绍了在CentOS7操作系统上从零开始搭建Graylog3.0日志管理平台的完整过程。内容涵盖Java环境准备、MongoDB与Elasticsearch依赖安装、Graylog Server核心配置,并实战演示了通过Graylog Sidecar集中管理日志采集器以及配置邮件告警功能,为中小型团队提供了一个比ELK更轻量、易维护的一体化日志解决方案。

weixin_29207149的博客 85

YOLOv8 智能交通违章检测 - 机动车道占用(违停/非机动车占道)详解

本文提出基于YOLOv8的智能交通违章检测方案,主要针对机动车道占用问题。系统整合目标检测、目标跟踪和ROI区域判定,实现两种典型场景检测:违章停车(静止超时)和非机动车/行人占道。详细介绍了系统架构、配置文件设计、核心逻辑实现及可视化模块,包括ROI区域管理、状态跟踪和违章判定算法。针对实际应用中的堵车误判、非机动车误报等问题,提出了密度检测、轨迹分析和自适应阈值等优化策略。该方案计算量适中,适合边缘设备部署,并建议配套开发ROI标定工具和证据链保存功能。

u010117029的博客 235
上一篇: Android之蓝牙编程开发详解
下一篇: AChartEngine应用之BarChart(动态柱形图)
It_BeeCoder
博客等级 码龄10年 967粉丝 238原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值