diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index 24ccfcd..94a25f7 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -2,6 +2,5 @@
-
\ No newline at end of file
diff --git a/app/src/main/cpp/src/data_praser.cpp b/app/src/main/cpp/src/data_praser.cpp
index 2b0f574..4aa4baf 100644
--- a/app/src/main/cpp/src/data_praser.cpp
+++ b/app/src/main/cpp/src/data_praser.cpp
@@ -565,22 +565,23 @@ std::vector parse_device_data(const std::vector& file_data)
return final_results;
}
-// CRC16校验函数 (Modbus CRC16)
+// CRC16校验函数 (CCITT CRC16)
uint16_t calculate_crc16(const uint8_t* data, size_t length) {
- uint16_t crc = 0xFFFF;
+ uint16_t wCRCin = 0xFFFF;
+ const uint16_t wCPoly = 0x1021;
for (size_t i = 0; i < length; i++) {
- crc ^= data[i];
for (int j = 0; j < 8; j++) {
- if (crc & 0x0001) {
- crc = (crc >> 1) ^ 0xA001;
- } else {
- crc = crc >> 1;
+ bool bit = ((data[i] >> (7 - j)) & 1) == 1;
+ bool c15 = ((wCRCin >> 15) & 1) == 1;
+ wCRCin = wCRCin << 1;
+ if (c15 ^ bit) {
+ wCRCin = wCRCin ^ wCPoly;
}
}
}
- return crc;
+ return wCRCin & 0xFFFF;
}
// 工具函数:将数值转换为十六进制字符串
diff --git a/app/src/main/java/com/example/cmake_project_test/BluetoothManager.kt b/app/src/main/java/com/example/cmake_project_test/BluetoothManager.kt
index 9fee58b..4a6ee41 100644
--- a/app/src/main/java/com/example/cmake_project_test/BluetoothManager.kt
+++ b/app/src/main/java/com/example/cmake_project_test/BluetoothManager.kt
@@ -26,9 +26,6 @@ import java.util.UUID
*/
class BluetoothManager(private val context: Context) {
- // PPTM命令编码器
- private val pptmEncoder = PPTMCommandEncoder()
-
companion object {
private const val TAG = "BluetoothManager"
@@ -44,22 +41,14 @@ class BluetoothManager(private val context: Context) {
// 功能码定义
const val FUNC_QUERY_DEVICE_INFO = 0x0000 // 查询设备信息
- const val FUNC_START_COLLECTION = 0x0001 // 开启采集
- const val FUNC_QUERY_BATTERY = 0x0002 // 查询电量
- const val FUNC_SET_SAMPLE_RATE = 0x0003 // 设置采样率
- const val FUNC_SET_GAIN = 0x0004 // 设置增益
- const val FUNC_SET_FILTER = 0x0005 // 设置滤波器
- const val FUNC_SET_LEAD = 0x0006 // 设置导联
- const val FUNC_SET_ALARM = 0x0007 // 设置报警
- const val FUNC_SET_TIME = 0x0008 // 设置时间
- const val FUNC_SET_DATE = 0x0009 // 设置日期
- const val FUNC_POWER_LINE_FILTER = 0x000A // 工频滤波
- const val FUNC_QUERY_STATUS = 0x000B // 查询状态
- const val FUNC_RESET_DEVICE = 0x000C // 设备复位
- const val FUNC_UPDATE_FIRMWARE = 0x000D // 固件升级
- const val FUNC_DATA_STREAM = 0x8000 // 数据流
- const val FUNC_ALARM_DATA = 0x8001 // 报警数据
- const val FUNC_STATUS_REPORT = 0x8002 // 状态报告
+ const val FUNC_START_COLLECTION = 0x0001 // 采集使能开关(带时间戳)
+ const val FUNC_QUERY_BATTERY = 0x0002 // 电量查询
+ const val FUNC_STIM_SWITCH = 0x0003 // 电刺激开关
+ const val FUNC_POWER_LINE_FILTER = 0x000A // 工频滤波开关
+ const val FUNC_SYNC_TIMESTAMP = 0x0080 // 同步时间戳(64bit毫秒)
+ const val FUNC_DATA_STREAM = 0x8000 // 数据上传
+ const val FUNC_ALARM_DATA = 0x8001 // 设备状态上报
+ const val FUNC_STATUS_REPORT = 0x8002 // 电量上报
// 数据包类型
const val PACKET_TYPE_COMMAND = 0x00 // 命令包
@@ -75,31 +64,7 @@ class BluetoothManager(private val context: Context) {
const val POWER_LINE_FILTER_OFF = 0x00 // 关闭工频滤波
const val POWER_LINE_FILTER_ON = 0x01 // 开启工频滤波
- // 采样率
- const val SAMPLE_RATE_125 = 125 // 125Hz
- const val SAMPLE_RATE_250 = 250 // 250Hz
- const val SAMPLE_RATE_500 = 500 // 500Hz
- const val SAMPLE_RATE_1000 = 1000 // 1000Hz
-
- // 增益设置
- const val GAIN_1 = 1 // 1倍增益
- const val GAIN_2 = 2 // 2倍增益
- const val GAIN_4 = 4 // 4倍增益
- const val GAIN_8 = 8 // 8倍增益
-
- // 导联设置
- const val LEAD_I = 0x01 // I导联
- const val LEAD_II = 0x02 // II导联
- const val LEAD_III = 0x03 // III导联
- const val LEAD_AVR = 0x04 // aVR导联
- const val LEAD_AVL = 0x05 // aVL导联
- const val LEAD_AVF = 0x06 // aVF导联
- const val LEAD_V1 = 0x07 // V1导联
- const val LEAD_V2 = 0x08 // V2导联
- const val LEAD_V3 = 0x09 // V3导联
- const val LEAD_V4 = 0x0A // V4导联
- const val LEAD_V5 = 0x0B // V5导联
- const val LEAD_V6 = 0x0C // V6导联
+ // 已移除:采样率、增益、导联设置常量(按PDF协议未定义)
// 响应状态码
const val RESPONSE_SUCCESS = 0x00 // 成功
@@ -156,9 +121,7 @@ class BluetoothManager(private val context: Context) {
// 协议状态
private var deviceInfo: DeviceInfo? = null
private var isCollecting = false
- private var currentSampleRate = Protocol.SAMPLE_RATE_500
- private var currentGain = Protocol.GAIN_1
- private var currentLead = Protocol.LEAD_II
+ // 已移除:采样率、增益、导联状态变量(按PDF协议未定义)
private var powerLineFilterEnabled = false
// 数据统计
@@ -908,101 +871,70 @@ class BluetoothManager(private val context: Context) {
}
/**
- * 查询设备信息
- * 功能码: 0x0000
+ * 电刺激开关
+ * 功能码: 0x0003
+ * 数据格式: [开关及类型(1字节)]
+ * 数据长度字段表示整个包的长度(7字节)
*/
- fun queryDeviceInfo() {
+ fun stimSwitch(stimType: Int, enable: Boolean) {
try {
- val packet = buildProtocolPacket(Protocol.FUNC_QUERY_DEVICE_INFO)
- Log.d(TAG, "发送查询设备信息指令: ${packet.joinToString(", ") { "0x%02X".format(it) }}")
+ val data = ByteArray(1)
+ // 开关及类型控制
+ // 高4位:开关控制(0000=关闭,0001=开启)
+ // 低4位:刺激类型(0000~1111,即0-15)
+ val switchBits = if (enable) 0x10 else 0x00 // 高4位:0001或0000
+ val typeBits = stimType and 0x0F // 低4位:确保在0-15范围内
+ data[0] = (switchBits or typeBits).toByte()
+
+ val packet = buildProtocolPacket(Protocol.FUNC_STIM_SWITCH, data)
+ Log.d(TAG, "发送电刺激开关指令: ${packet.joinToString(", ") { "0x%02X".format(it) }}")
sendCommand(packet)
} catch (e: Exception) {
- Log.e(TAG, "构建查询设备信息指令失败: ${e.message}")
- callback?.onCommandSent(false, "构建查询设备信息指令失败: ${e.message}")
+ Log.e(TAG, "构建电刺激开关指令失败: ${e.message}")
+ callback?.onCommandSent(false, "构建电刺激开关指令失败: ${e.message}")
}
}
-
+
/**
- * 查询电量
- * 功能码: 0x0002
+ * 同步时间戳
+ * 功能码: 0x0080
+ * 数据格式: [时间戳(8字节, 小端, 毫秒)]
*/
- fun queryBattery() {
+ fun syncTimestamp(timestampMs: Long) {
try {
- val packet = buildProtocolPacket(Protocol.FUNC_QUERY_BATTERY)
- Log.d(TAG, "发送查询电量指令: ${packet.joinToString(", ") { "0x%02X".format(it) }}")
+ val data = ByteArray(8)
+ for (i in 0..7) {
+ data[i] = ((timestampMs shr (i * 8)) and 0xFF).toByte()
+ }
+ val packet = buildProtocolPacket(Protocol.FUNC_SYNC_TIMESTAMP, data)
+ Log.d(TAG, "发送同步时间戳指令: ${packet.joinToString(", ") { "0x%02X".format(it) }}")
sendCommand(packet)
} catch (e: Exception) {
- Log.e(TAG, "构建查询电量指令失败: ${e.message}")
- callback?.onCommandSent(false, "构建查询电量指令失败: ${e.message}")
+ Log.e(TAG, "构建同步时间戳指令失败: ${e.message}")
+ callback?.onCommandSent(false, "构建同步时间戳指令失败: ${e.message}")
}
}
-
+
/**
* 设置采样率
* 功能码: 0x0003
* 数据格式: [采样率(2字节)]
*/
- fun setSampleRate(sampleRate: Int) {
- try {
- val data = ByteArray(2)
- data[0] = (sampleRate and 0xFF).toByte()
- data[1] = ((sampleRate shr 8) and 0xFF).toByte()
-
- val packet = buildProtocolPacket(Protocol.FUNC_SET_SAMPLE_RATE, data)
- Log.d(TAG, "发送设置采样率指令: ${packet.joinToString(", ") { "0x%02X".format(it) }}")
- sendCommand(packet)
-
- currentSampleRate = sampleRate
-
- } catch (e: Exception) {
- Log.e(TAG, "构建设置采样率指令失败: ${e.message}")
- callback?.onCommandSent(false, "构建设置采样率指令失败: ${e.message}")
- }
- }
+ // 已移除:设置采样率(按PDF未列出)
/**
* 设置增益
* 功能码: 0x0004
* 数据格式: [增益(1字节)]
*/
- fun setGain(gain: Int) {
- try {
- val data = ByteArray(1)
- data[0] = gain.toByte()
-
- val packet = buildProtocolPacket(Protocol.FUNC_SET_GAIN, data)
- Log.d(TAG, "发送设置增益指令: ${packet.joinToString(", ") { "0x%02X".format(it) }}")
- sendCommand(packet)
-
- currentGain = gain
-
- } catch (e: Exception) {
- Log.e(TAG, "构建设置增益指令失败: ${e.message}")
- callback?.onCommandSent(false, "构建设置增益指令失败: ${e.message}")
- }
- }
+ // 已移除:设置增益(按PDF未列出)
/**
* 设置导联
* 功能码: 0x0006
* 数据格式: [导联(1字节)]
*/
- fun setLead(lead: Int) {
- try {
- val data = ByteArray(1)
- data[0] = lead.toByte()
-
- val packet = buildProtocolPacket(Protocol.FUNC_SET_LEAD, data)
- Log.d(TAG, "发送设置导联指令: ${packet.joinToString(", ") { "0x%02X".format(it) }}")
- sendCommand(packet)
-
- currentLead = lead
-
- } catch (e: Exception) {
- Log.e(TAG, "构建设置导联指令失败: ${e.message}")
- callback?.onCommandSent(false, "构建设置导联指令失败: ${e.message}")
- }
- }
+ // 已移除:设置导联(按PDF未列出)
/**
* 工频滤波开关
@@ -1030,31 +962,13 @@ class BluetoothManager(private val context: Context) {
* 查询状态
* 功能码: 0x000B
*/
- fun queryStatus() {
- try {
- val packet = buildProtocolPacket(Protocol.FUNC_QUERY_STATUS)
- Log.d(TAG, "发送查询状态指令: ${packet.joinToString(", ") { "0x%02X".format(it) }}")
- sendCommand(packet)
- } catch (e: Exception) {
- Log.e(TAG, "构建查询状态指令失败: ${e.message}")
- callback?.onCommandSent(false, "构建查询状态指令失败: ${e.message}")
- }
- }
+ // 已移除:查询状态(按PDF未列出)
/**
* 设备复位
* 功能码: 0x000C
*/
- fun resetDevice() {
- try {
- val packet = buildProtocolPacket(Protocol.FUNC_RESET_DEVICE)
- Log.d(TAG, "发送设备复位指令: ${packet.joinToString(", ") { "0x%02X".format(it) }}")
- sendCommand(packet)
- } catch (e: Exception) {
- Log.e(TAG, "构建设备复位指令失败: ${e.message}")
- callback?.onCommandSent(false, "构建设备复位指令失败: ${e.message}")
- }
- }
+ // 已移除:设备复位(按PDF未列出)
/**
* 获取协议统计信息
@@ -1066,9 +980,7 @@ class BluetoothManager(private val context: Context) {
"totalPacketsReceived" to totalPacketsReceived,
"totalBytesReceived" to totalBytesReceived,
"isCollecting" to isCollecting,
- "currentSampleRate" to currentSampleRate,
- "currentGain" to currentGain,
- "currentLead" to currentLead,
+ // 已移除:采样率、增益、导联状态(按PDF协议未定义)
"powerLineFilterEnabled" to powerLineFilterEnabled,
"deviceInfo" to deviceInfo
)
@@ -1164,21 +1076,21 @@ class BluetoothManager(private val context: Context) {
* 计算CRC16-CCITT-FALSE校验
*/
private fun calculateCRC16(data: ByteArray, offset: Int, length: Int): Int {
- var crc = 0xFFFF
+ var wCRCin = 0xFFFF
+ val wCPoly = 0x1021
for (i in offset until offset + length) {
- crc = crc xor (data[i].toInt() and 0xFF)
for (j in 0..7) {
- if ((crc and 0x0001) != 0) {
- crc = crc shr 1
- crc = crc xor 0x8408
- } else {
- crc = crc shr 1
+ val bit = ((data[i].toInt() shr (7 - j)) and 1) == 1
+ val c15 = ((wCRCin shr 15) and 1) == 1
+ wCRCin = wCRCin shl 1
+ if (c15 xor bit) {
+ wCRCin = wCRCin xor wCPoly
}
}
}
- return crc
+ return wCRCin and 0xFFFF
}
/**
@@ -1691,80 +1603,4 @@ class BluetoothManager(private val context: Context) {
isCleaningUp = true
}
}
-
- // ==================== PPTM设备命令方法 ====================
-
- /**
- * 发送PPTM开始采样命令
- * 使用PPTM协议编码器生成带CRC16校验的命令
- */
- fun sendPptmStartSampleCmd() {
- try {
- val command = pptmEncoder.createPptmStartSampleCmd()
- Log.d(TAG, "发送PPTM开始采样命令: ${command.joinToString(", ") { "0x%02X".format(it) }}")
- sendCommand(command)
- callback?.onStatusChanged("📤 已发送PPTM开始采样命令")
- } catch (e: Exception) {
- Log.e(TAG, "发送PPTM开始采样命令失败: ${e.message}")
- callback?.onCommandSent(false, "发送PPTM开始采样命令失败: ${e.message}")
- }
- }
-
- /**
- * 发送PPTM停止采样命令
- * 使用PPTM协议编码器生成带CRC16校验的命令
- */
- fun sendPptmStopSampleCmd() {
- try {
- val command = pptmEncoder.createPptmStopSampleCmd()
- Log.d(TAG, "发送PPTM停止采样命令: ${command.joinToString(", ") { "0x%02X".format(it) }}")
- sendCommand(command)
- callback?.onStatusChanged("📤 已发送PPTM停止采样命令")
- } catch (e: Exception) {
- Log.e(TAG, "发送PPTM停止采样命令失败: ${e.message}")
- callback?.onCommandSent(false, "发送PPTM停止采样命令失败: ${e.message}")
- }
- }
-
- /**
- * 发送自定义PPTM命令
- * @param opcode 操作码
- * @param payload 负载数据
- */
- fun sendCustomPptmCmd(opcode: Short, payload: ByteArray) {
- try {
- val command = pptmEncoder.createCustomPptmCmd(opcode, payload)
- Log.d(TAG, "发送自定义PPTM命令: 操作码=0x%04X, 负载=${payload.joinToString(", ") { "0x%02X".format(it) }}".format(opcode))
- sendCommand(command)
- callback?.onStatusChanged("📤 已发送自定义PPTM命令: 操作码=0x%04X".format(opcode))
- } catch (e: Exception) {
- Log.e(TAG, "发送自定义PPTM命令失败: ${e.message}")
- callback?.onCommandSent(false, "发送自定义PPTM命令失败: ${e.message}")
- }
- }
-
- /**
- * 验证PPTM数据包CRC16校验
- * @param packet 完整数据包
- * @return 校验是否通过
- */
- fun verifyPptmPacket(packet: ByteArray): Boolean {
- return pptmEncoder.verifyCrc16(packet)
- }
-
- /**
- * 解析PPTM数据包
- * @param packet 完整数据包
- * @return 解析结果 (操作码, 负载数据) 或 null
- */
- fun parsePptmPacket(packet: ByteArray): Pair? {
- return pptmEncoder.parsePacket(packet)
- }
-
- /**
- * 获取PPTM编码器实例(用于调试)
- */
- fun getPptmEncoder(): PPTMCommandEncoder {
- return pptmEncoder
- }
}
diff --git a/app/src/main/java/com/example/cmake_project_test/CompletePipelineExample.kt b/app/src/main/java/com/example/cmake_project_test/CompletePipelineExample.kt
deleted file mode 100644
index 992985c..0000000
--- a/app/src/main/java/com/example/cmake_project_test/CompletePipelineExample.kt
+++ /dev/null
@@ -1,183 +0,0 @@
-package com.example.cmake_project_test
-
-import android.util.Log
-import type.SensorData
-
-/**
- * 完整数据处理管道示例
- * 演示从原始数据到最终指标的完整流程
- */
-class CompletePipelineExample {
-
- private val dataMapper = DataMapper()
- private val indicatorCalculator = IndicatorCalculator()
- private val signalProcessor = SignalProcessorJNI()
-
- private var dataMapperInitialized = false
- private var indicatorCalculatorInitialized = false
- private var signalProcessorInitialized = false
-
- /**
- * 初始化完整管道
- */
- fun initialize(): Boolean {
- Log.d("CompletePipeline", "初始化完整数据处理管道...")
-
- // 初始化数据映射器
- dataMapperInitialized = dataMapper.initialize()
- if (!dataMapperInitialized) {
- Log.e("CompletePipeline", "数据映射器初始化失败")
- return false
- }
-
- // 初始化指标计算器
- indicatorCalculatorInitialized = indicatorCalculator.initialize()
- if (!indicatorCalculatorInitialized) {
- Log.e("CompletePipeline", "指标计算器初始化失败")
- cleanup()
- return false
- }
-
- // 初始化信号处理器
- try {
- signalProcessorInitialized = signalProcessor.createProcessor()
- if (!signalProcessorInitialized) {
- Log.e("CompletePipeline", "信号处理器初始化失败")
- cleanup()
- return false
- }
- } catch (e: Exception) {
- Log.e("CompletePipeline", "信号处理器初始化异常: ${e.message}")
- cleanup()
- return false
- }
-
- Log.d("CompletePipeline", "完整数据处理管道初始化成功")
- return true
- }
-
- /**
- * 处理单个数据包的完整流程
- * 原始数据 → 解析数据 → 通道映射 → 信号处理 → 指标计算
- */
- fun processCompletePipeline(rawData: SensorData, sampleRate: Float = 250.0f): Map? {
- if (!isInitialized()) {
- Log.w("CompletePipeline", "管道未初始化")
- return null
- }
-
- Log.d("CompletePipeline", "开始处理完整数据管道...")
- Log.d("CompletePipeline", "输入数据类型: ${rawData.dataType}, 采样率: $sampleRate Hz")
-
- try {
- // 步骤1: 通道映射
- Log.d("CompletePipeline", "步骤1: 执行通道映射...")
- val mappedData = dataMapper.mapSensorData(rawData)
- if (mappedData == null) {
- Log.e("CompletePipeline", "通道映射失败")
- return null
- }
- Log.d("CompletePipeline", "通道映射完成")
-
- // 步骤2: 信号处理 (这里可以添加信号处理逻辑)
- Log.d("CompletePipeline", "步骤2: 执行信号处理...")
- // 暂时跳过信号处理,直接使用映射后的数据
- val processedData = mappedData
- Log.d("CompletePipeline", "信号处理完成")
-
- // 步骤3: 指标计算
- Log.d("CompletePipeline", "步骤3: 执行指标计算...")
- val metrics = indicatorCalculator.processCompletePipeline(processedData, sampleRate)
- if (metrics == null) {
- Log.e("CompletePipeline", "指标计算失败")
- return null
- }
-
- Log.d("CompletePipeline", "指标计算完成,计算了 ${metrics.size} 个指标")
- Log.d("CompletePipeline", "完整数据处理管道执行成功")
-
- // 打印主要指标
- metrics["heart_rate"]?.let {
- Log.d("CompletePipeline", "心率: ${String.format("%.1f", it)} bpm")
- }
- metrics["signal_quality"]?.let {
- Log.d("CompletePipeline", "信号质量: ${String.format("%.2f", it)}")
- }
- metrics["spo2"]?.let {
- Log.d("CompletePipeline", "血氧饱和度: ${String.format("%.1f", it)}%")
- }
-
- return metrics
-
- } catch (e: Exception) {
- Log.e("CompletePipeline", "完整数据处理管道异常: ${e.message}")
- return null
- }
- }
-
- /**
- * 批量处理数据包
- */
- fun processBatchPipeline(rawDataList: List, sampleRate: Float = 250.0f): List