增加心率回调
This commit is contained in:
parent
dd06e16646
commit
09ff19795a
199
README.md
199
README.md
@ -1,146 +1,83 @@
|
|||||||
# ASR5515串口通信Android应用
|
# ASR5515 Android 串口通信应用
|
||||||
|
|
||||||
## 项目概述
|
## 项目概述
|
||||||
这是一个用于与ASR5515设备进行串口通信的Android应用,提供设备管理、状态监控、固件升级等功能。应用通过串口(/dev/ttyS3)与设备通信,波特率115200。
|
这是一个基于 Android 平台的串口通信应用,主要用于与 ASR5515 设备进行通信。该应用实现了完整的串口通信协议,支持设备管理、数据采集、状态监控等功能。
|
||||||
|
|
||||||
## 主要功能
|
## 主要功能
|
||||||
- 设备检查与状态监控
|
1. 串口通信
|
||||||
- 设备重启
|
- 基于 Android SerialPort API 的串口通信实现
|
||||||
- 日志控制
|
- 支持自定义波特率和串口配置
|
||||||
- 蓝牙版本查询
|
- 数据帧封装和解析
|
||||||
- 蓝牙固件升级
|
|
||||||
- 主机状态同步
|
|
||||||
- 心率血压血氧(HR/BP/BO)测量
|
|
||||||
- 自动测量
|
|
||||||
- 手动测量
|
|
||||||
- 动态测量功能
|
|
||||||
- Boot bin检查
|
|
||||||
- 采集频率设置
|
|
||||||
- 支持模拟模式(不实际连接硬件)
|
|
||||||
|
|
||||||
## 项目结构
|
2. 设备管理
|
||||||
```
|
- 设备检测和状态查询
|
||||||
com.ismart.ib86
|
- 设备重启控制
|
||||||
├── app/ # 主应用相关
|
- 固件版本管理
|
||||||
│ └── MainActivity.java
|
- 蓝牙模块管理
|
||||||
├── common/ # 公共组件
|
|
||||||
│ └── utils/ # 工具类
|
3. 数据采集
|
||||||
└── feature/ # 功能模块
|
- 心率、血压、血氧自动测量
|
||||||
└── serial/ # 串口通信实现
|
- 手动测量模式支持
|
||||||
├── ASR5515DeviceManager.java
|
- 动态测量功能
|
||||||
├── ASR5515Protocol.java
|
- 可配置的数据采集频率
|
||||||
└── SerialPortHelper.java
|
|
||||||
|
4. 状态监控
|
||||||
|
- 设备佩戴检测
|
||||||
|
- 主机状态同步
|
||||||
|
- 日志控制功能
|
||||||
|
|
||||||
|
## 技术架构
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
A[Android App] --> B[串口通信层]
|
||||||
|
B --> C[协议解析层]
|
||||||
|
C --> D[设备管理]
|
||||||
|
C --> E[数据采集]
|
||||||
|
C --> F[状态监控]
|
||||||
|
|
||||||
|
B --> |SerialPortHelper| G[串口读写]
|
||||||
|
C --> |ASR5515Protocol| H[协议实现]
|
||||||
|
D --> |DeviceManager| I[设备控制]
|
||||||
```
|
```
|
||||||
|
|
||||||
## 核心类说明
|
## 核心模块
|
||||||
|
|
||||||
### 1. ASR5515Protocol
|
1. **SerialPortHelper**
|
||||||
协议核心类,定义ASR5515设备的通信协议格式和命令。
|
- 串口通信的核心类
|
||||||
|
- 实现数据的发送和接收
|
||||||
|
- 管理通信线程和数据队列
|
||||||
|
|
||||||
**主要功能:**
|
2. **ASR5515Protocol**
|
||||||
- 定义设备信息结构(DeviceInfo)
|
- 实现 ASR5515 设备通信协议
|
||||||
- 定义各种命令(Commands)
|
- 定义命令集和数据格式
|
||||||
- 定义帧结构(Frame)
|
- 处理数据帧的封装和解析
|
||||||
- 提供各种请求和响应的创建与解析方法
|
|
||||||
|
|
||||||
### 2. SerialPortHelper
|
3. **设备管理模块**
|
||||||
串口通信核心实现类,封装了与ASR5515设备的通信逻辑。
|
- 设备信息查询
|
||||||
|
- 设备控制命令
|
||||||
|
- 固件升级支持
|
||||||
|
|
||||||
**主要功能:**
|
## 通信协议
|
||||||
- 串口初始化和管理
|
- 帧格式:`[命令字(2字节) + 序列号(2字节) + 长度(2字节) + 数据 + ]`
|
||||||
- 数据发送和接收
|
- 支持的命令类型:
|
||||||
- ASR5515协议命令的封装
|
- 设备检查 (0x0065/0x0066)
|
||||||
- 回调机制处理各种响应
|
- 设备重启 (0x0067/0x0068)
|
||||||
- 支持模拟模式
|
- 状态同步 (0x0079/0x007A)
|
||||||
|
- 数据采集 (0x00C9-0x00D0)
|
||||||
|
- 佩戴检测 (0x0105/0x0106)
|
||||||
|
|
||||||
### 3. ASR5515DeviceManager
|
## 开发环境
|
||||||
设备管理核心类,提供高级设备管理接口。
|
- Android Studio
|
||||||
|
- Java
|
||||||
|
- Gradle 构建系统
|
||||||
|
|
||||||
**主要功能:**
|
## 依赖
|
||||||
- 设备状态检查
|
- Android SerialPort API
|
||||||
- 设备重启
|
- Android SDK
|
||||||
- 日志控制
|
|
||||||
- 蓝牙版本查询
|
|
||||||
- 蓝牙升级
|
|
||||||
- 主机状态同步
|
|
||||||
|
|
||||||
### 4. MainActivity
|
|
||||||
应用主界面,提供用户交互界面。
|
|
||||||
|
|
||||||
## 使用说明
|
## 使用说明
|
||||||
|
1. 配置串口参数(波特率、设备路径)
|
||||||
### 初始化串口
|
2. 初始化 SerialPortHelper
|
||||||
```java
|
3. 实现必要的回调接口
|
||||||
SerialPortHelper serialPortHelper = new SerialPortHelper("/dev/ttyS1", 115200);
|
4. 使用设备管理和数据采集功能
|
||||||
serialPortHelper.setDeviceStatusCallback(new DeviceStatusCallback() {
|
|
||||||
@Override
|
|
||||||
public void onDeviceCheckResponse(DeviceInfo deviceInfo) {
|
|
||||||
// 处理设备检查响应
|
|
||||||
}
|
|
||||||
|
|
||||||
// 实现其他回调方法...
|
|
||||||
});
|
|
||||||
serialPortHelper.open();
|
|
||||||
```
|
|
||||||
|
|
||||||
### 发送命令
|
|
||||||
```java
|
|
||||||
// 设备检查
|
|
||||||
serialPortHelper.checkDevice();
|
|
||||||
|
|
||||||
// 设备重启
|
|
||||||
serialPortHelper.restartDevice();
|
|
||||||
|
|
||||||
// 查询蓝牙版本
|
|
||||||
serialPortHelper.queryBtVersion();
|
|
||||||
|
|
||||||
// 蓝牙升级
|
|
||||||
serialPortHelper.upgradeBt();
|
|
||||||
```
|
|
||||||
|
|
||||||
### 关闭串口
|
|
||||||
```java
|
|
||||||
serialPortHelper.close();
|
|
||||||
```
|
|
||||||
|
|
||||||
## 开发环境要求
|
|
||||||
- Android Studio 最新稳定版
|
|
||||||
- Android SDK API 21+
|
|
||||||
- JDK 8+
|
|
||||||
- 支持串口的Android设备或模拟器
|
|
||||||
|
|
||||||
## 硬件连接指南
|
|
||||||
1. 确保ASR5515设备已正确供电
|
|
||||||
2. 使用USB转串口线连接设备与Android主机
|
|
||||||
3. 确认串口设备节点(通常为/dev/ttyS3)
|
|
||||||
4. 设置波特率为115200
|
|
||||||
|
|
||||||
## 构建与运行
|
|
||||||
1. 克隆项目
|
|
||||||
```bash
|
|
||||||
git clone https://github.com/ismart/ib86.git
|
|
||||||
```
|
|
||||||
2. 导入Android Studio
|
|
||||||
3. 配置设备连接参数(在MainActivity中修改)
|
|
||||||
4. 构建并运行应用
|
|
||||||
|
|
||||||
## 测试方法
|
|
||||||
1. 单元测试
|
|
||||||
```bash
|
|
||||||
./gradlew test
|
|
||||||
```
|
|
||||||
2. 功能测试
|
|
||||||
- 使用模拟模式测试基本功能
|
|
||||||
- 连接实际设备测试通信功能
|
|
||||||
- 测试各种测量功能(HR/BP/BO)
|
|
||||||
|
|
||||||
## 依赖项
|
|
||||||
- Android SerialPort API
|
|
||||||
- ASR5515通信协议(参考ASR-5515通信协议.docx)
|
|
||||||
|
|
||||||
## 注意事项
|
|
||||||
1. 需要设备支持串口通信
|
|
||||||
2. 需要正确配置串口名称和波特率
|
|
||||||
3. 模拟模式可用于开发测试
|
|
||||||
4. 实际使用时请参考ASR5515设备的具体通信协议
|
|
||||||
5. 测量功能需要ASR5515设备支持相应传感器
|
|
@ -166,6 +166,20 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
deviceManager.setWearDetectionListener(response ->
|
deviceManager.setWearDetectionListener(response ->
|
||||||
LogManager.d(TAG, "佩戴检测: " + response.isWearing)
|
LogManager.d(TAG, "佩戴检测: " + response.isWearing)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 设置算法结果回调
|
||||||
|
deviceManager.setAlgoResultListener(new ASR5515DeviceManager.AlgoResultListener() {
|
||||||
|
@Override
|
||||||
|
public void onAlgoResultReceived(ASR5515Protocol.AlgoResultResponse response) {
|
||||||
|
LogManager.d(TAG, "算法结果: " + response.toString());
|
||||||
|
// 在这里处理心率结果
|
||||||
|
if (response.heartRate > 0) {
|
||||||
|
LogManager.d(TAG, "心率值: " + response.heartRate);
|
||||||
|
// 可以在这里更新UI或进行其他操作
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startProtocolTests() {
|
private void startProtocolTests() {
|
||||||
@ -184,11 +198,11 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
// deviceManager.queryBtVersion();
|
// deviceManager.queryBtVersion();
|
||||||
// }
|
// }
|
||||||
// }, 2000);
|
// }, 2000);
|
||||||
|
deviceManager.stopGH3220Measure((byte) 0x02);
|
||||||
handler.postDelayed(new Runnable() {
|
handler.postDelayed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
deviceManager.sendWearDetectionRequest();
|
deviceManager.startGH3220Measure((byte) 0x02);
|
||||||
}
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
@ -207,10 +221,10 @@ protected void onDestroy() {
|
|||||||
|
|
||||||
// 移至后台线程执行耗时操作,避免ANR
|
// 移至后台线程执行耗时操作,避免ANR
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
if (deviceManager != null) {
|
// if (deviceManager != null) {
|
||||||
deviceManager.syncHostStatus(false);
|
// deviceManager.syncHostStatus(false);
|
||||||
deviceManager.close();
|
// deviceManager.close();
|
||||||
}
|
// }
|
||||||
|
|
||||||
// 释放GPIO测试资源
|
// 释放GPIO测试资源
|
||||||
if (gpioTest != null) {
|
if (gpioTest != null) {
|
||||||
|
@ -31,6 +31,8 @@ public class ASR5515DeviceManager {
|
|||||||
private HrBpBoManualMeasureListener hrBpBoManualMeasureListener;
|
private HrBpBoManualMeasureListener hrBpBoManualMeasureListener;
|
||||||
private DynamicMeasureListener dynamicMeasureListener;
|
private DynamicMeasureListener dynamicMeasureListener;
|
||||||
private WearDetectionListener wearDetectionListener;
|
private WearDetectionListener wearDetectionListener;
|
||||||
|
private GH3220MeasureListener gh3220MeasureListener;
|
||||||
|
private AlgoResultListener algoResultListener;
|
||||||
|
|
||||||
// 细分回调接口
|
// 细分回调接口
|
||||||
public interface DeviceCheckListener {
|
public interface DeviceCheckListener {
|
||||||
@ -81,6 +83,22 @@ public class ASR5515DeviceManager {
|
|||||||
void onWearDetectionResponse(ASR5515Protocol.WearDetectionResponse response);
|
void onWearDetectionResponse(ASR5515Protocol.WearDetectionResponse response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 算法结果监听器
|
||||||
|
*/
|
||||||
|
public interface AlgoResultListener {
|
||||||
|
/**
|
||||||
|
* 接收到心率算法结果
|
||||||
|
* @param response 心率结果响应
|
||||||
|
*/
|
||||||
|
void onAlgoResultReceived(ASR5515Protocol.AlgoResultResponse response);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface GH3220MeasureListener {
|
||||||
|
void onGH3220MeasureStartResponse(ASR5515Protocol.GH3220MeasureResponse response);
|
||||||
|
void onGH3220MeasureStopResponse(ASR5515Protocol.GH3220MeasureResponse response);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造函数
|
* 构造函数
|
||||||
* @param context 上下文
|
* @param context 上下文
|
||||||
@ -206,6 +224,31 @@ public class ASR5515DeviceManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
serialPortHelper.setGH3220MeasureCallback(new SerialPortHelper.GH3220MeasureCallback() {
|
||||||
|
@Override
|
||||||
|
public void onGH3220MeasureStartResponse(ASR5515Protocol.GH3220MeasureResponse response) {
|
||||||
|
if (gh3220MeasureListener != null) {
|
||||||
|
mainHandler.post(() -> gh3220MeasureListener.onGH3220MeasureStartResponse(response));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onGH3220MeasureStopResponse(ASR5515Protocol.GH3220MeasureResponse response) {
|
||||||
|
if (gh3220MeasureListener != null) {
|
||||||
|
mainHandler.post(() -> gh3220MeasureListener.onGH3220MeasureStopResponse(response));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
serialPortHelper.setAlgoResultCallback(new SerialPortHelper.AlgoResultCallback() {
|
||||||
|
@Override
|
||||||
|
public void onAlgoResultReceived(final ASR5515Protocol.AlgoResultResponse response) {
|
||||||
|
if (algoResultListener != null) {
|
||||||
|
mainHandler.post(() -> algoResultListener.onAlgoResultReceived(response));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -275,6 +318,17 @@ public class ASR5515DeviceManager {
|
|||||||
this.wearDetectionListener = listener;
|
this.wearDetectionListener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setGH3220MeasureListener(GH3220MeasureListener listener) {
|
||||||
|
this.gh3220MeasureListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置算法结果监听器
|
||||||
|
*/
|
||||||
|
public void setAlgoResultListener(AlgoResultListener listener) {
|
||||||
|
this.algoResultListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置Boot Bin检查监听器
|
* 设置Boot Bin检查监听器
|
||||||
*/
|
*/
|
||||||
@ -396,6 +450,24 @@ public class ASR5515DeviceManager {
|
|||||||
serialPortHelper.sendWearDetectionRequest();
|
serialPortHelper.sendWearDetectionRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送GH3220开启测量请求
|
||||||
|
* @param type 测量类型,参考ASR5515Protocol.GH3220MeasureType
|
||||||
|
*/
|
||||||
|
public void startGH3220Measure(byte type) {
|
||||||
|
wakeupDevice();
|
||||||
|
serialPortHelper.startGH3220Measure(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送GH3220停止测量请求
|
||||||
|
* @param type 测量类型,参考ASR5515Protocol.GH3220MeasureType
|
||||||
|
*/
|
||||||
|
public void stopGH3220Measure(byte type) {
|
||||||
|
wakeupDevice();
|
||||||
|
serialPortHelper.stopGH3220Measure(type);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 唤醒设备
|
* 唤醒设备
|
||||||
* 通过GPIO33唤醒蓝牙,ASR休眠时会自动发送'w'字符
|
* 通过GPIO33唤醒蓝牙,ASR休眠时会自动发送'w'字符
|
||||||
|
@ -212,6 +212,11 @@ public class ASR5515Protocol {
|
|||||||
public static final short CMD_DYNAMIC_MEASURE_RESP = 0x00D0; // 动态测量响应 [208 sn 0]
|
public static final short CMD_DYNAMIC_MEASURE_RESP = 0x00D0; // 动态测量响应 [208 sn 0]
|
||||||
public static final short CMD_WEAR_DETECTION = 0x0105; // 佩戴检测查询 [261 0 0]
|
public static final short CMD_WEAR_DETECTION = 0x0105; // 佩戴检测查询 [261 0 0]
|
||||||
public static final short CMD_WEAR_DETECTION_RESP = 0x0106; // 佩戴检测响应 [262 sn len 0/1]
|
public static final short CMD_WEAR_DETECTION_RESP = 0x0106; // 佩戴检测响应 [262 sn len 0/1]
|
||||||
|
public static final short CMD_GH3220_MEASURE_START = 0x01F5; // GH3220开启测量 [501 0 len type]
|
||||||
|
public static final short CMD_GH3220_MEASURE_START_RESP = 0x01F6; // GH3220开启测量响应 [502 sn len status]
|
||||||
|
public static final short CMD_GH3220_MEASURE_STOP = 0x01F7; // GH3220停止测量 [503 0 len type]
|
||||||
|
public static final short CMD_GH3220_MEASURE_STOP_RESP = 0x01F8; // GH3220停止测量响应 [504 sn len status]
|
||||||
|
public static final short CMD_ALGO_RESULT = 0x01FE; // 主动上报算法结果(心率) [510 sn len AlgoResult]
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Frame {
|
public static class Frame {
|
||||||
@ -296,12 +301,12 @@ public class ASR5515Protocol {
|
|||||||
|
|
||||||
// 提取数据部分(如果有的话)
|
// 提取数据部分(如果有的话)
|
||||||
int dataLength = endIndex - (startIndex + 7); // 7 = head(1) + type(2) + sn(2) + len(2)
|
int dataLength = endIndex - (startIndex + 7); // 7 = head(1) + type(2) + sn(2) + len(2)
|
||||||
//LogManager.d(TAG, "len: "+ len + " dataLength: " + dataLength + " end data" + data[endIndex]);
|
LogManager.d(TAG, "len: "+ len + " dataLength: " + dataLength + " end data" + data[endIndex]);
|
||||||
byte[] frameData;
|
byte[] frameData;
|
||||||
if (dataLength > 0) {
|
if (dataLength > 0) {
|
||||||
frameData = new byte[dataLength];
|
frameData = new byte[dataLength];
|
||||||
System.arraycopy(data, startIndex + 7, frameData, 0, dataLength);
|
System.arraycopy(data, startIndex + 7, frameData, 0, dataLength);
|
||||||
// LogManager.d(TAG,"data :"+ bytesToHexString(frameData));
|
LogManager.d(TAG,"data :"+ bytesToHexString(frameData));
|
||||||
} else {
|
} else {
|
||||||
frameData = new byte[0];
|
frameData = new byte[0];
|
||||||
}
|
}
|
||||||
@ -645,4 +650,115 @@ public class ASR5515Protocol {
|
|||||||
boolean isWearing = frame.data[0] == 1;
|
boolean isWearing = frame.data[0] == 1;
|
||||||
return new WearDetectionResponse(isWearing);
|
return new WearDetectionResponse(isWearing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GH3220测量类型常量
|
||||||
|
public static class GH3220MeasureType {
|
||||||
|
public static final byte ADT = 0x01; // ADT
|
||||||
|
public static final byte HR = 0x02; // 心率
|
||||||
|
public static final byte LEAD = 0x03; // LEAD
|
||||||
|
public static final byte SPO2 = 0x40; // 血氧
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建GH3220开启测量请求帧 [501 0 len type]
|
||||||
|
public static byte[] createGH3220MeasureStartRequest(byte type) {
|
||||||
|
byte[] data = new byte[1];
|
||||||
|
data[0] = type; // 测量类型
|
||||||
|
return createFrame(Commands.CMD_GH3220_MEASURE_START, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建GH3220停止测量请求帧 [503 0 len type]
|
||||||
|
public static byte[] createGH3220MeasureStopRequest(byte type) {
|
||||||
|
byte[] data = new byte[1];
|
||||||
|
data[0] = type; // 测量类型
|
||||||
|
return createFrame(Commands.CMD_GH3220_MEASURE_STOP, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// GH3220测量响应类
|
||||||
|
public static class GH3220MeasureResponse {
|
||||||
|
public byte sn;
|
||||||
|
public byte len;
|
||||||
|
public byte status;
|
||||||
|
|
||||||
|
public GH3220MeasureResponse(byte sn, byte len, byte status) {
|
||||||
|
this.sn = sn;
|
||||||
|
this.len = len;
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "GH3220MeasureResponse{" +
|
||||||
|
"sn=" + sn +
|
||||||
|
", len=" + len +
|
||||||
|
", status=" + status +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析GH3220开启测量响应帧 [502 sn len status]
|
||||||
|
public static GH3220MeasureResponse parseGH3220MeasureStartResponse(Frame frame) {
|
||||||
|
if (frame == null || frame.command != Commands.CMD_GH3220_MEASURE_START_RESP || frame.data.length < 3) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new GH3220MeasureResponse(frame.data[0], frame.data[1], frame.data[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析GH3220停止测量响应帧 [504 sn len status]
|
||||||
|
public static GH3220MeasureResponse parseGH3220MeasureStopResponse(Frame frame) {
|
||||||
|
if (frame == null || frame.command != Commands.CMD_GH3220_MEASURE_STOP_RESP || frame.data.length < 3) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new GH3220MeasureResponse(frame.data[0], frame.data[1], frame.data[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 算法结果响应类 [510 sn len AlgoResult]
|
||||||
|
public static class AlgoResultResponse {
|
||||||
|
public int heartRate; // 心率值 (snResult[0])
|
||||||
|
public int confidence; // 置信度 (snResult[1])
|
||||||
|
public int signalNoiseRatio; // 信噪比 (snResult[2])
|
||||||
|
|
||||||
|
public AlgoResultResponse(int heartRate, int confidence, int signalNoiseRatio) {
|
||||||
|
this.heartRate = heartRate;
|
||||||
|
this.confidence = confidence;
|
||||||
|
this.signalNoiseRatio = signalNoiseRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "AlgoResultResponse{" +
|
||||||
|
", heartRate=" + heartRate +
|
||||||
|
", confidence=" + confidence +
|
||||||
|
", signalNoiseRatio=" + signalNoiseRatio +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析算法结果响应帧 [updateFlag resultNum resultBit(2byte) heartRate(4) confidence(4) signalNoiseRatio(4)]
|
||||||
|
public static AlgoResultResponse parseAlgoResultResponse(Frame frame) {
|
||||||
|
if (frame == null || frame.command != Commands.CMD_ALGO_RESULT || frame.data.length < 4) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
LogManager.d(TAG," frame.data.length:"+ frame.data.length);
|
||||||
|
try {
|
||||||
|
// 解析心率值,只取第一个字节
|
||||||
|
int heartRate = frame.data[4];
|
||||||
|
|
||||||
|
int confidence = 0;
|
||||||
|
int signalNoiseRatio = 0;
|
||||||
|
|
||||||
|
// 如果数据长度足够,解析置信度,只取第一个字节
|
||||||
|
if (frame.data.length >= 8) {
|
||||||
|
confidence = frame.data[8];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果数据长度足够,解析信噪比,只取第一个字节
|
||||||
|
if (frame.data.length >= 16) {
|
||||||
|
signalNoiseRatio = frame.data[16];
|
||||||
|
}
|
||||||
|
return new AlgoResultResponse(heartRate, confidence, signalNoiseRatio);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogManager.e(TAG, "Parse algo result error: " + e.getMessage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -38,6 +38,8 @@ public class SerialPortHelper {
|
|||||||
private HrBpBoManualMeasureCallback hrBpBoManualMeasureCallback;
|
private HrBpBoManualMeasureCallback hrBpBoManualMeasureCallback;
|
||||||
private DynamicMeasureCallback dynamicMeasureCallback;
|
private DynamicMeasureCallback dynamicMeasureCallback;
|
||||||
private WearDetectionCallback wearDetectionCallback;
|
private WearDetectionCallback wearDetectionCallback;
|
||||||
|
private GH3220MeasureCallback gh3220MeasureCallback;
|
||||||
|
private AlgoResultCallback algoResultCallback;
|
||||||
private boolean isSimulationMode = false;
|
private boolean isSimulationMode = false;
|
||||||
private final ByteBuffer frameBuffer = ByteBuffer.allocate(1024);
|
private final ByteBuffer frameBuffer = ByteBuffer.allocate(1024);
|
||||||
|
|
||||||
@ -101,6 +103,22 @@ public class SerialPortHelper {
|
|||||||
void onWearDetectionResponse(ASR5515Protocol.WearDetectionResponse response);
|
void onWearDetectionResponse(ASR5515Protocol.WearDetectionResponse response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface GH3220MeasureCallback {
|
||||||
|
void onGH3220MeasureStartResponse(ASR5515Protocol.GH3220MeasureResponse response);
|
||||||
|
void onGH3220MeasureStopResponse(ASR5515Protocol.GH3220MeasureResponse response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 算法结果回调接口
|
||||||
|
*/
|
||||||
|
public interface AlgoResultCallback {
|
||||||
|
/**
|
||||||
|
* 接收到心率算法结果
|
||||||
|
* @param response 心率结果响应
|
||||||
|
*/
|
||||||
|
void onAlgoResultReceived(ASR5515Protocol.AlgoResultResponse response);
|
||||||
|
}
|
||||||
|
|
||||||
public SerialPortHelper(String portName, int baudRate) {
|
public SerialPortHelper(String portName, int baudRate) {
|
||||||
this.mPortName = portName;
|
this.mPortName = portName;
|
||||||
this.mBaudRate = baudRate;
|
this.mBaudRate = baudRate;
|
||||||
@ -168,6 +186,18 @@ public class SerialPortHelper {
|
|||||||
this.wearDetectionCallback = callback;
|
this.wearDetectionCallback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setGH3220MeasureCallback(GH3220MeasureCallback callback) {
|
||||||
|
this.gh3220MeasureCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置算法结果回调
|
||||||
|
* @param callback 算法结果回调
|
||||||
|
*/
|
||||||
|
public void setAlgoResultCallback(AlgoResultCallback callback) {
|
||||||
|
this.algoResultCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发送佩戴检测查询请求
|
* 发送佩戴检测查询请求
|
||||||
*/
|
*/
|
||||||
@ -256,6 +286,24 @@ public class SerialPortHelper {
|
|||||||
sendData(data, null);
|
sendData(data, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送GH3220开启测量请求
|
||||||
|
* @param type 测量类型,参考ASR5515Protocol.GH3220MeasureType
|
||||||
|
*/
|
||||||
|
public void startGH3220Measure(byte type) {
|
||||||
|
byte[] data = ASR5515Protocol.createGH3220MeasureStartRequest(type);
|
||||||
|
sendData(data, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送GH3220停止测量请求
|
||||||
|
* @param type 测量类型,参考ASR5515Protocol.GH3220MeasureType
|
||||||
|
*/
|
||||||
|
public void stopGH3220Measure(byte type) {
|
||||||
|
byte[] data = ASR5515Protocol.createGH3220MeasureStopRequest(type);
|
||||||
|
sendData(data, null);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean open() {
|
public boolean open() {
|
||||||
try {
|
try {
|
||||||
LogManager.d(TAG, "Opening serial port: " + mPortName + " with baud rate: " + mBaudRate);
|
LogManager.d(TAG, "Opening serial port: " + mPortName + " with baud rate: " + mBaudRate);
|
||||||
@ -371,7 +419,7 @@ public class SerialPortHelper {
|
|||||||
}
|
}
|
||||||
} else if (mSerialPort != null) {
|
} else if (mSerialPort != null) {
|
||||||
try {
|
try {
|
||||||
LogManager.d(TAG, "ASR->5515 DATA: " + Arrays.toString(data));
|
//LogManager.d(TAG, "ASR->5515 DATA: " + Arrays.toString(data));
|
||||||
LogManager.d(TAG, "ASR->5515 DATA: " + bytesToHexString(data));
|
LogManager.d(TAG, "ASR->5515 DATA: " + bytesToHexString(data));
|
||||||
mSerialPort.getOutputStream().write(data);
|
mSerialPort.getOutputStream().write(data);
|
||||||
if (sendCallback != null) {
|
if (sendCallback != null) {
|
||||||
@ -403,7 +451,7 @@ public class SerialPortHelper {
|
|||||||
int bytesRead = mSerialPort.getInputStream().read(buffer);
|
int bytesRead = mSerialPort.getInputStream().read(buffer);
|
||||||
if (bytesRead > 0) {
|
if (bytesRead > 0) {
|
||||||
byte[] receivedData = Arrays.copyOf(buffer, bytesRead);
|
byte[] receivedData = Arrays.copyOf(buffer, bytesRead);
|
||||||
LogManager.d(TAG, "5515->ASR DATA: " + Arrays.toString(receivedData));
|
//LogManager.d(TAG, "5515->ASR DATA: " + Arrays.toString(receivedData));
|
||||||
LogManager.d(TAG, "5515->ASR DATA: " + bytesToHexString(receivedData));
|
LogManager.d(TAG, "5515->ASR DATA: " + bytesToHexString(receivedData));
|
||||||
receiveQueue.put(receivedData);
|
receiveQueue.put(receivedData);
|
||||||
}
|
}
|
||||||
@ -586,6 +634,27 @@ public class SerialPortHelper {
|
|||||||
wearDetectionCallback.onWearDetectionResponse(wearDetectionResponse);
|
wearDetectionCallback.onWearDetectionResponse(wearDetectionResponse);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ASR5515Protocol.Commands.CMD_GH3220_MEASURE_START_RESP:
|
||||||
|
ASR5515Protocol.GH3220MeasureResponse gh3220StartResponse = ASR5515Protocol.parseGH3220MeasureStartResponse(frame);
|
||||||
|
if (gh3220StartResponse != null && gh3220MeasureCallback != null) {
|
||||||
|
gh3220MeasureCallback.onGH3220MeasureStartResponse(gh3220StartResponse);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ASR5515Protocol.Commands.CMD_GH3220_MEASURE_STOP_RESP:
|
||||||
|
ASR5515Protocol.GH3220MeasureResponse gh3220StopResponse = ASR5515Protocol.parseGH3220MeasureStopResponse(frame);
|
||||||
|
if (gh3220StopResponse != null && gh3220MeasureCallback != null) {
|
||||||
|
gh3220MeasureCallback.onGH3220MeasureStopResponse(gh3220StopResponse);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ASR5515Protocol.Commands.CMD_ALGO_RESULT:
|
||||||
|
ASR5515Protocol.AlgoResultResponse algoResultResponse = ASR5515Protocol.parseAlgoResultResponse(frame);
|
||||||
|
if (algoResultResponse != null && algoResultCallback != null) {
|
||||||
|
algoResultCallback.onAlgoResultReceived(algoResultResponse);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user