feat:增加蓝牙配网功能
This commit is contained in:
+59
-13
@@ -19,6 +19,11 @@ RadarManager::RadarManager()
|
||||
, _callback(nullptr)
|
||||
, _frameCount(0)
|
||||
, _errorCount(0)
|
||||
, _lastHeartBeat(0)
|
||||
, _lastBreathBeat(0)
|
||||
, _stablePresence(false)
|
||||
, _presenceCnt(0)
|
||||
, _lastRawPresence(false)
|
||||
{
|
||||
memset(&_currentFrame, 0, sizeof(_currentFrame));
|
||||
memset(&_data, 0, sizeof(_data));
|
||||
@@ -43,6 +48,9 @@ bool RadarManager::begin() {
|
||||
_resetParser();
|
||||
memset(&_data, 0, sizeof(_data));
|
||||
_data.lastUpdate = millis();
|
||||
_stablePresence = false;
|
||||
_presenceCnt = 0;
|
||||
_lastRawPresence = false;
|
||||
|
||||
// 不给雷达发任何命令,让它自己初始化并开始自动上报
|
||||
// R60ABD1 上电后通常需要 15-30 秒自检,之后自动输出数据
|
||||
@@ -68,6 +76,16 @@ void RadarManager::loop() {
|
||||
Serial.printf("[雷达] ✅ 开始接收数据 (首帧)\n");
|
||||
}
|
||||
|
||||
// 心率/呼吸数据过期 (>10秒无更新 → 标记无效)
|
||||
if (millis() - _lastHeartBeat > 10000) {
|
||||
_data.vitalValid = false;
|
||||
_data.heartRate = 0;
|
||||
}
|
||||
if (millis() - _lastBreathBeat > 10000) {
|
||||
_data.vitalValid = false;
|
||||
_data.breathRate = 0;
|
||||
}
|
||||
|
||||
// 超时检测:如果 10 秒还没收到任何数据,打印一次
|
||||
static uint32_t noDataWarn = 0;
|
||||
if (_frameCount == 0 && millis() - _data.lastUpdate > 10000) {
|
||||
@@ -222,6 +240,9 @@ void RadarManager::_processCompleteFrame() {
|
||||
case CTRL_HEART_RATE:
|
||||
_extractHeartRate(_currentFrame);
|
||||
break;
|
||||
case CTRL_FALL:
|
||||
_extractFall(_currentFrame); // AFD1 专用跌倒
|
||||
break;
|
||||
case CTRL_SLEEP:
|
||||
_extractSleep(_currentFrame);
|
||||
break;
|
||||
@@ -250,47 +271,60 @@ void RadarManager::_processCompleteFrame() {
|
||||
|
||||
void RadarManager::_extractPresence(const RadarFrame& frame) {
|
||||
uint8_t raw = frame.data_length > 0 ? frame.data[0] : 0;
|
||||
bool rawPresence = false;
|
||||
|
||||
// cmd 0x00 (len=1): 有人状态 (1=有人 0=无人)
|
||||
if (frame.command == 0x00 && frame.data_length >= 1) {
|
||||
_data.presence = (raw == 1);
|
||||
rawPresence = (raw == 1);
|
||||
_data.radarValid = true;
|
||||
_data.lastUpdate = millis();
|
||||
_notifyUpdate();
|
||||
}
|
||||
// cmd 0x01 (len=1): 运动状态/体动 (值越大越活跃)
|
||||
else if (frame.command == 0x01 && frame.data_length >= 1) {
|
||||
_data.body = raw; // 0=静止, 1+=有体动
|
||||
_data.motion = (raw >= 1); // >=1 有运动
|
||||
_data.body = raw;
|
||||
_data.motion = (raw >= 1);
|
||||
_data.radarValid = true;
|
||||
_data.lastUpdate = millis();
|
||||
_notifyUpdate();
|
||||
return; // 运动帧不含有人信息, 跳过防抖
|
||||
}
|
||||
// cmd 0x03 (len=1): 有人状态备用 (非0=有人)
|
||||
else if (frame.command == 0x03 && frame.data_length >= 1) {
|
||||
_data.presence = (raw != 0);
|
||||
rawPresence = (raw != 0);
|
||||
_data.radarValid = true;
|
||||
_data.lastUpdate = millis();
|
||||
_notifyUpdate();
|
||||
}
|
||||
// cmd 0x04 (len=2): [0]=presence [1]=motion
|
||||
else if (frame.command == 0x04 && frame.data_length >= 2) {
|
||||
_data.presence = (frame.data[0] != 0);
|
||||
_data.motion = (frame.data[1] == 0);
|
||||
rawPresence = (frame.data[0] != 0);
|
||||
_data.motion = (frame.data[1] == 0);
|
||||
_data.radarValid = true;
|
||||
_data.lastUpdate = millis();
|
||||
_notifyUpdate();
|
||||
}
|
||||
// cmd 0x05 (len=6): 完整包
|
||||
else if (frame.command == 0x05 && frame.data_length >= 6) {
|
||||
_data.presence = (frame.data[0] != 0);
|
||||
rawPresence = (frame.data[0] != 0);
|
||||
_data.motion = (frame.data[1] == 0);
|
||||
_data.distance = ((uint16_t)frame.data[2] << 8) | frame.data[3];
|
||||
_data.body = frame.data[4];
|
||||
_data.radarValid = true;
|
||||
_data.lastUpdate = millis();
|
||||
_notifyUpdate();
|
||||
} else {
|
||||
return; // 未知命令
|
||||
}
|
||||
|
||||
// 防抖: 连续 PRESENCE_HYSTERESIS 次一致才更新
|
||||
if (rawPresence == _lastRawPresence) {
|
||||
if (_presenceCnt < PRESENCE_HYSTERESIS) _presenceCnt++;
|
||||
} else {
|
||||
_presenceCnt = 0;
|
||||
_lastRawPresence = rawPresence;
|
||||
}
|
||||
if (_presenceCnt >= PRESENCE_HYSTERESIS && rawPresence != _data.presence) {
|
||||
_data.presence = rawPresence;
|
||||
_stablePresence = rawPresence;
|
||||
}
|
||||
_notifyUpdate();
|
||||
}
|
||||
|
||||
void RadarManager::_extractBreathing(const RadarFrame& frame) {
|
||||
@@ -299,8 +333,9 @@ void RadarManager::_extractBreathing(const RadarFrame& frame) {
|
||||
if (rate != 0x80 && rate != 0x00 && rate <= 40) {
|
||||
_data.breathRate = rate;
|
||||
_data.vitalValid = true;
|
||||
_data.presence = true; // 有呼吸=有人
|
||||
_data.presence = true;
|
||||
_data.radarValid = true;
|
||||
_lastBreathBeat = millis();
|
||||
}
|
||||
_data.lastUpdate = millis();
|
||||
_notifyUpdate();
|
||||
@@ -313,14 +348,25 @@ void RadarManager::_extractHeartRate(const RadarFrame& frame) {
|
||||
if (rate != 0x80 && rate != 0x00 && rate >= 40) {
|
||||
_data.heartRate = rate;
|
||||
_data.vitalValid = true;
|
||||
_data.presence = true; // 有心跳=有人
|
||||
_data.presence = true;
|
||||
_data.radarValid = true;
|
||||
_lastHeartBeat = millis();
|
||||
}
|
||||
_data.lastUpdate = millis();
|
||||
_notifyUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
// AFD1 专用: 跌倒检测 (控制字 0x83)
|
||||
void RadarManager::_extractFall(const RadarFrame& frame) {
|
||||
if (frame.data_length >= 1) {
|
||||
_data.fall = (frame.data[0] != 0);
|
||||
_data.radarValid = true;
|
||||
_data.lastUpdate = millis();
|
||||
_notifyUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void RadarManager::_extractSleep(const RadarFrame& frame) {
|
||||
// 从睡眠数据提取: cmd=0x00/0x01 为入床离床状态
|
||||
if (frame.data_length >= 1) {
|
||||
|
||||
Reference in New Issue
Block a user