External MCU design ok.

This commit is contained in:
Fancy code 2024-05-14 17:47:44 +08:00
parent 081397e560
commit 05ee22d556
7 changed files with 256 additions and 31 deletions

View File

@ -4,21 +4,6 @@
## 1.1. 基本概念
* **启动模式决定CPU单次启动的任务内容**
  每次启动的时间都是有限的由CPU完成单次启动完成任务后发送断电关机指令给MCUMCU给CPU断开物理电源启动模式可以由CPU主动询问也可以由MCU主动发送。
| 启动模式 | 说明 |
| ---- | ---- |
| PIR启动 | PIR触发启动。 |
| TEST启动 | 三档拨键拨到“TEST”常通电的工作模式。 |
| 连拍启动 | PIR触发场景下用户可以设置连拍的张数和连拍的间隔CPU通过协议告诉MCU在多少时间之后进行连拍启动。 |
| PIR延时启动 | 同PIR启动只是PIR触发后需要延时一段时间再给CPU上电。 |
| 定时启动 | 间隔固定时间启动一次例如60min/次 |
| 关机启动 | 某种场景下需要关机给CPU上电一次由CPU正式下发“关机”指令。 |
| 低电关机 | 电池低电需要关机给CPU上电一次由CPU正式下发“关机”指令。 |
| 异常启动 | CPU不正常时断电重启例如喂狗异常心跳异常。 |
* **工作状态:**
| 工作状态 | 说明 |
@ -27,12 +12,37 @@
| TEST状态 | 非正常工作状态此时主控常通电除非无操作时自动切换到ON状态。 |
| ON状态 | 设备正常工作状态必须保证低功耗性能PIR触发抓拍后必须快速关机主控断电。 |
**评审补充:**
1. 首次整机上电必须CPU物理上电完成SD卡产测文件检测实现产测功能
2. 动态切换到TEST/ON状态需要CPU物理上电
* **启动模式决定CPU单次启动的任务内容**
  每次启动的时间都是有限的由CPU完成单次启动完成任务后发送断电关机指令给MCUMCU给CPU断开物理电源启动模式可以由CPU主动询问也可以由MCU主动发送。
| 启动模式 | 说明 |
| ---- | ---- |
| PIR启动 | PIR触发启动。 |
| TEST启动 | 三档拨键拨到“TEST”常通电的工作模式。 |
| ON启动 | 三档拨键拨到“ON”正常工作模式。 |
| 连拍启动 | PIR触发场景下用户可以设置连拍的张数和连拍的间隔CPU通过协议告诉MCU在多少时间之后进行连拍启动。 |
| PIR延时启动 | 同PIR启动只是PIR触发后需要延时一段时间再给CPU上电。 |
| 定时启动 | 间隔固定时间启动一次例如60min/次 **待定** |
| 关机启动 | 某种场景下需要关机给CPU上电一次由CPU正式下发“关机”指令。 |
| 低电关机 | 电池低电需要关机给CPU上电一次由CPU正式下发“关机”指令。 |
| 异常启动 | CPU不正常时断电重启例如喂狗异常超时启动异常。 |
  工作模式对应板子上的三档拨键,有三个工作模式:关机/TEST/ON。
**评审补充:**
* 一个PIR连拍周期内忽略PIR触发
## 1.2. MCU基本功能
* 外围连接RTCPIR传感器
* 保存数据包括CPU的启动模式CPU定时启动时间工作时间周期
* 外围连接RTCPIR传感器,电量计
* 保存数据包括CPU的启动模式CPU定时启动时间工作时间周期PIR灵敏度
* 使用串口协议与CPU进行数据/功能协议交互;
| 需要保存的数据 | 说明 |
@ -52,6 +62,10 @@
  整机物理上电时,根据实际情况刷新设备的工作状态。
补充:
如果掉电无法保存数据,首次物理上电向主控获取;
默认开启喂狗;
```mermaid
sequenceDiagram
participant CPU
@ -89,6 +103,8 @@ note over MCU:休眠后进入正常工作模式当发生PIR触发时<br>
&emsp;&emsp;合理的休眠设计,最大降低产品功耗,延长单次换电的使用周期。
定时中断待确认;
```mermaid
sequenceDiagram
participant CPU
@ -167,6 +183,8 @@ end
&emsp;&emsp;外置MCU充当硬件狗在系统异常时断电重启系统。喂狗逻辑和启动模式无关。
默认开启喂狗;
```mermaid
sequenceDiagram
participant CPU
@ -202,6 +220,9 @@ note over MCU:休眠后进入正常工作模式当发生PIR触发时<br>
**注意:** 整机上电之后如果从来未开启过喂狗功能,此功能不生效。避免调试版本不停重启。
取消心跳,默认开启喂狗。喂狗线程模拟主线程心跳;
单次上电时间异常重启总时间3min
```mermaid
sequenceDiagram
participant CPU

View File

@ -101,9 +101,7 @@ class VMcuMonitor
public:
VMcuMonitor() = default;
virtual ~VMcuMonitor() = default;
virtual void RecvIpcMissionEvent(std::shared_ptr<VMcuAsk> &recv, const IpcMission &mission)
{
}
virtual void RecvIpcMissionEvent(std::shared_ptr<VMcuAsk> &recv, const IpcMission &mission);
};
class IMcuManager
{
@ -123,5 +121,6 @@ public:
virtual const StatusCode SetPirSensitivity(std::shared_ptr<VMcuAsk> &ask, const unsigned char &sensitivity);
virtual const StatusCode ContorlInfraredLight(std::shared_ptr<VMcuAsk> &ask, const ControlLight &control);
virtual const StatusCode GetPhotosensitivityValue(std::shared_ptr<VMcuAsk> &ask);
virtual const char *PrintIpcMissionString(const IpcMission &mission);
};
#endif

View File

@ -14,6 +14,9 @@
*/
#include "IMcuManager.h"
#include "ILog.h"
void VMcuMonitor::RecvIpcMissionEvent(std::shared_ptr<VMcuAsk> &recv, const IpcMission &mission)
{
}
std::shared_ptr<IMcuManager> &IMcuManager::GetInstance(std::shared_ptr<IMcuManager> *impl)
{
static auto instance = std::make_shared<IMcuManager>();
@ -73,3 +76,7 @@ const StatusCode IMcuManager::GetPhotosensitivityValue(std::shared_ptr<VMcuAsk>
{
return CreateStatusCode(STATUS_CODE_VIRTUAL_FUNCTION);
}
const char *IMcuManager::PrintIpcMissionString(const IpcMission &mission)
{
return "VIRTUAL FUNCTION";
}

View File

@ -78,6 +78,29 @@ const StatusCode McuManagerImpl::GetPhotosensitivityValue(std::shared_ptr<VMcuAs
std::shared_ptr<VProtocolContext> context = std::make_shared<ProtocolContext<std::shared_ptr<VMcuAsk>>>(ask);
return McuProtocol::GetPhotosensitivityValue(context);
}
const char *McuManagerImpl::PrintIpcMissionString(const IpcMission &mission)
{
switch (mission) {
case IpcMission::PIR_TRIGGERED: {
return "PIR_TRIGGERED";
}
case IpcMission::TEST: {
return "TEST";
}
case IpcMission::CONTINUOUS_SHOOTING: {
return "CONTINUOUS_SHOOTING";
}
case IpcMission::PIR_TRIGGERED_DELAY: {
return "PIR_TRIGGERED_DELAY";
}
case IpcMission::REGULAR_START: {
return "REGULAR_START";
}
default: {
return "UNKNOWN";
}
}
}
std::shared_ptr<VMcuMonitor> McuManagerImpl::GetMcuMonitor(void)
{
auto monitor = mMonitor.lock();

View File

@ -35,6 +35,7 @@ public:
const StatusCode SetPirSensitivity(std::shared_ptr<VMcuAsk> &ask, const unsigned char &sensitivity) override;
const StatusCode ContorlInfraredLight(std::shared_ptr<VMcuAsk> &ask, const ControlLight &control) override;
const StatusCode GetPhotosensitivityValue(std::shared_ptr<VMcuAsk> &ask) override;
const char *PrintIpcMissionString(const IpcMission &mission) override;
private:
std::shared_ptr<VMcuMonitor> GetMcuMonitor(void);

View File

@ -51,7 +51,7 @@ public:
}
};
// ../output_files/test/bin/McuManagerTest
// --gtest_filter=McuManagerTest.INTEGRATION_McuManager_AUTO_GetIpcMission
// --gtest_filter=McuManagerTest.RH_INTEGRATION_McuManager_AUTO_GetIpcMission
TEST_F(McuManagerTest, RH_INTEGRATION_McuManager_AUTO_GetIpcMission)
{
class McuAskTest : public McuAsk<IpcMission>, public McuAskBaseTestTool
@ -82,4 +82,173 @@ TEST_F(McuManagerTest, RH_INTEGRATION_McuManager_AUTO_GetIpcMission)
IMcuManager::GetInstance()->GetIpcMission(ask);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
// ../output_files/test/bin/McuManagerTest
// --gtest_filter=McuManagerMockTest.RH_INTEGRATION_McuManager_AUTO_OtherSideSendIpcMission
TEST_F(McuManagerTest, RH_INTEGRATION_McuManager_AUTO_OtherSideSendIpcMission)
{
class MonitorTest : public VMcuMonitor
{
public:
MonitorTest() = default;
virtual ~MonitorTest() = default;
void RecvIpcMissionEvent(std::shared_ptr<VMcuAsk> &recv, const IpcMission &mission) override
{
LogInfo("RecvIpcMissionEvent %s\n", IMcuManager::GetInstance()->PrintIpcMissionString(mission));
std::shared_ptr<McuAsk<ASK_RESULT>> ask = std::dynamic_pointer_cast<McuAsk<ASK_RESULT>>(recv);
ask->mDataReply = ASK_RESULT::SUCCEED;
recv->ReplyFinished(true);
}
};
IMcuManager::GetInstance()->Init();
std::shared_ptr<VMcuMonitor> monitor = std::make_shared<MonitorTest>();
IMcuManager::GetInstance()->SetMcuMonitor(monitor);
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
IMcuManager::GetInstance()->UnInit();
}
// ../output_files/test/bin/McuManagerTest
// --gtest_filter=McuManagerMockTest.RH_INTEGRATION_McuManager_AUTO_CutOffPowerSupply
TEST_F(McuManagerTest, RH_INTEGRATION_McuManager_AUTO_CutOffPowerSupply)
{
class McuAskTest : public McuAskBaseTestTool
{
public:
McuAskTest()
: McuAskBaseTestTool(McuAskBlock::UNRELATED,
McuAskReply::NEED_NOT_REPLY) // using McuAskReply::NEED_NOT_REPLY
{
}
virtual ~McuAskTest() = default;
};
IMcuManager::GetInstance()->Init();
std::shared_ptr<VMcuAsk> ask = std::make_shared<McuAskTest>();
std::shared_ptr<McuAskBaseTestTool> testTool = std::dynamic_pointer_cast<McuAskBaseTestTool>(ask);
testTool->McuAskDefaultFeatures(testTool);
StatusCode code = IMcuManager::GetInstance()->CutOffPowerSupply(ask);
EXPECT_EQ(code.mStatusCode, STATUS_CODE_OK); // STATUS_CODE_OK means write data to mcu succeed.
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
IMcuManager::GetInstance()->UnInit();
}
// ../output_files/test/bin/McuManagerTest
// --gtest_filter=McuManagerMockTest.RH_INTEGRATION_McuManager_AUTO_SetFeedingCycleForWatchDog
TEST_F(McuManagerTest, RH_INTEGRATION_McuManager_AUTO_SetFeedingCycleForWatchDog)
{
class McuAskTest : public McuAsk<ASK_RESULT>, public McuAskBaseTestTool
{
public:
McuAskTest() : McuAskBaseTestTool(McuAskBlock::BLOCK,
McuAskReply::NEED_REPLY) // using McuAskBlock::BLOCK,
{
}
virtual ~McuAskTest() = default;
void ReplyFinished(const bool result) override
{
McuAskBaseTestTool::ReplyFinished(result);
if (result) {
LogInfo("Ask data succeed, mDataReply = %d.\n", static_cast<int>(mDataReply));
EXPECT_LT(static_cast<int>(mDataReply), static_cast<int>(ASK_RESULT::SUCCEED));
}
else {
LogError("Ask data falied.\n");
}
}
};
IMcuManager::GetInstance()->Init();
std::shared_ptr<VMcuAsk> ask = std::make_shared<McuAskTest>();
std::shared_ptr<McuAskBaseTestTool> testTool = std::dynamic_pointer_cast<McuAskBaseTestTool>(ask);
testTool->McuAskDefaultFeatures(testTool);
StatusCode code = IMcuManager::GetInstance()->SetFeedingCycleForWatchDog(ask, 1, 1, 1);
EXPECT_EQ(code.mStatusCode, STATUS_CODE_OK); // STATUS_CODE_OK means write data to mcu succeed.
std::this_thread::sleep_for(std::chrono::milliseconds(100));
IMcuManager::GetInstance()->UnInit();
}
// ../output_files/test/bin/McuManagerTest
// --gtest_filter=McuManagerMockTest.RH_INTEGRATION_McuManager_AUTO_FeedWatchDog
TEST_F(McuManagerTest, RH_INTEGRATION_McuManager_AUTO_FeedWatchDog)
{
class McuAskTest : public McuAskBaseTestTool
{
public:
McuAskTest()
: McuAskBaseTestTool(McuAskBlock::UNRELATED,
McuAskReply::NEED_NOT_REPLY) // using McuAskReply::NEED_NOT_REPLY
{
}
virtual ~McuAskTest() = default;
};
IMcuManager::GetInstance()->Init();
std::shared_ptr<VMcuAsk> ask = std::make_shared<McuAskTest>();
std::shared_ptr<McuAskBaseTestTool> testTool = std::dynamic_pointer_cast<McuAskBaseTestTool>(ask);
testTool->McuAskDefaultFeatures(testTool);
StatusCode code = IMcuManager::GetInstance()->FeedWatchDog(ask);
EXPECT_EQ(code.mStatusCode, STATUS_CODE_OK); // STATUS_CODE_OK means write data to mcu succeed.
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
IMcuManager::GetInstance()->UnInit();
}
// ../output_files/test/bin/McuManagerTest
// --gtest_filter=McuManagerMockTest.RH_INTEGRATION_McuManager_AUTO_SetDataTime
TEST_F(McuManagerTest, RH_INTEGRATION_McuManager_AUTO_SetDataTime)
{
class McuAskTest : public McuAsk<ASK_RESULT>, public McuAskBaseTestTool
{
public:
McuAskTest() : McuAskBaseTestTool(McuAskBlock::BLOCK,
McuAskReply::NEED_REPLY) // using McuAskBlock::NOT_BLOCK
{
}
virtual ~McuAskTest() = default;
void ReplyFinished(const bool result) override
{
McuAskBaseTestTool::ReplyFinished(result);
if (result) {
LogInfo("Ask data succeed, mDataReply = %d.\n", static_cast<int>(mDataReply));
EXPECT_LT(static_cast<int>(mDataReply), static_cast<int>(ASK_RESULT::SUCCEED));
}
else {
LogError("Ask data falied.\n");
}
}
};
IMcuManager::GetInstance()->Init();
std::shared_ptr<VMcuAsk> ask = std::make_shared<McuAskTest>();
std::shared_ptr<McuAskBaseTestTool> testTool = std::dynamic_pointer_cast<McuAskBaseTestTool>(ask);
testTool->McuAskDefaultFeatures(testTool);
McuAskDateTime value(2014, 1, 15, 0, 0, 0);
StatusCode code = IMcuManager::GetInstance()->SetDateTime(ask, value);
EXPECT_EQ(code.mStatusCode, STATUS_CODE_OK); // STATUS_CODE_OK means write data to mcu succeed.
std::this_thread::sleep_for(std::chrono::milliseconds(100));
IMcuManager::GetInstance()->UnInit();
}
// ../output_files/test/bin/McuManagerTest
// --gtest_filter=McuManagerMockTest.RH_INTEGRATION_McuManager_AUTO_SetPirSensitivity
TEST_F(McuManagerTest, RH_INTEGRATION_McuManager_AUTO_SetPirSensitivity)
{
class McuAskTest : public McuAsk<ASK_RESULT>, public McuAskBaseTestTool
{
public:
McuAskTest() : McuAskBaseTestTool(McuAskBlock::BLOCK,
McuAskReply::NEED_REPLY) // using McuAskBlock::NOT_BLOCK
{
}
virtual ~McuAskTest() = default;
void ReplyFinished(const bool result) override
{
McuAskBaseTestTool::ReplyFinished(result);
if (result) {
LogInfo("Ask data succeed, mDataReply = %d.\n", static_cast<int>(mDataReply));
EXPECT_LT(static_cast<int>(mDataReply), static_cast<int>(ASK_RESULT::SUCCEED));
}
else {
LogError("Ask data falied.\n");
}
}
};
IMcuManager::GetInstance()->Init();
std::shared_ptr<VMcuAsk> ask = std::make_shared<McuAskTest>();
std::shared_ptr<McuAskBaseTestTool> testTool = std::dynamic_pointer_cast<McuAskBaseTestTool>(ask);
testTool->McuAskDefaultFeatures(testTool);
StatusCode code = IMcuManager::GetInstance()->SetPirSensitivity(ask, 1);
EXPECT_EQ(code.mStatusCode, STATUS_CODE_OK); // STATUS_CODE_OK means write data to mcu succeed.
std::this_thread::sleep_for(std::chrono::milliseconds(100));
IMcuManager::GetInstance()->UnInit();
}
} // namespace McuManagerTest

View File

@ -122,16 +122,16 @@ unsigned short calculate_check_sum(const unsigned char* pData, unsigned short le
4. 问答型协议只有按位最高位相反其它位相等例如0x8101与0x0101是一问一答的协议
| 命令字 | CPU | MCU | 数据段 | 协议解析 | 备注 |
|----|----|----|----|----|----|
| ---- | ---- | ---- | ---- | ---- | ---- |
| 0x8101 | ask | - | - | 获取启动模式 | - |
| 0x0101 | - | reply | Data[0]:启动模式<br>0x01:PIR启动<br>0x02:TEST启动<br>0x03:连拍启动<br>0x04:PIR延时启动<br>0x05:定时(间隔一定时间)启动<br>0x06:关机<br>0x07:低电关机<br>0x08:异常启动 | 回复启动模式 | 异常启动数据Data[1]<br>0x00:喂狗异常启动<br>0x01:心跳异常启动 |
| 0x0101 | - | reply | Data[0]:启动模式<br>0x01:PIR启动 <br>0x02:TEST启动 <br>0x03:ON启动 <br>0x04:连拍启动 <br>0x05:PIR延时启动 <br>0x06:定时(间隔一定时间)启动 <br>0x07:关机 <br>0x08:低电关机 <br>0x09:异常启动 | 回复启动模式 | 异常启动数据Data[1]<br>0x00:喂狗异常启动<br>0x01:超时异常启动 |
| 0x8102 | ask | - | - | 断电关机 | - |
| 0x8103 | ask | - | - | 喂狗 | - |
| 0x8104 | ask | - | Data[0]:Hour<br>0-23<br>Data[1]:Min<br>0-59<br>Data[2]:Sec<br>0-59 | 开启狗/设置喂狗周期 | - |
| 0x0104 | - | reply | Data[0]:结果<br>0x01:成功<br>0x02:失败 | 开启狗/设置喂狗周期回复 | - |
| 0x8105 | ask | - | - | 关闭狗 | - |
| 0x0105 | - | reply | Data[0]:结果<br>0x01:成功<br>0x02:失败 | 关闭狗回复 | - |
| 0x8106 | ask | - | Data[0]:Hour<br>0-23<br>Data[1]:Min<br>0-59<br>Data[2]:Sec<br>0-59 | 设置间隔启动时间 | - |
| 0x8104 | ask | - | Data[2]两字节的数字单位s | 设置喂狗周期 | 0s代表关闭喂狗 修改为两个字节单位s |
| 0x0104 | - | reply | Data[0]:结果<br>0x01:成功<br>0x02:失败 | 设置喂狗周期回复 | - |
| 0x8105 | ask | - | - | 关闭狗 | 取消 |
| 0x0105 | - | reply | Data[0]:结果<br>0x01:成功<br>0x02:失败 | 关闭狗回复 | 取消 |
| 0x8106 | ask | - | Data[0]:Hour<br>0-23<br>Data[1]:Min<br>0-59<br>Data[2]:Sec<br>0-59 | 设置间隔启动时间 | 定时启动 |
| 0x0106 | - | reply | Data[0]:结果<br>0x01:成功<br>0x02:失败 | 设置间隔启动时间回复 | - |
| 0x8107 | ask | - | Data[0]:Year<br>Data[1]:Mon<br>1-12<br>Data[2]:Day<br>0-31<br>Data[3]:Hour<br>0-23<br>Data[4]:Min<br>0-59<br>Data[5]:Sec<br>0-59 | 设置日期和时间 | - |
| 0x0107 | - | reply | Data[0]:结果<br>0x01:成功<br>0x02:失败 | 设置日期和时间回复 | - |
@ -145,7 +145,12 @@ unsigned short calculate_check_sum(const unsigned char* pData, unsigned short le
| 0x010B | - | reply | Data[0]:结果<br>0-100 | 获取光敏值回复 | 取消 |
| ====== | === | ====== | ============================ | ==================== | ======= |
| 0xC101 | reply | - | Data[0]:结果<br>0x01:成功<br>0x02:失败 | 发送启动模式回复 | - |
| 0x4101 | - | ask | Data[0]:启动模式<br>0x01:PIR启动<br>0x02:TEST启动<br>0x03:连拍启动<br>0x04:PIR延时启动<br>0x05:定时(间隔一定时间)启动<br>0x06:关机<br>0x07:低电关机<br>0x08:异常启动 | 发送启动模式 | 异常启动数据Data[1]<br>0x00:喂狗异常启动<br>0x01:心跳异常启动 |
| 0xC102 | reply | - | - | 回复心跳包 | - |
| 0x4102 | - | ask | - | 发送心跳包 | - |
| 0x4101 | - | ask | Data[0]:启动模式<br>0x01:PIR启动 <br>0x02:TEST启动 <br>0x03:ON启动 <br>0x04:连拍启动 <br>0x05:PIR延时启动 <br>0x06:定时(间隔一定时间)启动 <br>0x07:关机 <br>0x08:低电关机 <br>0x09:异常启动 | 发送启动模式 | 异常启动数据Data[1]<br>0x00:喂狗异常启动<br>0x01:超时异常启动 |
| 0xC102 | reply | - | - | 回复心跳包 | 取消 |
| 0x4102 | - | ask | - | 发送心跳包 | 取消 |
### 1.2.1. 名词解析
| 名词 | 解析 |
| ---- | ---- |
| 超时异常启动 | MCU给主控上电后**非TEST启动**不管主控是否正常喂狗如果单次上电时长超过3min未关机给主控断电重启一次。 |