1103 lines
		
	
	
		
			45 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			1103 lines
		
	
	
		
			45 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| # 1. 设计文档
 | ||
| 
 | ||
| ## 1.1. 产品概述
 | ||
| 
 | ||
|   一款低功耗的IPC产品设计方案。
 | ||
| 
 | ||
| ### 1.1.1. 名词说明:
 | ||
| MCU:外接的单片机;
 | ||
| 小核:rk1106内置的单片机
 | ||
| 大核:rk1106 linux部分业务
 | ||
| 
 | ||
| ## 1.2. 结构设计
 | ||
| 1. 迷彩外观;
 | ||
| 2. 抽屉式电池箱组;
 | ||
| 3. 捆绑/相机支架安装方式;
 | ||
| 4. 可拓展4G模块;
 | ||
| 5. 户外防水等级?
 | ||
| 
 | ||
| ### 1.2.1. 结构
 | ||
| 
 | ||
| | 物料 | 备注 |
 | ||
| |----|----|
 | ||
| | 喇叭 | - |
 | ||
| | 麦克风 | - |
 | ||
| | 按键 | 恢复出厂<br>SD卡格式化<br>TEST拨键<br>硬件电源开关 |
 | ||
| | 指示灯 | RGB三色灯 |
 | ||
| | 红外灯 | 940nm |
 | ||
| | usb | TYPEC,充电 |
 | ||
| | 太阳能板 | - |
 | ||
| | 电池仓 | - |
 | ||
| | TF卡卡槽 | - |
 | ||
| | PIR | - |
 | ||
| 
 | ||
| ### 1.2.2. 配件
 | ||
| 
 | ||
| | 物料 | 备注 |
 | ||
| |----|----|
 | ||
| | 捆绑轧带 | - |
 | ||
| | 快充电池 | - |
 | ||
| | 快充适配器 | - |
 | ||
| 
 | ||
| ## 1.3. 硬件设计
 | ||
| 
 | ||
| ### 1.3.1. 关键外设
 | ||
| 1. 双摄像头;
 | ||
| 2. PIR sensor;
 | ||
| 3. IR leds;
 | ||
| 4. 电池(箱体);
 | ||
| 5. 电源开关;
 | ||
| 6. 复位按键:同步/复位/格式化;
 | ||
| 7. 功能按键:拍摄/cpu通电启动/
 | ||
| 8. tf card;
 | ||
| 9. usb接口;
 | ||
| 10. 光感传感器:白天/黑夜;
 | ||
| 11. 单色指示灯:设备状态(工作/WiFi连接/异常);
 | ||
| 
 | ||
| ## 1.4. 软件设计
 | ||
| 
 | ||
| ### 1.4.1. 多态单例设计模式
 | ||
| 
 | ||
|   多态单例模式包含两部分:抽象接口 + 抽象接口实例,代码基于抽象接口存在,业务基于抽象接口实例存在。
 | ||
| 
 | ||
| #### 1.4.1.1. 多态单例图示
 | ||
| 
 | ||
|   下述图示分别为:类图 / 依赖关系图 / 编译链接关系图
 | ||
| ```mermaid
 | ||
| classDiagram
 | ||
|     APP --> AbstractInterface:使用
 | ||
|     AbstractInterface <|.. Instance:实现
 | ||
|     应用 --> 抽象接口库:依赖
 | ||
|     抽象接口库 ..> 实例库:依赖
 | ||
|     main线程 --> 抽象接口代码库:链接
 | ||
|     main线程 --> 实例代码库:链接
 | ||
| ```
 | ||
| #### 1.4.1.2. 多态单例模块使用时序图
 | ||
| 
 | ||
|   在使用多态单例设计模式开发功能模块时,使用统一的命名规则:
 | ||
| * 抽象接口命名:xxx + Abstract,例如:libLogAbstract.a;
 | ||
| * 实例库命名:xxx + 具体实例名称,例如:libLogEasylogging.a;
 | ||
| 
 | ||
| **调用关系如下图**
 | ||
| ```mermaid
 | ||
| sequenceDiagram
 | ||
| User ->> +libLogAbstract.a:调用抽象接口
 | ||
| libLogAbstract.a --> +libLogEasylogging.a:实际调用实例接口
 | ||
| libLogEasylogging.a --> -libLogAbstract.a:return
 | ||
| libLogAbstract.a -->> -User:return
 | ||
| ```
 | ||
| **只有main函数实际调用实例库的实例化接口时,log功能才会生效。**
 | ||
| 
 | ||
| #### 1.4.1.3. 多态单例目录结构规范
 | ||
| 
 | ||
|   根据多态单例设计模式,指定使用多态单例模式开发的模块的源码目录结构,耦合思路清晰。
 | ||
| ```
 | ||
| └── Log // 多态单例模式模块的目录
 | ||
|     ├── include  // 多态单例模块对外暴露的头文件目录,抽象接口定义
 | ||
|     │   └── ILogAbstract.h
 | ||
|     ├── abstract // 多态单例模式抽象接口声明
 | ||
|     │   └── ILogAbstract.cpp
 | ||
|     └── src      // 多态单例接口实例代码,目录名称可根据实际功能定义
 | ||
|         ├── LogAstract.cpp
 | ||
|         └── LogAstract.h
 | ||
| ```
 | ||
|   构建时把abstract目录和src目录的源码分别编译成库,main线程根据实际需要链接并实例化即可。
 | ||
| 
 | ||
| #### 1.4.1.4. 混合多态单例
 | ||
| 
 | ||
|   多态单例的分类有C++版本多态单例,C语言版本多态单例,混合(C/C++)多态单例。混合多态单例的提出是由于纯C语言多态单例开发难度较高,纯C++语言的多态单例不适合底层(特指本文的分层结构中的适配层)接口为C++时,很多C语言代码调用困难。
 | ||
| 
 | ||
|   混合多态单例,内部多态实现使用C++,保留C++开发便捷性和易维护性(智能指针),对外同时提供C语言多态抽象接口和C++多态抽象接口,满足C/C++混编时易用性。最大特点是include文件夹里面会包含两个头文件。
 | ||
| 
 | ||
| ##### 1.4.1.4.1. 多态单例目录结构
 | ||
| ```
 | ||
| hal
 | ||
| ├── abstract // 抽象接口库的基础代码
 | ||
| │   ├── IHal.cpp
 | ||
| │   └── IHalCpp.cpp
 | ||
| ├── include
 | ||
| │   ├── IHalCpp.h  // C++抽象接口头文件
 | ||
| │   └── IHal.h     // C语言抽象接口头文件
 | ||
| └── src // 抽象接口实例库代码
 | ||
|     ├── Hal.c      // C语言接口实例
 | ||
|     ├── HalCpp.cpp // C++接口实例
 | ||
|     ├── HalCpp.h
 | ||
|     ├── Hal.h
 | ||
|     ├── HalMakePtr.cpp // 负责创建内部实例
 | ||
|     └── HalMakePtr.h
 | ||
| ```
 | ||
| 
 | ||
| #### 1.4.1.5. 多态单例总结:
 | ||
| 
 | ||
| 1. 应用代码只使用抽象接口,禁止直接依赖实例代码;
 | ||
| 2. 应用代码只有在main线程初始化时实例化实例模块即可;
 | ||
| 3. 多态单例模块由两个库组成,一个是抽象接口库,一个是实例代码库,支持静态多态和动态多态;
 | ||
| 
 | ||
| ### 1.4.2. 产品业务功能设计
 | ||
| 
 | ||
|   基于芯片大小核架构的启动设计。
 | ||
| 
 | ||
| #### 1.4.2.1. 白/黑切换状态启动
 | ||
| 
 | ||
|   由外置单片机检测光敏adc,判断由白天切换到黑夜或者黑夜切换到白天时,主动给主控上电,主控上电后会校验并保存新的环境参数,以下次正常PIR启动时,可以避免ircut耗时快速收敛第一帧,最大程度实现快启功能。
 | ||
| 
 | ||
| **启动时序图**
 | ||
| 
 | ||
| ```mermaid
 | ||
| sequenceDiagram
 | ||
| participant MCU
 | ||
| participant 小核
 | ||
| participant 大核
 | ||
| loop 光敏检测
 | ||
|     MCU ->> MCU:定时唤醒(定时时间待定)
 | ||
|     opt 光敏>>>黑夜状态
 | ||
|     note over MCU:由外置单片机点亮红外补光灯
 | ||
|         MCU ->> MCU:点亮红外灯
 | ||
|     end
 | ||
|     opt 光敏>>>黑/白切换
 | ||
|         MCU ->> 小核:上电
 | ||
|         activate 小核
 | ||
|             note over 小核:根据上次启动的ircut切换条件初始化ircut IO<br>本次启动上次的切换条件是异常的
 | ||
|             小核 ->> 小核:ircut切换-消耗0ms
 | ||
|             小核 ->> 小核:Sensor初始化
 | ||
|             小核 --> 大核:Sensor初始化完成-100ms
 | ||
|         deactivate 小核
 | ||
|             activate 大核
 | ||
|                 大核 ->> 大核:内核快启抓拍(1P/3P)-200ms
 | ||
|                 大核 ->> 大核:内核启动(文件系统/挂载sd卡)-?ms
 | ||
|                 大核 ->> 大核:启动脚本启动APP-?ms
 | ||
|                 大核 ->> +MCU:获取启动模式
 | ||
|                     note over 大核:大核启动后,需要通过串口获取启动模式,<br>来执行后续的任务
 | ||
|                 MCU -->> -大核:回复启动模式
 | ||
|                 opt 黑/白切换状态
 | ||
|                     大核 ->> +MCU:获取黑/白状态
 | ||
|                         note over 大核:大核启动后,需要通过串口获取启动模式,<br>来执行后续的任务
 | ||
|                     MCU -->> -大核:回复黑或者白
 | ||
|                     opt 黑/白状态不符合抓拍的初始化参数
 | ||
|                         大核 ->> 大核:ircut重新切换
 | ||
|                         大核 ->> 大核:重新初始化sensor参数
 | ||
|                     end
 | ||
|                     大核 ->> MCU:关机
 | ||
|                     MCU ->> 大核:断电
 | ||
|                 end
 | ||
|             deactivate 大核
 | ||
|     end
 | ||
| end
 | ||
| ```
 | ||
| 
 | ||
| #### 1.4.2.2. 红外触发状态启动(正常工作快启)
 | ||
| 
 | ||
|   红外触发启动作为产品正常工作时最经常最重要的启动状态。启动后快速抓拍/录像,快速关机。
 | ||
| 
 | ||
| 1. 为保证快启速度,IRCUT需要业务设计进行提前切换;
 | ||
| 2. 每次启动抓拍/录像完,需要校验IRCUT状态,保证sensor初始化参数和环境相匹配;
 | ||
| 3. 如果发生sensor初始化参数和光照环境不匹配,需要重新初始化sesor并补拍;
 | ||
| 
 | ||
| **启动时序图**
 | ||
| 
 | ||
| ```mermaid
 | ||
| sequenceDiagram
 | ||
| participant MCU
 | ||
| participant 小核
 | ||
| participant 大核
 | ||
| MCU ->> MCU:PIR中断唤醒
 | ||
| opt 光敏>>>黑夜状态
 | ||
| note over MCU:由外置单片机点亮红外补光灯
 | ||
|     MCU ->> MCU:点亮红外灯
 | ||
| end
 | ||
| opt PIR信号触发
 | ||
|     alt 主控未开机
 | ||
|         MCU ->> 小核:上电
 | ||
|         activate 小核
 | ||
|             note over 小核:根据上次启动的ircut切换条件初始化ircut IO<br>消耗0ms是由于ircut IO会提前切换好
 | ||
|             小核 ->> 小核:ircut切换-消耗0ms
 | ||
|             小核 ->> 小核:Sensor初始化
 | ||
|             小核 --> 大核:Sensor初始化完成-100ms
 | ||
|         deactivate 小核
 | ||
|             activate 大核
 | ||
|                 大核 ->> 大核:内核快启抓拍(1P/3P)-200ms
 | ||
|                 大核 ->> 大核:内核启动(文件系统/挂载sd卡)-?ms
 | ||
|                 大核 ->> 大核:启动脚本启动APP-?ms
 | ||
|                 大核 ->> +MCU:获取启动模式
 | ||
|                     note over 大核:大核启动后,需要通过串口获取启动模式,<br>来执行后续的任务
 | ||
|                 MCU -->> -大核:回复启动模式
 | ||
|                 opt PIR触发状态
 | ||
|                     大核 ->> +MCU:获取黑/白状态
 | ||
|                         note over 大核:大核启动后,需要通过串口获取启动模式,<br>来执行后续的任务
 | ||
|                     MCU -->> -大核:回复黑或者白
 | ||
|                     alt sensor初始化参数和环境参数匹配
 | ||
|                         note over 大核:环境参数未发生变化时,可直接保存快启的抓拍
 | ||
|                         大核 ->> 大核:保存到sd卡-?ms
 | ||
|                     else sensor初始化参数和环境参数不匹配
 | ||
|                         note over 大核:环境参数发生变化时,需要重新初始化sensor并补拍
 | ||
|                         大核 ->> 大核:ircut重新切换
 | ||
|                         大核 ->> 大核:重新初始化sensor参数
 | ||
|                         大核 ->> 大核:重新抓拍/录像
 | ||
|                         大核 ->> 大核:保存到sd卡-?ms
 | ||
|                     end
 | ||
|                 end
 | ||
|                 alt TEST拨键-OFF
 | ||
|                     大核 ->> MCU:关机
 | ||
|                     MCU ->> 小核:断电
 | ||
|                     MCU ->> 大核:断电
 | ||
|                 else TEST拨键-ON
 | ||
|                     opt 超时关机
 | ||
|                         大核 ->> MCU:关机
 | ||
|                         MCU ->> 小核:断电
 | ||
|                         MCU ->> 大核:断电
 | ||
|                     end
 | ||
|                 end
 | ||
|             deactivate 大核
 | ||
|     else 主控已经开机
 | ||
|         MCU ->> +大核:发送抓拍指令
 | ||
|             大核 ->> 大核:抓拍
 | ||
|             大核 ->> MCU:回复抓拍
 | ||
|             大核 ->> 大核:保存抓拍
 | ||
|         大核 ->> -MCU:关机指令
 | ||
|         MCU ->> 大核:断电
 | ||
|     end
 | ||
| end
 | ||
| ```
 | ||
| 
 | ||
| #### 1.4.2.3. 定时触发状态启动
 | ||
| 
 | ||
| **定时触发状态启动时序图**
 | ||
| 
 | ||
| ```mermaid
 | ||
| sequenceDiagram
 | ||
| participant MCU
 | ||
| participant 小核
 | ||
| participant 大核
 | ||
| MCU ->> MCU:定时中断唤醒
 | ||
| opt 光敏>>>黑夜状态
 | ||
| note over MCU:由外置单片机点亮红外补光灯
 | ||
|     MCU ->> MCU:点亮红外灯
 | ||
| end
 | ||
| opt 根据定时参数上电
 | ||
|     MCU ->> 小核:上电
 | ||
|     activate 小核
 | ||
|         note over 小核:根据上次启动的ircut切换条件初始化ircut IO<br>消耗0ms是由于ircut IO会提前切换好
 | ||
|         小核 ->> 小核:ircut切换-消耗0ms
 | ||
|         小核 ->> 小核:Sensor初始化
 | ||
|         小核 --> 大核:Sensor初始化完成-100ms
 | ||
|     deactivate 小核
 | ||
|         activate 大核
 | ||
|             大核 ->> 大核:内核快启抓拍(1P/3P)-200ms
 | ||
|             大核 ->> 大核:内核启动(文件系统/挂载sd卡)-?ms
 | ||
|             大核 ->> 大核:启动脚本启动APP-?ms
 | ||
|             大核 ->> +MCU:获取启动模式
 | ||
|                 note over 大核:大核启动后,需要通过串口获取启动模式,<br>来执行后续的任务
 | ||
|             MCU -->> -大核:回复启动模式
 | ||
|             opt 定时启动状态
 | ||
|                 大核 ->> +MCU:获取黑/白状态
 | ||
|                     note over 大核:大核启动后,需要通过串口获取启动模式,<br>来执行后续的任务
 | ||
|                 MCU -->> -大核:回复黑或者白
 | ||
|                 alt sensor初始化参数和环境参数匹配
 | ||
|                     note over 大核:环境参数未发生变化时,可直接保存快启的抓拍
 | ||
|                     大核 ->> 大核:保存到sd卡-?ms
 | ||
|                 else sensor初始化参数和环境参数不匹配
 | ||
|                     note over 大核:环境参数发生变化时,需要重新初始化sensor并补拍
 | ||
|                     大核 ->> 大核:ircut重新切换
 | ||
|                     大核 ->> 大核:重新初始化sensor参数
 | ||
|                     大核 ->> 大核:重新抓拍/录像
 | ||
|                     大核 ->> 大核:保存到sd卡-?ms
 | ||
|                 end
 | ||
|             end
 | ||
|             note over 大核:定时状态启动抓拍完直接关机
 | ||
|             大核 ->> MCU:关机
 | ||
|             MCU ->> 小核:断电
 | ||
|             MCU ->> 大核:断电
 | ||
|         deactivate 大核
 | ||
| end
 | ||
| ```
 | ||
| 
 | ||
| #### 1.4.2.4. 设置/调试状态启动
 | ||
| 
 | ||
|   特殊的启动状态,可以较长时间通电完成其它功能,期间可供用户完成相关调试和参数设置,此时功耗较高。超时进入工作模式。
 | ||
| 
 | ||
| 1. 设置状态按键触发CPU上电,首先进入设置状态启动,5分钟后自动切换到工作状态。
 | ||
| 
 | ||
| **设置状态启动时序图**
 | ||
| 
 | ||
| ```mermaid
 | ||
| sequenceDiagram
 | ||
| participant MCU
 | ||
| participant 小核
 | ||
| participant 大核
 | ||
| MCU ->> MCU:待机
 | ||
| opt 光敏>>>黑夜状态
 | ||
| note over MCU:由外置单片机点亮红外补光灯
 | ||
|     MCU ->> MCU:点亮红外灯
 | ||
| end
 | ||
| opt TEST拨键-ON
 | ||
|     MCU ->> 小核:上电
 | ||
|     activate 小核
 | ||
|         MCU ->> 大核:上电
 | ||
|         activate 大核
 | ||
|         note over 小核:根据上次启动的ircut切换条件初始化ircut IO<br>消耗0ms是由于ircut IO会提前切换好
 | ||
|         小核 ->> 小核:ircut切换-消耗0ms
 | ||
|         小核 ->> 小核:Sensor初始化
 | ||
|         小核 --> 大核:Sensor初始化完成-100ms
 | ||
|     deactivate 小核
 | ||
|             大核 ->> 大核:内核启动(文件系统/挂载sd卡)-?ms
 | ||
|             大核 ->> 大核:启动脚本启动APP-?ms
 | ||
|             大核 ->> +MCU:获取启动模式
 | ||
|                 note over 大核:大核启动后,需要通过串口获取启动模式,<br>来执行后续的任务
 | ||
|             MCU -->> -大核:回复启动模式
 | ||
|             opt TEST状态
 | ||
|                 大核 ->> +MCU:获取黑/白状态
 | ||
|                     note over 大核:大核启动后,需要通过串口获取启动模式,<br>来执行后续的任务
 | ||
|                 MCU -->> -大核:回复黑或者白
 | ||
|                 opt sensor初始化参数和环境参数不匹配
 | ||
|                     note over 大核:环境参数发生变化时,需要重新初始化sensor并补拍
 | ||
|                     大核 ->> 大核:ircut重新切换
 | ||
|                     大核 ->> 大核:重新初始化sensor参数
 | ||
|                 end
 | ||
|                 alt WiFi链接
 | ||
|                     大核 ->> 大核:常通电待机
 | ||
|                 else 无WiFi连接/无操作
 | ||
|                     opt 超时
 | ||
|                         大核 ->> MCU:关机
 | ||
|                         MCU ->> 小核:断电
 | ||
|                         MCU ->> 大核:断电
 | ||
|                     end
 | ||
|                 end
 | ||
|             end
 | ||
|         deactivate 大核
 | ||
| end
 | ||
| ```
 | ||
| 
 | ||
| #### 1.4.2.5. 厂测状态启动
 | ||
| 
 | ||
|   生产测试状态触发:使用tf card配置文件触发生产测试状态;
 | ||
| 
 | ||
| **厂测状态启动时序图**
 | ||
| 
 | ||
| ```mermaid
 | ||
| sequenceDiagram
 | ||
| participant MCU
 | ||
| participant 小核
 | ||
| participant 大核
 | ||
| MCU ->> MCU:物理上电
 | ||
| MCU ->> 小核:上电
 | ||
|     activate 小核
 | ||
|         MCU ->> 大核:上电
 | ||
|         activate 大核
 | ||
|             小核 ->> 小核:Sensor初始化
 | ||
|             小核 --> 大核:Sensor初始化完成-100ms
 | ||
|     deactivate 小核
 | ||
|             大核 ->> 大核:内核启动(文件系统/挂载sd卡)-?ms
 | ||
|             大核 ->> 大核:启动脚本启动APP-?ms
 | ||
|             alt TEST拨键-ON
 | ||
|                 alt tf card厂测配置文件存在
 | ||
|                     大核 ->> 大核:常通电待机
 | ||
|                 else tf card厂测配置文件不存在
 | ||
|                     opt 超时
 | ||
|                         大核 ->> MCU:关机
 | ||
|                         MCU ->> 小核:断电
 | ||
|                         MCU ->> 大核:断电
 | ||
|                     end
 | ||
|                 end
 | ||
|             else TEST拨键-OFF
 | ||
|                 alt tf card厂测配置文件存在
 | ||
|                     大核 ->> 大核:常通电待机
 | ||
|                 else tf card厂测配置文件不存在
 | ||
|                     大核 ->> MCU:关机
 | ||
|                     MCU ->> 小核:断电
 | ||
|                     MCU ->> 大核:断电
 | ||
|                 end
 | ||
|             end
 | ||
|         deactivate 大核
 | ||
| ```
 | ||
| 
 | ||
| #### 1.4.2.6. 快启时序时间消耗
 | ||
| 
 | ||
| ```mermaid
 | ||
| sequenceDiagram
 | ||
| participant MCU
 | ||
| participant 小核
 | ||
| participant 大核
 | ||
| MCU ->> MCU:PIR中断唤醒
 | ||
| note right of MCU:设此时为时间轴0ms
 | ||
| MCU ->> 小核:上电
 | ||
| MCU ->> 大核:上电
 | ||
| activate MCU
 | ||
| activate 小核
 | ||
| activate 大核
 | ||
| note right of 大核:竞品时间12ms
 | ||
|     opt 光敏>>>黑夜状态
 | ||
|         note over MCU:由外置单片机点亮红外补光灯
 | ||
|         MCU ->> MCU:点亮红外灯
 | ||
|     end
 | ||
| deactivate MCU
 | ||
|     opt PIR信号触发
 | ||
|         alt 主控未开机
 | ||
|                 note over 小核:根据上次启动的ircut切换条件初始化ircut IO<br>消耗0ms是由于ircut IO会提前切换好
 | ||
|                 note right of 大核:竞品在CPU启动后,获取MCU的光敏值<br>再切ircut和打开红外灯-时间168ms
 | ||
|                 小核 ->> 小核:ircut切换-消耗0ms
 | ||
|                 小核 ->> 小核:Sensor初始化
 | ||
|                 小核 --> 大核:Sensor初始化完成-100ms
 | ||
| deactivate 小核
 | ||
|                 activate 大核
 | ||
|                     大核 ->> 大核:内核快启抓拍(1P/3P)-200ms
 | ||
|                     note right of 大核:竞品第一帧时间350ms
 | ||
|                     大核 ->> 大核:内核启动(文件系统/挂载sd卡)-?ms
 | ||
|                     大核 ->> 大核:启动脚本启动APP-?ms
 | ||
|                 deactivate 大核
 | ||
|         end
 | ||
|     end
 | ||
| deactivate 大核
 | ||
| ```
 | ||
| 
 | ||
| ### 1.4.3. 根据软件模块作用域分层
 | ||
| 
 | ||
| #### 1.4.3.1. 应用层(application)
 | ||
| 
 | ||
| ##### 1.4.3.1.1. 应用层概述
 | ||
| 
 | ||
|   应用层负责处理产品级的复杂业务关系,是产品功能的直接体现,应用层模块全部使用C++接口的多态单例模式设计,各模块之间可以互相调用接口,应用层各库可以随意任意调用中间件或者工具类接口。
 | ||
| 
 | ||
| ##### 1.4.3.1.2. 网络服务模块
 | ||
| 
 | ||
| ###### 1.4.3.1.2.1. 网络服务概述
 | ||
| 
 | ||
|   根据产品联网属性,网络服务模块分为不联网 / 联网(B端)/ 联网(自研)三个多态属性。联网时,IPC的图片 / 视频资源通过网络服务器进行管理。
 | ||
| 
 | ||
| 1. 不联网版本:网络服务模块不实例化即可;
 | ||
| 2. 联网(B端):媒体资源由三方服务器管理;
 | ||
| 3. 联网(自研):媒体资源由自研服务器管理;
 | ||
| 
 | ||
| ###### 1.4.3.1.2.2. 网络服务多态设计模式
 | ||
| 
 | ||
|   通过构建配置文件选择需要实例化的网络服务模块代码。
 | ||
| 
 | ||
| ##### 1.4.3.1.3. 相机任务管理
 | ||
| 
 | ||
|   相机主业务逻辑使用状态机机制进行管理。
 | ||
| 
 | ||
| ###### 1.4.3.1.3.1. 任务状态
 | ||
| 
 | ||
|   任务状态是指相机启动需要执行的任务,可能是拍照 / 视频,可能是其它任务。
 | ||
| 
 | ||
| **例如:**
 | ||
| 1. 移动物体侦测启动;
 | ||
| 2. 定时启动拍照 / 录像;
 | ||
| 3. 测试启动;
 | ||
| 
 | ||
| ###### 1.4.3.1.3.2. 状态机设计
 | ||
| 
 | ||
| ```mermaid
 | ||
| stateDiagram-v2
 | ||
| [*] --> TopState
 | ||
| TopState --> PowerOff
 | ||
| TopState --> MSDCState
 | ||
| TopState --> DeviceAbnormal
 | ||
| TopState --> MissionState
 | ||
| MissionState --> 存储管理
 | ||
| 存储管理 --> EMMC
 | ||
| 存储管理 --> SD卡
 | ||
| SD卡 --> 插卡
 | ||
| SD卡 --> 拔卡
 | ||
| SD卡 --> 卡异常
 | ||
| MissionState --> 网络管理
 | ||
| 网络管理 --> 联网
 | ||
| 联网 --> 上传文件
 | ||
| 网络管理 --> 未联网
 | ||
| MissionState --> 直播
 | ||
| MissionState --> 4G管理
 | ||
| 4G管理 --> Sim卡初始化
 | ||
| 4G管理 --> 注网状态
 | ||
| MissionState --> Upgrade
 | ||
| ```
 | ||
| 
 | ||
| ###### 1.4.3.1.3.3. 任务状态获取启动
 | ||
| 
 | ||
|   应用程序运行后,首先需要知道主控是由于何种任务被唤醒,然后根据任务来执行相应的功能代码;
 | ||
| 
 | ||
| **时序图**
 | ||
| 
 | ||
| ```mermaid
 | ||
| sequenceDiagram
 | ||
| participant MCU
 | ||
| participant 大核
 | ||
| MCU ->> MCU:待机
 | ||
| opt MCU上电
 | ||
|     MCU ->> 大核:上电
 | ||
|     activate 大核
 | ||
|         大核 ->> 大核:系统初始化
 | ||
|         大核 ->> 大核:启动脚本拉起APP
 | ||
|         大核 ->> +MCU:读取启动任务
 | ||
|         MCU -->> -大核:return
 | ||
|         alt PIR触发
 | ||
|             大核 ->> 大核:APP初始化
 | ||
|             大核 ->> 大核:抓拍并保存
 | ||
|         else 定时
 | ||
|             大核 ->> 大核:APP初始化
 | ||
|             大核 ->> 大核:抓拍并保存
 | ||
|         else TEST
 | ||
|             大核 ->> 大核:APP初始化
 | ||
|             大核 ->> 大核:待机
 | ||
|         end
 | ||
|     deactivate 大核
 | ||
| end
 | ||
| ```
 | ||
| 
 | ||
| #### 1.4.3.2. 中间件(middleware)
 | ||
| 
 | ||
| ##### 1.4.3.2.1. 中间件概述
 | ||
| 
 | ||
|   一些相对中性的业务功能库,这些库可以提供给不同的产品需求使用,在应用层不同的调用方式可实现不同的产品功能。中间件只能被应用层调用或者向下调用适配层或者调用工具库,中间件各模块之间不能互相调用。中间件库接口可以使用C或者C++接口。
 | ||
| 
 | ||
| ##### 1.4.3.2.2. 设备管理模块
 | ||
| 
 | ||
|   设备,统指Linux的设备节点,应用层唯一的硬件设备接口库。包含灯 / 按键 / GPIO / SD卡 / 串口 / USB等。
 | ||
| 
 | ||
| ##### 1.4.3.2.3. 相机管理模块
 | ||
| 
 | ||
|   应用层唯一的摄像头接口库。
 | ||
| 
 | ||
| ##### 1.4.3.2.4. MCU管理模块
 | ||
| 
 | ||
|   MCU通信接口库,一般使用串口进行通信,需要考虑多态其它接口(例如I2C),考虑多态协议数据结构。MCU负责管理外设的电源控制 / 充当硬狗等。
 | ||
| 
 | ||
| ###### 1.4.3.2.4.1. MCU管理模块设计模式
 | ||
| 
 | ||
|   使用C++接口的多态单例模式。
 | ||
| 
 | ||
| 基本功能:
 | ||
| 
 | ||
| 1. 使用utils当中的串口功能模块,支持多态切换到其它串口功能模块;
 | ||
| 2. 设置MCU管理的监视器monitor,用于回调处理MCU接受到的业务事件;
 | ||
| 3. 通信协议不暴露,内部处理基于协议的数据解析 / 组包;
 | ||
| 4. 通信协议支持多态拓展,通信协议独立成库;
 | ||
| 
 | ||
| ##### 1.4.3.2.5. MCU协议模块
 | ||
| 
 | ||
|   负责对MCU协议进行封包/解包,负责协议的多态替换。协议数据统一使用网络字节序(大端字节序)。
 | ||
| 
 | ||
| ###### 1.4.3.2.5.1. 协议格式
 | ||
| 
 | ||
| | 协议头 | 流水号 | 命令字 | 长度 | 数据段 | 校验码 |
 | ||
| |----|----|----|----|----|----|
 | ||
| | 2字节<br>0xFAC1 | 4字节 | 2字节 | 2字节 | - | 2字节 |
 | ||
| 
 | ||
| **流水号**
 | ||
| 
 | ||
|   流水号用于强绑定问答型协议的发送数据和回复数据,回复者原数据回传即可。例如:
 | ||
| 
 | ||
| ```
 | ||
| unsigned char ASK_IPC_MISSION[] = {0xFA, 0xC1, 0x00, 0x00, 0x00, 0x01, 0x81, 0x01, 0x00, 0x0C, 0x71, 0x88};
 | ||
| unsigned char REPLY_IPC_MISSION[] = {0xFA, 0xC1, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x0D, 0x01, 0xAA, 0x89};
 | ||
| ```
 | ||
| 
 | ||
|   流水号管理发送方和接收方互相独立,各自往外发的协议中流水号存在重复的可能,接收方直接复制回传即可。
 | ||
| 
 | ||
|   流水号必须大于等于1,0用于代码初始化值,代码意义上表示无效的流水号。
 | ||
| 
 | ||
| **协议收发匹配逻辑**
 | ||
|   协议发送时,附带自管理的流水号,对端回复时,根据流水号绑定发送的协议,为了避免对端回复时,流水号错误导致的业务逻辑错乱,本端除了匹配流水号,还需要根据协议匹配回复的命令字,保证回复内容的有效匹配。如果流水号和命令字无法同时匹配,该回复的数据包被丢弃。
 | ||
| 
 | ||
| **校验码算法**
 | ||
| 
 | ||
|   校验码算法使用ModBus CRC16方法计算。
 | ||
| 
 | ||
| **参考代码(查表法)**
 | ||
| 
 | ||
| ```
 | ||
| /* Table of CRC values for high–order byte */
 | ||
| unsigned char chCRCHi[] ={
 | ||
|     0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 
 | ||
|     0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
 | ||
|     0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 
 | ||
|     0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 
 | ||
|     0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 
 | ||
|     0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 
 | ||
|     0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 
 | ||
|     0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
 | ||
|     0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 
 | ||
|     0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 
 | ||
|     0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 
 | ||
|     0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 
 | ||
|     0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 
 | ||
|     0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 
 | ||
|     0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 
 | ||
|     0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 
 | ||
|     0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 
 | ||
|     0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
 | ||
|     0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 
 | ||
|     0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
 | ||
|     0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 
 | ||
|     0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 
 | ||
|     0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 
 | ||
|     0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
 | ||
|     0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 
 | ||
|     0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
 | ||
| };
 | ||
| 
 | ||
| /* Table of CRC values for low–order byte */
 | ||
| unsigned char chCRCLo[] ={
 | ||
|     0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 
 | ||
|     0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 
 | ||
|     0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 
 | ||
|     0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 
 | ||
|     0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, 
 | ||
|     0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, 
 | ||
|     0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 
 | ||
|     0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 
 | ||
|     0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 
 | ||
|     0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 
 | ||
|     0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 
 | ||
|     0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, 
 | ||
|     0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 
 | ||
|     0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 
 | ||
|     0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 
 | ||
|     0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 
 | ||
|     0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 
 | ||
|     0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, 
 | ||
|     0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 
 | ||
|     0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 
 | ||
|     0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 
 | ||
|     0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 
 | ||
|     0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 
 | ||
|     0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, 
 | ||
|     0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 
 | ||
|     0x43, 0x83, 0x41, 0x81, 0x80, 0x40
 | ||
| };
 | ||
| /**
 | ||
|  * @brief       计算校验和
 | ||
|  * 
 | ||
|  * @param       pData 数据指针
 | ||
|  * @param       length 数据长度
 | ||
|  * @return      unsigned short 
 | ||
|  */
 | ||
| unsigned short calculate_check_sum(const unsigned char* pData, unsigned short length)
 | ||
| {
 | ||
|     unsigned char CRCHi = 0xFF;
 | ||
|     unsigned char CRCLo = 0xFF;
 | ||
|     int uIndex;
 | ||
|     while (length--)
 | ||
|     {
 | ||
|         uIndex = CRCHi ^ *pData++;
 | ||
|         CRCHi = CRCLo ^ chCRCHi[uIndex];
 | ||
|         CRCLo = chCRCLo[uIndex];
 | ||
|     }
 | ||
|     return (CRCHi << 8 | CRCLo);
 | ||
| }
 | ||
| ```
 | ||
| 
 | ||
| ###### 1.4.3.2.5.2. 协议内容
 | ||
| 
 | ||
| **基本描述**
 | ||
| 1. 大于等于0x8000的命令字由CPU发给MCU;
 | ||
| 2. 小于0x8000的命令字由MCU发给CPU;
 | ||
| 3. 大于0x0801而小于0xC101的命令由CPU主动发送给MCU,大于等于0xC101的命令由CPU回复发送给MCU;
 | ||
| 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:低电关机 | 回复启动模式 | - |
 | ||
| | 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 | 设置间隔启动时间 | - |
 | ||
| | 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:失败 | 设置日期和时间回复 | - |
 | ||
| | 0x8108 | ask | - | Data[0]:灵敏度<br>0-9 | 设置PIR灵敏度 | - |
 | ||
| | 0x0108 | - | reply | Data[0]:结果<br>0x01:成功<br>0x02:失败 | 设置PIR灵敏度回复 | - |
 | ||
| | 0x8109 | ask | - | Data[0]:Hour<br>0-23<br>Data[1]:Min<br>0-59<br>Data[2]:Sec<br>0-59 | 设置连拍间隔 | - |
 | ||
| | 0x0109 | - | reply | Data[0]:结果<br>0x01:成功<br>0x02:失败 | 设置连拍间隔回复 | - |
 | ||
| | 0x810A | ask | - | Data[0]:控制模式<br>0-关闭红外灯<br>1-开启红外灯 | 红外灯控制 | - |
 | ||
| | 0x010A | - | reply | Data[0]:结果<br>0x01:成功<br>0x02:失败 | 红外灯控制回复 | - |
 | ||
| | 0x810B | ask | - | - | 获取光敏值 | - |
 | ||
| | 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:低电关机 | 发送启动模式 | - |
 | ||
| 
 | ||
| ##### 1.4.3.2.6. IPC配置库
 | ||
| 
 | ||
|   负责管理IPC产品相关的配置数据。
 | ||
| 
 | ||
| ###### 1.4.3.2.6.1. IPC配置库设计模式
 | ||
| 
 | ||
|   使用多态单例设计模式,对外提供C语言接口,内部不局限使用C或者C++。
 | ||
| 
 | ||
| **基本功能**
 | ||
| 
 | ||
| 1. 敏感数据(例如:账号 / 密码)需要加密处理;
 | ||
| 2. 读到内存使用二进制数据,缓存到数据结构体;
 | ||
| 3. 调用utils工具里面的配置库,对配置文件进行读 / 写;
 | ||
| 4. 使用二进制结构体 + 明文配置文件结合的模式,既可减少内存消耗,又可以规避二进制数据升级迭代数据匹配困难问题;
 | ||
| 5. 使用枚举方式管理IPC配置数据定义,当使用纯16进制保存数据时,可不链接utils工具里面的配置库,直接保存16进制数据到文件系统即可;
 | ||
| 6. 应用程序全局唯一可以操作IPC配置文件的库,保证配置文件正确读写;
 | ||
| 
 | ||
| ###### 1.4.3.2.6.2. IPC配置库类图
 | ||
| ```mermaid
 | ||
| classDiagram
 | ||
|     i_ipc_config <.. ipc_config:实现
 | ||
|     ipc_config --> i_config_manager:依赖
 | ||
|     ipc_config --> IHal:依赖
 | ||
|     i_config_manager <.. config_manager:实现
 | ||
|     config_manager --> libconfig开源库:依赖
 | ||
| ```
 | ||
| 
 | ||
| ###### 1.4.3.2.6.3. 关键业务时序图
 | ||
| 
 | ||
|   **时序图会忽略抽象接口直接使用实例接口表示。**
 | ||
| 
 | ||
| * IPC配置库初始化 / 解初始化
 | ||
| ```mermaid
 | ||
| sequenceDiagram
 | ||
| participant User
 | ||
| participant ipc_config
 | ||
| participant i_config
 | ||
| participant IHal
 | ||
| User ->> +ipc_config:初始化
 | ||
|     ipc_config ->> +IHal:获取文件系统路径
 | ||
|     IHal -->> -ipc_config:return
 | ||
|     ipc_config ->> +i_config:打开配置文件
 | ||
|     i_config -->> -ipc_config:return
 | ||
|     alt 打开成功
 | ||
|         rect rgba(255,220,200,1)
 | ||
|             loop 读取所有数据到IPC数据结构体
 | ||
|                 ipc_config ->> +i_config:读取一个数据到IPC数据结构体
 | ||
|                 i_config -->> -ipc_config:return
 | ||
|                 rect rgba(255,255,200,1)
 | ||
|                     opt 读取失败
 | ||
|                         ipc_config ->> ipc_config:生成默认数据
 | ||
|                         ipc_config ->> +i_config:设置默认数据
 | ||
|                         i_config ->> -ipc_config:return
 | ||
|                     end
 | ||
|                 end
 | ||
|             end
 | ||
|             ipc_config ->> +i_config:关闭配置文件
 | ||
|             i_config -->> -ipc_config:return
 | ||
|         end
 | ||
|     else 打开失败
 | ||
|         rect rgba(255,200,200,1)
 | ||
|             ipc_config ->> ipc_config:生产默认数据
 | ||
|             ipc_config ->> +i_config:创建配置文件
 | ||
|             i_config -->> -ipc_config:return
 | ||
|             ipc_config ->> +i_config:设置默认数据
 | ||
|             i_config -->> -ipc_config:return
 | ||
|             ipc_config ->> +i_config:关闭配置文件
 | ||
|             i_config -->> -ipc_config:return
 | ||
|         end
 | ||
|     end
 | ||
| ipc_config -->> -User:return
 | ||
| User ->> +ipc_config:解初始化
 | ||
|     ipc_config ->> ipc_config:释放内存中的数据
 | ||
| ipc_config -->> -User:return
 | ||
| ```
 | ||
| 
 | ||
| * 读 / 写(修改)数据
 | ||
| 
 | ||
| ```mermaid
 | ||
| sequenceDiagram
 | ||
| participant User
 | ||
| participant ipc_config
 | ||
| User ->> +ipc_config:读取数据
 | ||
|     ipc_config ->> ipc_config:返回内存保存的数据
 | ||
| ipc_config -->> -User:return
 | ||
| User ->> +ipc_config:修改数据
 | ||
|     ipc_config ->> ipc_config:修改内存保存的数据
 | ||
| ipc_config -->> -User:return
 | ||
| ```
 | ||
| 
 | ||
| * 保存数据
 | ||
| 
 | ||
| 
 | ||
| ```mermaid
 | ||
| sequenceDiagram
 | ||
| participant User
 | ||
| participant ipc_config
 | ||
| participant i_config
 | ||
| User ->> +ipc_config:保存
 | ||
|     ipc_config ->> +i_config:打开配置文件
 | ||
|     i_config -->> -ipc_config:return
 | ||
|     ipc_config ->> +i_config:同步数据
 | ||
|     i_config -->> -ipc_config:return
 | ||
|     ipc_config ->> +i_config:保存配置文件
 | ||
|     i_config -->> -ipc_config:return
 | ||
|     ipc_config ->> +i_config:关闭配置文件
 | ||
|     i_config -->> -ipc_config:return
 | ||
| ipc_config -->> -User:return
 | ||
| ```
 | ||
| 
 | ||
| 
 | ||
| ##### 1.4.3.2.7. 高级配置库
 | ||
| 
 | ||
|   对配置库的二级封装,提供更便捷的功能服务,例如:可以监控文件的修改事件 / 可以直接捕获某个配置文件或者数据的操作对象。
 | ||
| 
 | ||
| ###### 1.4.3.2.7.1. 高级配置库设计
 | ||
| 
 | ||
|   对外暴露C++接口,使用多态单例设计模式。
 | ||
| 
 | ||
| ##### 1.4.3.2.8. 状态机管理
 | ||
| 
 | ||
|   提供实现状态机管理机制C++接口,使用鸿蒙状态机开源源码进行改造封装。
 | ||
| 
 | ||
| ###### 1.4.3.2.8.1. 状态机管理设计模式
 | ||
| 
 | ||
|   使用多态单例设计模式,暂定使用鸿蒙状态机开源代码改造实现,后续可替换其它源码或者自研代码。
 | ||
| 
 | ||
| ##### 1.4.3.2.9. 文件数据库
 | ||
| 
 | ||
|   文件数据库负责管理设备的媒体资源(图片 / 视频等)。
 | ||
| 
 | ||
| ###### 1.4.3.2.9.1. 文件数据设计模式
 | ||
| 
 | ||
|   使用混合多态单例模式开发。
 | ||
| 
 | ||
| ###### 1.4.3.2.9.2. 开源库选型
 | ||
| 
 | ||
|   sqlite3开源库,编译成工具类库提供给文件数据库使用。
 | ||
| 
 | ||
| ###### 1.4.3.2.9.3. 基本功能和业务需求
 | ||
| 
 | ||
| 1. 对媒体资源文件的增删改查处理;
 | ||
| 2. 记录媒体资源文件的生成时间,任务(是否发送);
 | ||
| 3. 业务根据需要,通过数据库判断哪些文件已经发送完成,哪些文件发送失败,哪些文件待发送;
 | ||
| 
 | ||
| #### 1.4.3.3. 硬件适配层(hal)
 | ||
| 
 | ||
|   负责适配不同的硬件平台。
 | ||
| 
 | ||
| ##### 1.4.3.3.1. 硬件适配层设计模式
 | ||
| 
 | ||
|   基于C语言接口的多态单例模式,编译时静态多态链接对应的芯片平台适配代码,实现芯片接口的标准功能定义。
 | ||
| 
 | ||
| ##### 1.4.3.3.2. 媒体适配方案:
 | ||
| 
 | ||
|   IPC应用在适配芯片平台的多媒体接口时,使用多进程的方式实现。满足IPC应用可以快起(无需等待媒体相关的初始化)的需求。
 | ||
| 
 | ||
| **媒体基本需求**
 | ||
| 
 | ||
| 1. 图片抓拍;
 | ||
| 2. 视频抓拍;
 | ||
| 
 | ||
| **多进程通信方案**
 | ||
| 
 | ||
|   使用本地socket的方式进行多进程通信,媒体进程为客户端,IPC应用为服务端(IPC先启动)。
 | ||
| 
 | ||
| 1. 客户端可自动重连;
 | ||
| 2. 服务端可多次关闭和开启,满足gtest资源回收需求;
 | ||
| 
 | ||
| ##### 1.4.3.3.3. 适配层多进程类图
 | ||
| 
 | ||
| ```mermaid
 | ||
| classDiagram
 | ||
|     i_hal <.. hal:实现
 | ||
|     hal --> v_media_handle:依赖
 | ||
|     v_media_handle --> local_socket:依赖
 | ||
|     local_socket .. media进程:跨进程
 | ||
|     media进程 --> 芯片媒体API:依赖
 | ||
| ```
 | ||
| 
 | ||
| ##### 1.4.3.3.4. 跨进程业务时序图
 | ||
| 
 | ||
| * 本地socket链接
 | ||
| 
 | ||
| ```mermaid
 | ||
| sequenceDiagram
 | ||
| participant hal
 | ||
| participant v_media_handle
 | ||
| participant local_socket_s
 | ||
| participant local_socket_c
 | ||
| participant media进程
 | ||
| participant 芯片媒体API
 | ||
| hal ->> +v_media_handle:初始化
 | ||
|     v_media_handle ->> +local_socket_s:本地socket服务端启动
 | ||
|     par 本地socket初始化
 | ||
|         local_socket_s -->> -v_media_handle:return
 | ||
| v_media_handle -->> -hal:return
 | ||
|     and
 | ||
|         media进程 ->> media进程:启动
 | ||
|         media进程 ->> +local_socket_c:初始化服务端
 | ||
|             local_socket_c -->> local_socket_s:链接
 | ||
|         local_socket_c -->> -media进程:return
 | ||
|             local_socket_s -->> local_socket_c:初始化媒体
 | ||
|             local_socket_c ->> media进程:回调回传协议事件
 | ||
|             media进程 ->> +芯片媒体API:初始化媒体
 | ||
|             芯片媒体API -->> -media进程:return
 | ||
|     end
 | ||
| ```
 | ||
| 
 | ||
| * 存在问题:
 | ||
| 使用C语言开发时如何解决智能指针问题?
 | ||
| 
 | ||
| #### 1.4.3.4. 工具库(utils)
 | ||
| 
 | ||
| ##### 1.4.3.4.1. 工具库概述
 | ||
|   工具库是功能单一的不依赖任何三方库的独立库(日志库和返回码管理库除外),必须提供C语言接口,内部实现不限于C或者C++。工具类库可以被任意的其它模块调用,特别指hal/component/application三大层级。
 | ||
| 
 | ||
| ##### 1.4.3.4.2. 日志库
 | ||
| 
 | ||
| ###### 1.4.3.4.2.1. 日志库概述
 | ||
|   提供程序的日志管理功能,含日志的实时打印/保存/跟踪(实时上传云端)。
 | ||
| 
 | ||
| ###### 1.4.3.4.2.2. 日志库设计模式
 | ||
|   C语言接口的多态单例模式,可动态/静态加载多态实例。
 | ||
| 
 | ||
| ###### 1.4.3.4.2.3. 日志库启动
 | ||
|   日志库是否启用一般来讲是dubug版本启用日志功能,release版本禁用日志功能,考虑到release版本的维护问题,标准启动时,main线程在启动时使用dlopen系列函数去加载日志库(多态),特殊版本仍可在main线程加载日志库后,二次实例化日志库(多态)来实现不同的日志功能。
 | ||
| 
 | ||
| 1. 标准流程:main线程加载sd卡动态库,如有即可动态实现日志功能,正常出货sd卡不带日志库,此时没有日志功能;
 | ||
| 2. 可以通过配置参数决定是否启用日志;
 | ||
| 3. sd卡的日志动态,根据实际售后维护,可以是实时打印log/保存本地log/云log的多态实例库;
 | ||
| 4. 多态日志功能,可以忽略debug和release版本的区别,只发布一个版本即可;
 | ||
| 
 | ||
| ##### 1.4.3.4.3. 状态码管理库
 | ||
| 
 | ||
|   提供整个应用程序的返回码管理功能,例如:打印返回码的字符串含义。提供C语言接口,纯C语言开发的模块,形成项目内部唯一返回码标准。
 | ||
| 
 | ||
| ###### 1.4.3.4.3.1. 状态码功能
 | ||
| 
 | ||
| 1. 创建返回码操作“句柄”;
 | ||
| 2. 打印返回码/获取返回码(字符串);
 | ||
| 3. 不同模块可继承实现各自的返回码处理接口;
 | ||
| 4. 不同模块之间可透传状态码,避免错误码的转换麻烦;
 | ||
| 5. 状态码的定义是跟着模块走的,独立模块的状态码定义在模块内部,不链接时不占用程序空间;
 | ||
| 
 | ||
| ###### 1.4.3.4.3.2. 基础状态码定义
 | ||
| 
 | ||
|   基础状态码是全局的基础状态码,枚举值全局唯一,其它独立模块必须继承基础状态码累加枚举值,但是,独立模块之间的枚举值可重复,状态码在使用时,日志只关注状态码的字符串,不关心状态码枚举值,代码逻辑使用枚举值。
 | ||
| 
 | ||
| ```
 | ||
| enum STATUS_CODE
 | ||
| {
 | ||
|     STATUS_CODE_OK = 0,
 | ||
|     STATUS_CODE_NOT_OK,
 | ||
|     STATUS_CODE_VIRTUAL_FUNCTION,
 | ||
|     STATUS_CODE_INVALID_PARAMENTER,
 | ||
|     STATUS_CODE_END
 | ||
| };
 | ||
| ```
 | ||
| | 枚举名   | 字符串                             | 描述      |
 | ||
| | ------ | :------------------------------- | --------- |
 | ||
| | STATUS_CODE_OK | STATUS_CODE_OK | 成功 |
 | ||
| | STATUS_CODE_NOT_OK | STATUS_CODE_NOT_OK | 失败 |
 | ||
| | STATUS_CODE_VIRTUAL_FUNCTION | STATUS_CODE_VIRTUAL_FUNCTION | 抽象接口,提示抽象接口未实例化 |
 | ||
| | STATUS_CODE_INVALID_PARAMENTER | STATUS_CODE_INVALID_PARAMENTER | 无效的参数 |
 | ||
| | STATUS_CODE_END | STATUS_CODE_END | 结束,无意义 |
 | ||
| | 其它 | ? | 其它状态码在各自模块定义 |
 | ||
| 
 | ||
| ###### 1.4.3.4.3.3. 已知漏洞
 | ||
| 
 | ||
|   状态码在代码层面是存在重复的可能性的,代码逻辑在使用状态码枚举值时,可能会出现逻辑错误。
 | ||
| 
 | ||
| * 解决方案
 | ||
| 在使用状态码进行逻辑判断时,使用状态码枚举值的字符串。
 | ||
| Example:
 | ||
| ```
 | ||
| static inline bool StatusCodeEqual(const StatusCode code, const char *value)
 | ||
| ```
 | ||
| 
 | ||
| ##### 1.4.3.4.4. 系统标准接口库
 | ||
| 
 | ||
|   对系统标准接口的套壳封装,主要是为了对系统标准打桩满足测试需求。
 | ||
| 
 | ||
|   使用普通的C语言接口封装即可,通过使用gcc编译参数在Linux x86系统中满足打桩需求,在交叉编译(担心工具链兼容问题)测试程序中无法对系统标准接口进行打桩。
 | ||
| 
 | ||
| ##### 1.4.3.4.5. 通用配置库
 | ||
| 
 | ||
| ###### 1.4.3.4.5.1. 通用配置库概述
 | ||
| 
 | ||
|   配置库负责管理软件配置参数,对配置数据进行设置 / 获取 / 存储 / 备份 / 升级等功能;通用配置库不限制使用场景,是一个通用的配置文件管理库。
 | ||
| 
 | ||
| ###### 1.4.3.4.5.2. 配置库设计模式
 | ||
| 
 | ||
|   对外提供C语言接口,内部不局限使用C或者C++。整个软件唯一可以直接操作文件系统配置文件的库。配置库可以理解为简单的三方库的接口直接封装,使用多态单例设计模式实现静态或者动态切换三方库的使用。
 | ||
| 
 | ||
| **基本功能**
 | ||
| 
 | ||
| 1. 使用**三方库**保存明文格式的配置文件到文件系统;
 | ||
| 2. 可注册回调函数,监听文件的操作事件;
 | ||
| 3. 使用字符串名字key + 值的方式管理配置文件,作为通用的配置文件管理库;
 | ||
| 
 | ||
| ###### 1.4.3.4.5.3. 开源库
 | ||
| 
 | ||
| 两种方案:
 | ||
| 1. 使用libconfig作为文件操作的开源库,实现文件和数据的读 / 写。
 | ||
| 2. 使用sqlite3作为文件操作的开源库,作为数据库文件处理。
 | ||
| 
 | ||
| ###### 1.4.3.4.5.4. 通用配置库类图
 | ||
|   多态单例设计模式,main线程静态链接多态库。
 | ||
| ```mermaid
 | ||
| classDiagram
 | ||
|     i_config_manager <.. config_manager:实现
 | ||
|     config_manager --> libconfig开源库:依赖
 | ||
|     i_config_manager <.. sqlite_manager:实现
 | ||
|     sqlite_manager --> sqlite3数据库:依赖
 | ||
| ```
 | ||
| 
 | ||
| ###### 1.4.3.4.5.5. 备份机制
 | ||
| 
 | ||
|   备份数据用于数据异常时可还原旧数据。
 | ||
| 
 | ||
| 方案选择:
 | ||
| 1. 出厂默认配置文件为只读文件,在数据破坏时还原;
 | ||
| 
 | ||
| ###### 1.4.3.4.5.6. 升级机制
 | ||
| 
 | ||
|   程序升级后配置数据发生增 / 删时如何兼容和还原。
 | ||
| 
 | ||
| ##### 1.4.3.4.6. 串口功能模块
 | ||
| 
 | ||
|   串口的打开 / 关闭 / 数据读 / 数据写 功能。
 | ||
| 
 | ||
| ###### 1.4.3.4.6.1. 串口开源库
 | ||
| 使用下述开源库对串口数据进行收发。
 | ||
| ```
 | ||
| https://gitee.com/RT-Thread-Mirror/TinyFrame
 | ||
| ```
 | ||
| 
 | ||
| ##### 1.4.3.4.7. MCU协议库
 | ||
| 
 | ||
|   负责MCU通信协议的组包 / 拆包 / 事件转换。
 | ||
| 
 | ||
| ###### 1.4.3.4.7.1. MCU协议库设计模式
 | ||
| 
 | ||
|   基于C语言的多态单例设计模式。
 | ||
| 
 | ||
| ###### 1.4.3.4.7.2. 协议数据结构
 | ||
| 
 | ||
| ##### 1.4.3.4.8. 多进程通讯库
 | ||
| 
 | ||
|   负责多进程之间的数据交换。使用local socket方式实现。
 | ||
| 
 | ||
| ##### 1.4.3.4.9. 多进程协议库
 | ||
| 
 | ||
|   负责IPC应用和媒体进程之间的协议组包 / 拆包,在协议和业务之间进行转换接口的封装。
 | ||
| 
 | ||
| ## 1.5. 生产测试/研发调试
 | ||
| 
 | ||
|   基于公版代码派生出来的特定的定制版本,用于辅助生产和测试。
 | ||
| 
 | ||
| ## 1.6. 自动化测试
 | ||
| 
 | ||
| ### 1.6.1. 自动化测试概述
 | ||
| 
 | ||
|   自动化测试是该产品设计的一大特点,需要严格执行。自动化测试指使用纯代码对业务设计进行测试用例设计,实现业务集成测试的能力。
 | ||
| 
 | ||
| 
 | ||
| ### 1.6.2. 自动化测试规范
 | ||
| 
 | ||
| 1. 每个源码文件在开发时,均要写调试的example,用于验证该文件的接口功能;测试文件的命名规则为:文件名 + “_Test.c(pp)”;
 | ||
| 例如: 
 | ||
| * C语言:log_impl.c对应的测试文件为log_impl_Test.cpp;
 | ||
| * C++:LogImpl.cpp对应的测试文件为LogImpl_Test.cpp;
 | ||
| 
 | ||
| ## 1.7. 编码规范
 | ||
| 
 | ||
| 1. 文件命名统一使用大驼峰命名规则;
 | ||
| 2. 混合多态单例的C++抽象接口头文件需要有Cpp关键字标识;
 | ||
| 3. 多单单例的头文件 / 类名 统一使用“I”前缀,interface的单词首字母;
 | ||
| 4. 抽象对象接口类统一使用“V”前缀, virtual的单词首字母;
 | ||
| 5. 所有函数统一使用大驼峰命名规则;
 | ||
| 6. 其它遵循华为的编码规范要求; | 
