Browse Source

ble与设备通信

master
白凤吉 4 months ago
parent
commit
c4fd55b561
  1. 8
      app/src/main/java/com/iflytop/profilometer/MainActivity.java
  2. 31
      app/src/main/java/com/iflytop/profilometer/api/ble/BleApi.java
  3. 15
      app/src/main/java/com/iflytop/profilometer/api/ws/BleWebsocketManager.java
  4. 58
      app/src/main/java/com/iflytop/profilometer/api/ws/DeviceStateWebsocketManager.java
  5. 37
      app/src/main/java/com/iflytop/profilometer/core/bluetooth/BleDeviceListener.java
  6. 11
      app/src/main/java/com/iflytop/profilometer/core/bluetooth/BleDeviceOnReportListener.java
  7. 10
      app/src/main/java/com/iflytop/profilometer/core/bluetooth/BleManager.java
  8. 29
      app/src/main/java/com/iflytop/profilometer/core/migration/channel/BleDeviceUartChannel.java
  9. 77
      app/src/main/java/com/iflytop/profilometer/core/system/DeviceState.java
  10. 5
      app/src/main/java/com/iflytop/profilometer/core/system/SystemState.java

8
app/src/main/java/com/iflytop/profilometer/MainActivity.java

@ -12,10 +12,14 @@ import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import com.iflytop.profilometer.api.ws.BleWebsocketManager;
import com.iflytop.profilometer.api.ws.DeviceStateWebsocketManager;
import com.iflytop.profilometer.core.bluetooth.BleManager;
import com.iflytop.profilometer.server.HttpServer;
public class MainActivity extends AppCompatActivity {
private BleManager bleManager;
@SuppressLint({"SetJavaScriptEnabled", "MissingInflatedId"})
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -41,7 +45,7 @@ public class MainActivity extends AppCompatActivity {
webView.getSettings().setUseWideViewPort(true);
webView.loadUrl("http://127.0.0.1:8080/");
BleManager bleManager = BleManager.getInstance(this);
bleManager = BleManager.getInstance(this);
// 针对 Android 12 及以上版本请求必要的运行时权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
bleManager.checkAndRequestPermissions(this);
@ -56,6 +60,6 @@ public class MainActivity extends AppCompatActivity {
super.onDestroy();
// Activity 销毁时停止服务器
HttpServer.stop();
BleManager.getInstance(this).stopScan();
bleManager.stopScan();
}
}

31
app/src/main/java/com/iflytop/profilometer/api/ble/BleApi.java

@ -3,10 +3,12 @@ package com.iflytop.profilometer.api.ble;
import android.content.Context;
import android.util.Log;
import com.iflytop.profilometer.api.ws.BleWebsocketManager;
import com.iflytop.profilometer.api.ws.DeviceStateWebsocketManager;
import com.iflytop.profilometer.common.result.Result;
import com.iflytop.profilometer.core.bluetooth.BleDeviceListener;
import com.iflytop.profilometer.core.bluetooth.BleManager;
import com.iflytop.profilometer.core.migration.driver.BleDeviceUartChannel;
import com.iflytop.profilometer.core.migration.type.protocol.TPMIBasicReport;
import com.iflytop.profilometer.core.migration.channel.BleDeviceUartChannel;
/**
* 蓝牙接口
@ -24,8 +26,8 @@ public class BleApi {
*/
public String start() {
try {
BleManager.getInstance(context).startScan();
BleWebsocketManager.getInstance(context).startWsPush();
BleManager.getInstance().startScan();
BleWebsocketManager.getInstance().startWsPush();
return Result.success();
} catch (Exception e) {
Log.e(TAG, "开始获取蓝牙列表失败", e);
@ -38,8 +40,8 @@ public class BleApi {
*/
public String stop() {
try {
BleManager.getInstance(context).stopScan();
BleWebsocketManager.getInstance(context).stopWsPush();
BleManager.getInstance().stopScan();
BleWebsocketManager.getInstance().stopWsPush();
return Result.success();
} catch (Exception e) {
Log.e(TAG, "结束获取蓝牙设备列表失败", e);
@ -52,19 +54,8 @@ public class BleApi {
*/
public String connect(String mac) {
try {
BleManager.getInstance(context).connectToDevice(mac);
BleDeviceUartChannel uartChannel = new BleDeviceUartChannel();
uartChannel.init();
uartChannel.setOnReportListener(packet -> {
if (packet instanceof TPMIBasicReport basic) {
Log.d("BLE", "温度: " + basic.getTemperature());
Log.d("BLE", "倾角X: " + basic.getInclinatorX());
Log.d("BLE", "倾角Y: " + basic.getInclinatorY());
Log.d("BLE", "电量: " + basic.getPower());
}
});
BleManager.getInstance().connectToDevice(mac);
DeviceStateWebsocketManager.getInstance().startWsPush();
return Result.success();
} catch (Exception e) {
Log.e(TAG, "链接蓝牙设备失败", e);
@ -77,7 +68,7 @@ public class BleApi {
*/
public String disconnect() {
try {
BleManager.getInstance(context).disconnect();
BleManager.getInstance().disconnect();
return Result.success();
} catch (Exception e) {
Log.e(TAG, "断开蓝牙设备链接失败", e);

15
app/src/main/java/com/iflytop/profilometer/api/ble/BleWebsocketManager.java → app/src/main/java/com/iflytop/profilometer/api/ws/BleWebsocketManager.java

@ -1,4 +1,4 @@
package com.iflytop.profilometer.api.ble;
package com.iflytop.profilometer.api.ws;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothDevice;
@ -21,19 +21,18 @@ public class BleWebsocketManager {
private static BleWebsocketManager instance;
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
private ScheduledFuture<?> scheduledTask;
private final Context context;
private BleWebsocketManager(Context context) {
this.context = context.getApplicationContext();
private BleWebsocketManager() {
}
public static synchronized BleWebsocketManager getInstance(Context context) {
public static synchronized BleWebsocketManager getInstance() {
if (instance == null) {
instance = new BleWebsocketManager(context);
instance = new BleWebsocketManager();
}
return instance;
}
/**
* 开始定时任务
*/
@ -41,14 +40,14 @@ public class BleWebsocketManager {
public void startWsPush() {
stopWsPush();
scheduledTask = scheduler.scheduleWithFixedDelay(() -> {
List<BluetoothDevice> scannedDevices = BleManager.getInstance(context).getScannedDevices();
List<BluetoothDevice> scannedDevices = BleManager.getInstance().getScannedDevices();
scannedDevices.sort(Comparator.comparing(BluetoothDevice::getAddress));
List<String> bleList = new ArrayList<>();
for (BluetoothDevice bluetoothDevice : scannedDevices) {
bleList.add(bluetoothDevice.getName() + "_" + bluetoothDevice.getAddress());
}
WebSocketManager.send(JSONUtil.toJsonStr(bleList));
}, 2, 120, TimeUnit.SECONDS);
}, 0, 2000, TimeUnit.MILLISECONDS);
}
/**

58
app/src/main/java/com/iflytop/profilometer/api/ws/DeviceStateWebsocketManager.java

@ -0,0 +1,58 @@
package com.iflytop.profilometer.api.ws;
import android.annotation.SuppressLint;
import android.content.Context;
import com.iflytop.profilometer.core.system.DeviceState;
import com.iflytop.profilometer.core.system.SystemState;
import com.iflytop.profilometer.core.websocket.WebSocketManager;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import cn.hutool.json.JSONUtil;
public class DeviceStateWebsocketManager {
private static DeviceStateWebsocketManager instance;
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
private ScheduledFuture<?> scheduledTask;
private DeviceStateWebsocketManager() {
}
public static synchronized DeviceStateWebsocketManager getInstance() {
if (instance == null) {
instance = new DeviceStateWebsocketManager();
}
return instance;
}
/**
* 开始定时任务
*/
@SuppressLint("MissingPermission")
public void startWsPush() {
stopWsPush();
scheduledTask = scheduler.scheduleWithFixedDelay(() -> {
DeviceState deviceState = SystemState.getInstance().getDeviceState();
Map<String, Object> map = new HashMap<>();
map.put("type", "peripheral-status");
map.put("data", deviceState);
WebSocketManager.send(JSONUtil.toJsonStr(map));
}, 0, 1000, TimeUnit.MILLISECONDS);
}
/**
* 结束定时任务
*/
public void stopWsPush() {
if (scheduledTask != null && !scheduledTask.isCancelled()) {
scheduledTask.cancel(false);
}
}
}

37
app/src/main/java/com/iflytop/profilometer/core/bluetooth/BleDeviceListener.java

@ -0,0 +1,37 @@
package com.iflytop.profilometer.core.bluetooth;
import android.util.Log;
import com.iflytop.profilometer.core.migration.type.protocol.TPMIBasicReport;
import com.iflytop.profilometer.core.migration.type.protocol.TPMIPacket;
import com.iflytop.profilometer.core.migration.type.protocol.TPMIPosReport;
import com.iflytop.profilometer.core.system.DeviceState;
import com.iflytop.profilometer.core.system.SystemState;
public class BleDeviceListener implements BleDeviceOnReportListener {
private static final String TAG = "MyBleDeviceListener";
@Override
public void onBasicReport(TPMIBasicReport report) {
Log.i(TAG, "基础上报包:" + report);
DeviceState deviceState = SystemState.getInstance().getDeviceState();
deviceState.setTemperature(report.getTemperature());
deviceState.setInclinatorX(report.getInclinatorX());
deviceState.setInclinatorY(report.getInclinatorY());
deviceState.setPower(report.getPower());
deviceState.setFlag(report.getFlag());
deviceState.setState(report.getState());
}
@Override
public void onPosReport(TPMIPosReport report) {
Log.i(TAG, "位置信息上报:");
Log.i(TAG, "ARM0角度 " + report.getArm1Angle());
Log.i(TAG, "ARM1角度" + report.getArm2Angle());
}
@Override
public void onUnknownReport(TPMIPacket raw) {
Log.w(TAG, "收到未知类型数据包: CMD=" + raw.getCommand() + " LEN=" + raw.getPacketLen());
}
}

11
app/src/main/java/com/iflytop/profilometer/core/bluetooth/BleDeviceOnReportListener.java

@ -0,0 +1,11 @@
package com.iflytop.profilometer.core.bluetooth;
import com.iflytop.profilometer.core.migration.type.protocol.TPMIBasicReport;
import com.iflytop.profilometer.core.migration.type.protocol.TPMIPacket;
import com.iflytop.profilometer.core.migration.type.protocol.TPMIPosReport;
public interface BleDeviceOnReportListener {
default void onBasicReport(TPMIBasicReport report) {}
default void onPosReport(TPMIPosReport report) {}
default void onUnknownReport(TPMIPacket raw) {}
}

10
app/src/main/java/com/iflytop/profilometer/core/bluetooth/BleManager.java

@ -27,6 +27,8 @@ import androidx.annotation.RequiresApi;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import com.iflytop.profilometer.core.migration.channel.BleDeviceUartChannel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@ -189,6 +191,9 @@ public class BleManager {
}
return instance;
}
public static synchronized BleManager getInstance() {
return instance;
}
/**
* 检查指定权限是否已授予
@ -345,6 +350,11 @@ public class BleManager {
try {
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(macAddress);
bluetoothGatt = device.connectGatt(context, false, gattCallback);
BleDeviceUartChannel channel = new BleDeviceUartChannel();
channel.init();
channel.setDeviceOnReportListener(new BleDeviceListener());
} catch (IllegalArgumentException e) {
Log.e(TAG, "无效的 MAC 地址: " + macAddress, e);
}

29
app/src/main/java/com/iflytop/profilometer/core/migration/driver/BleDeviceUartChannel.java → app/src/main/java/com/iflytop/profilometer/core/migration/channel/BleDeviceUartChannel.java

@ -1,10 +1,13 @@
package com.iflytop.profilometer.core.migration.driver;
package com.iflytop.profilometer.core.migration.channel;
import android.util.Log;
import com.iflytop.profilometer.core.bluetooth.BleDeviceOnReportListener;
import com.iflytop.profilometer.core.bluetooth.BleManager;
import com.iflytop.profilometer.core.migration.factory.TPMIPacketFactory;
import com.iflytop.profilometer.core.migration.type.protocol.TPMIBasicReport;
import com.iflytop.profilometer.core.migration.type.protocol.TPMIPacket;
import com.iflytop.profilometer.core.migration.type.protocol.TPMIPosReport;
import java.util.Arrays;
@ -15,19 +18,24 @@ public class BleDeviceUartChannel {
}
private OnBleReportListener reportListener;
private BleDeviceOnReportListener deviceOnReportListener;
private final byte[] buffer = new byte[1024];
private int bufferLen = 0;
public void init() {
BleManager.getInstance(null).setBleDataListener(this::handleReceivedData);
BleManager.getInstance().setBleDataListener(this::handleReceivedData);
}
public void setOnReportListener(OnBleReportListener listener) {
this.reportListener = listener;
}
public void setDeviceOnReportListener(BleDeviceOnReportListener listener) {
this.deviceOnReportListener = listener;
}
public void sendCommand(byte[] command) {
BleManager.getInstance(null).sendMessage(new String(command));
BleManager.getInstance().sendMessage(new String(command));
}
private void handleReceivedData(byte[] data) {
@ -49,6 +57,9 @@ public class BleDeviceUartChannel {
if (reportListener != null) {
reportListener.onReportReceived(report.packet);
}
if (deviceOnReportListener != null) {
dispatchTypedPacket(report.packet);
}
offset += report.packet.getPacketLen();
} else if (report.result.equals(TPMIPacketFactory.PacketAnalysisResult.CHECKSUM_ERROR)) {
Log.w("BLE", "BLE数据包校验失败,跳过 1 字节");
@ -66,4 +77,14 @@ public class BleDeviceUartChannel {
bufferLen -= offset;
}
}
}
private void dispatchTypedPacket(TPMIPacket packet) {
if (packet instanceof TPMIBasicReport) {
deviceOnReportListener.onBasicReport((TPMIBasicReport) packet);
} else if (packet instanceof TPMIPosReport) {
deviceOnReportListener.onPosReport((TPMIPosReport) packet);
} else {
deviceOnReportListener.onUnknownReport(packet);
}
}
}

77
app/src/main/java/com/iflytop/profilometer/core/system/DeviceState.java

@ -0,0 +1,77 @@
package com.iflytop.profilometer.core.system;
public class DeviceState {
private Boolean isConnected;
private Integer power;
private Integer state;
private Integer flag;
private Double inclinatorX;
private Double inclinatorY;
private Double temperature;
public DeviceState() {
isConnected = false;
power = 0;
state = 0;
flag = 0;
inclinatorX = 0.0;
inclinatorY = 0.0;
temperature = 0.0;
}
public Boolean getConnected() {
return isConnected;
}
public void setConnected(Boolean connected) {
isConnected = connected;
}
public Integer getPower() {
return power;
}
public void setPower(Integer power) {
this.power = power;
}
public Integer getState() {
return state;
}
public void setState(Integer state) {
this.state = state;
}
public Integer getFlag() {
return flag;
}
public void setFlag(Integer flag) {
this.flag = flag;
}
public Double getInclinatorX() {
return inclinatorX;
}
public void setInclinatorX(Double inclinatorX) {
this.inclinatorX = inclinatorX;
}
public Double getInclinatorY() {
return inclinatorY;
}
public void setInclinatorY(Double inclinatorY) {
this.inclinatorY = inclinatorY;
}
public Double getTemperature() {
return temperature;
}
public void setTemperature(Double temperature) {
this.temperature = temperature;
}
}

5
app/src/main/java/com/iflytop/profilometer/core/system/SystemState.java

@ -6,6 +6,7 @@ import com.iflytop.profilometer.model.entity.AppUser;
* 全局系统状态
*/
public class SystemState {
private final DeviceState deviceState = new DeviceState();
private SystemState() {
}
@ -28,4 +29,8 @@ public class SystemState {
public synchronized void setCurrentUser(AppUser currentUser) {
this.currentUser = currentUser;
}
public DeviceState getDeviceState() {
return deviceState;
}
}
Loading…
Cancel
Save