diff --git a/middleware/McuManager/README.md b/middleware/McuManager/README.md index 2bc02a9..9779f41 100644 --- a/middleware/McuManager/README.md +++ b/middleware/McuManager/README.md @@ -4,21 +4,6 @@ ## 1.1. 基本概念 -* **启动模式:决定CPU单次启动的任务内容;** - -  每次启动的时间都是有限的,由CPU完成单次启动完成任务后发送断电关机指令给MCU,MCU给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完成单次启动完成任务后发送断电关机指令给MCU,MCU给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基本功能 -* 外围连接RTC,PIR传感器; -* 保存数据包括:CPU的启动模式,CPU定时启动时间,工作时间周期; +* 外围连接RTC,PIR传感器,电量计; +* 保存数据包括:CPU的启动模式,CPU定时启动时间,工作时间周期,PIR灵敏度; * 使用串口协议与CPU进行数据/功能协议交互; | 需要保存的数据 | 说明 | @@ -52,6 +62,10 @@   整机物理上电时,根据实际情况刷新设备的工作状态。 +补充: +如果掉电无法保存数据,首次物理上电向主控获取; +默认开启喂狗; + ```mermaid sequenceDiagram participant CPU @@ -89,6 +103,8 @@ note over MCU:休眠后进入正常工作模式:当发生PIR触发时,
  合理的休眠设计,最大降低产品功耗,延长单次换电的使用周期。 +定时中断待确认; + ```mermaid sequenceDiagram participant CPU @@ -167,6 +183,8 @@ end   外置MCU充当硬件狗,在系统异常时断电重启系统。喂狗逻辑和启动模式无关。 +默认开启喂狗; + ```mermaid sequenceDiagram participant CPU @@ -202,6 +220,9 @@ note over MCU:休眠后进入正常工作模式:当发生PIR触发时,
**注意:** 整机上电之后如果从来未开启过喂狗功能,此功能不生效。避免调试版本不停重启。 +取消心跳,默认开启喂狗。喂狗线程模拟主线程心跳; +单次上电时间异常重启,总时间3min; + ```mermaid sequenceDiagram participant CPU diff --git a/middleware/McuManager/include/IMcuManager.h b/middleware/McuManager/include/IMcuManager.h index 2d46625..097e49d 100644 --- a/middleware/McuManager/include/IMcuManager.h +++ b/middleware/McuManager/include/IMcuManager.h @@ -122,5 +122,6 @@ public: virtual const StatusCode SetPirSensitivity(std::shared_ptr &ask, const unsigned char &sensitivity); virtual const StatusCode ContorlInfraredLight(std::shared_ptr &ask, const ControlLight &control); virtual const StatusCode GetPhotosensitivityValue(std::shared_ptr &ask); + virtual const char *PrintIpcMissionString(const IpcMission &mission); }; #endif \ No newline at end of file diff --git a/middleware/McuManager/src/IMcuManager.cpp b/middleware/McuManager/src/IMcuManager.cpp index fa53a80..1248b4b 100644 --- a/middleware/McuManager/src/IMcuManager.cpp +++ b/middleware/McuManager/src/IMcuManager.cpp @@ -78,4 +78,8 @@ const StatusCode IMcuManager::ContorlInfraredLight(std::shared_ptr &ask const StatusCode IMcuManager::GetPhotosensitivityValue(std::shared_ptr &ask) { return CreateStatusCode(STATUS_CODE_VIRTUAL_FUNCTION); +} +const char *IMcuManager::PrintIpcMissionString(const IpcMission &mission) +{ + return "VIRTUAL FUNCTION"; } \ No newline at end of file diff --git a/middleware/McuManager/src/McuManagerImpl.cpp b/middleware/McuManager/src/McuManagerImpl.cpp index 69fc538..d9ef88c 100644 --- a/middleware/McuManager/src/McuManagerImpl.cpp +++ b/middleware/McuManager/src/McuManagerImpl.cpp @@ -125,6 +125,29 @@ const StatusCode McuManagerImpl::GetPhotosensitivityValue(std::shared_ptr context = std::make_shared>>(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 McuManagerImpl::GetMcuMonitor(void) { auto monitor = mMonitor.lock(); diff --git a/middleware/McuManager/src/McuManagerImpl.h b/middleware/McuManager/src/McuManagerImpl.h index c89c13e..448c6bb 100644 --- a/middleware/McuManager/src/McuManagerImpl.h +++ b/middleware/McuManager/src/McuManagerImpl.h @@ -47,6 +47,7 @@ public: const StatusCode SetPirSensitivity(std::shared_ptr &ask, const unsigned char &sensitivity) override; const StatusCode ContorlInfraredLight(std::shared_ptr &ask, const ControlLight &control) override; const StatusCode GetPhotosensitivityValue(std::shared_ptr &ask) override; + const char *PrintIpcMissionString(const IpcMission &mission) override; private: std::shared_ptr GetMcuMonitor(void); diff --git a/test/middleware/McuManager/src/McuManager_Test.cpp b/test/middleware/McuManager/src/McuManager_Test.cpp index b2cddbe..b9edfe9 100644 --- a/test/middleware/McuManager/src/McuManager_Test.cpp +++ b/test/middleware/McuManager/src/McuManager_Test.cpp @@ -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, 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 &recv, const IpcMission &mission) override + { + LogInfo("RecvIpcMissionEvent %s\n", IMcuManager::GetInstance()->PrintIpcMissionString(mission)); + std::shared_ptr> ask = std::dynamic_pointer_cast>(recv); + ask->mDataReply = ASK_RESULT::SUCCEED; + recv->ReplyFinished(true); + } + }; + IMcuManager::GetInstance()->Init(); + std::shared_ptr monitor = std::make_shared(); + 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 ask = std::make_shared(); + std::shared_ptr testTool = std::dynamic_pointer_cast(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, 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(mDataReply)); + EXPECT_LT(static_cast(mDataReply), static_cast(ASK_RESULT::SUCCEED)); + } + else { + LogError("Ask data falied.\n"); + } + } + }; + IMcuManager::GetInstance()->Init(); + std::shared_ptr ask = std::make_shared(); + std::shared_ptr testTool = std::dynamic_pointer_cast(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 ask = std::make_shared(); + std::shared_ptr testTool = std::dynamic_pointer_cast(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, 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(mDataReply)); + EXPECT_LT(static_cast(mDataReply), static_cast(ASK_RESULT::SUCCEED)); + } + else { + LogError("Ask data falied.\n"); + } + } + }; + IMcuManager::GetInstance()->Init(); + std::shared_ptr ask = std::make_shared(); + std::shared_ptr testTool = std::dynamic_pointer_cast(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, 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(mDataReply)); + EXPECT_LT(static_cast(mDataReply), static_cast(ASK_RESULT::SUCCEED)); + } + else { + LogError("Ask data falied.\n"); + } + } + }; + IMcuManager::GetInstance()->Init(); + std::shared_ptr ask = std::make_shared(); + std::shared_ptr testTool = std::dynamic_pointer_cast(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 \ No newline at end of file diff --git a/utils/McuProtocol/README.md b/utils/McuProtocol/README.md index 097b21f..8849662 100644 --- a/utils/McuProtocol/README.md +++ b/utils/McuProtocol/README.md @@ -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]:启动模式
0x01:PIR启动
0x02:TEST启动
0x03:连拍启动
0x04:PIR延时启动
0x05:定时(间隔一定时间)启动
0x06:关机
0x07:低电关机
0x08:异常启动 | 回复启动模式 | 异常启动数据:Data[1]
0x00:喂狗异常启动
0x01:心跳异常启动 | +| 0x0101 | - | reply | Data[0]:启动模式
0x01:PIR启动
0x02:TEST启动
0x03:ON启动
0x04:连拍启动
0x05:PIR延时启动
0x06:定时(间隔一定时间)启动
0x07:关机
0x08:低电关机
0x09:异常启动 | 回复启动模式 | 异常启动数据:Data[1]
0x00:喂狗异常启动
0x01:超时异常启动 | | 0x8102 | ask | - | - | 断电关机 | - | | 0x8103 | ask | - | - | 喂狗 | - | -| 0x8104 | ask | - | Data[0]:Hour
0-23
Data[1]:Min
0-59
Data[2]:Sec
0-59 | 开启狗/设置喂狗周期 | - | -| 0x0104 | - | reply | Data[0]:结果
0x01:成功
0x02:失败 | 开启狗/设置喂狗周期回复 | - | -| 0x8105 | ask | - | - | 关闭狗 | - | -| 0x0105 | - | reply | Data[0]:结果
0x01:成功
0x02:失败 | 关闭狗回复 | - | -| 0x8106 | ask | - | Data[0]:Hour
0-23
Data[1]:Min
0-59
Data[2]:Sec
0-59 | 设置间隔启动时间 | - | +| 0x8104 | ask | - | Data[2]:两字节的数字,单位s | 设置喂狗周期 | 0s代表关闭喂狗 修改为两个字节,单位s | +| 0x0104 | - | reply | Data[0]:结果
0x01:成功
0x02:失败 | 设置喂狗周期回复 | - | +| 0x8105 | ask | - | - | 关闭狗 | 取消 | +| 0x0105 | - | reply | Data[0]:结果
0x01:成功
0x02:失败 | 关闭狗回复 | 取消 | +| 0x8106 | ask | - | Data[0]:Hour
0-23
Data[1]:Min
0-59
Data[2]:Sec
0-59 | 设置间隔启动时间 | 定时启动 | | 0x0106 | - | reply | Data[0]:结果
0x01:成功
0x02:失败 | 设置间隔启动时间回复 | - | | 0x8107 | ask | - | Data[0]:Year
Data[1]:Mon
1-12
Data[2]:Day
0-31
Data[3]:Hour
0-23
Data[4]:Min
0-59
Data[5]:Sec
0-59 | 设置日期和时间 | - | | 0x0107 | - | reply | Data[0]:结果
0x01:成功
0x02:失败 | 设置日期和时间回复 | - | @@ -145,7 +145,12 @@ unsigned short calculate_check_sum(const unsigned char* pData, unsigned short le | 0x010B | - | reply | Data[0]:结果
0-100 | 获取光敏值回复 | 取消 | | ====== | === | ====== | ============================ | ==================== | ======= | | 0xC101 | reply | - | Data[0]:结果
0x01:成功
0x02:失败 | 发送启动模式回复 | - | -| 0x4101 | - | ask | Data[0]:启动模式
0x01:PIR启动
0x02:TEST启动
0x03:连拍启动
0x04:PIR延时启动
0x05:定时(间隔一定时间)启动
0x06:关机
0x07:低电关机
0x08:异常启动 | 发送启动模式 | 异常启动数据:Data[1]
0x00:喂狗异常启动
0x01:心跳异常启动 | -| 0xC102 | reply | - | - | 回复心跳包 | - | -| 0x4102 | - | ask | - | 发送心跳包 | - | +| 0x4101 | - | ask | Data[0]:启动模式
0x01:PIR启动
0x02:TEST启动
0x03:ON启动
0x04:连拍启动
0x05:PIR延时启动
0x06:定时(间隔一定时间)启动
0x07:关机
0x08:低电关机
0x09:异常启动 | 发送启动模式 | 异常启动数据:Data[1]
0x00:喂狗异常启动
0x01:超时异常启动 | +| 0xC102 | reply | - | - | 回复心跳包 | 取消 | +| 0x4102 | - | ask | - | 发送心跳包 | 取消 | +### 1.2.1. 名词解析 + +| 名词 | 解析 | +| ---- | ---- | +| 超时异常启动 | MCU给主控上电后(**非TEST启动**),不管主控是否正常喂狗,如果单次上电时长超过3min未关机,给主控断电重启一次。 | \ No newline at end of file