版本比较

标识

  • 该行被添加。
  • 该行被删除。
  • 格式已经改变。

从这里开始

软件导读

软件开发基础

总得来看,软件至少分成三个部分,一是3861上运行的LiteOS系统API,这里因为不像Camera侧的LiteOS那样兼容POSIX,所以一些比较重要的接口要先搞懂,比如消息队列和事件,还有flash和nv操作。二是组件,组件是在系统API上又封装的一层通用接口,比如状态机,事件路由,参数等模块,这些组件在应用里大量用到。最后是业务,比如待机唤醒,保活,低功耗等。

LiteOS系统API

关键原因是3861上运行的LiteOS系统API和Camera侧的LiteOS系统API不太一样,Camera侧的LiteOS因为兼容POSIX,所以在开发程序时基本不需要学习新的API,只需要把在Linux上开发的那套东西拿过来直接用就可以了,比如线程,互斥锁,信号量等接口都是直接和Linux一样的。但在3861上运行的LiteOS系统的API不兼容POSIX,所以需要单独学习,这里只介绍几类常用的API,如下:

  1. "任务"
  2. "内存管理"
  3. "消息队列"
  4. "事件"
  5. "互斥锁"
  6. "时间管理"
  7. "软件定时器"

组件

组件是在系统API上又封装的一层代码,用于实现一些公共的功能,比如状态机,事件路由等,这些组件对于提升代码复用,降低代码复杂度,提升开发速度有用,在业务代码中大量应用了组件的接口,所以也需要学习。几个组件如下:

  1. "状态机"
  2. "事件路由"
  3. Devmng模块

一些编程总结

  1. 结果大量使用输出参数来传递,而不是返回值;

业务

在了解了3861的系统API和组件代码后,就可以开始分析3861主程序的业务代码了,主程序入口:3861L/wifi/reference/battery_ipcam/modules/init/src/hi_product_init_main.c,app_main()函数。

HI_VOID app_main(HI_VOID)
{
    ...
  
    HI_PDT_INIT_PERIPHERAL_Init();

    /* start key check thread as soon as possible */
    HI_PDT_INIT_SERVICE_PreInit();

    /* start system */
    PDT_INIT_Init();

    return;
}

  1. "HI_PDT_INIT_PERIPHERAL_Init"

    外设初始化。

  2. "HI_PDT_INIT_SERVICE_PreInit"

    服务预初始化。

  3. "PDT_INIT_Init"

    系统初始化。

软件开发大量参考文档:消费类 IP Camera Sample开发指南(Hi3861L).pdf

硬件导读

image.pngImage Added

  1. 3.3V_MCU是整个系统的供电,分两路,一路直接通到VDDIO给系统供电,一路通过MAX809生成上电复位信号给到POW_ON脚,完成上电复位功能。
  2. SET_KEY是门铃按键。
  3. PWR_HOLD是3861控制主控电源的管脚。
  4. SD1_HOST_INTO/SD1_CMD/SD1_CLK/SD1_D0是SDIO的管脚,单线传输,速度实测很低。

注意点:

  1. 设备的复位信号没接到3861上,这点与STM8方案不一样,STM8方案复位信号同时接主控和单片机,可以通过单片机强制复位。这点导致3861版的移康门铃无法实现开机上报复位键唤醒。

  2. 3861的2、6、8管脚在上电启动时不能输入高电平,否则会出异常,实测芯片根据启动不起来,上面的SPI_FS,也就是433的FCSB管脚接到了6脚上,而这个信号恰好是低有效,也就是平常是高电平状态,这就导致了按上面的电路上电,3861根本启动不起来,解决办法是临时增加一个拨位开关,在上电时断开SPI_FS,启动之后再连通SPI_FS和6脚。

    参考:IOT Camera低功耗方案开发导引(Hi35XX + Hi3861L)_V0.3(xm).pdf
    Image Added

  3. 上面的问题涉及到电路改版,目前的改动办法是,把SET_KEY,也就是门铃按键,和SPI_FS对调一下,同时修改门铃按键的电路,使其按下时为高,不按时为低就可以了。

典型功能分析

#todo#

  1. 上电启动
  2. 上电进快速配网
  3. 连接wifi,包括连接成功、失败等状态的处理;
  4. 串口配网,或是hisyslink/hichannel消息收发处理
  5. 保活
  6. 按键唤醒
  7. PIR唤醒

std::sort()

原型:

代码块
#include <algorithm>

template< class RandomIt >
void sort( RandomIt first, RandomIt last );

template< class RandomIt, class Compare >
void sort( RandomIt first, RandomIt last, Compare comp );

用于将范围 [first, last) 内的元素按升序排序。不稳定排序,相同的元素位置可能被打乱。

默认使用 operator< 进行排序,也可以提供一个自定义的比较函数comp,要求函数签名如下:
bool comp(const Type1 &a, const Type2 &b);
比较时a表示后面的元素,b表示前面的元素,要求comp(a, b)返回false。

使用示例:
#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;

static void print(vector<int> &a) {
    for(auto i : a) {
        cout << i << " ";
    }
    cout << "\n";
}

static bool less(int a, int b) {
    return a < b;
}

static bool customLess(int a, int b) {
    return a > b;
}

int main() {
    vector<int> a = {-1, 1, 2, 0, 3, 2, 0, 5};

    sort(a.begin(), a.end()); //默认升序
    print(a);

    random_shuffle(a.begin(), a.end());
    sort(a.begin(), a.end(), less); //使用less进行元素比较,升序
    print(a);

    random_shuffle(a.begin(), a.end());
    sort(a.begin(), a.end(), customLess); //使用customLess进行元素比较,降序
    print(a);

    random_shuffle(a.begin(), a.end());
    sort(a.begin(), a.end(),[](int a, int b){ //使用lambada函数,升序
        return a < b;
    });
    print(a);

    random_shuffle(a.begin(), a.end());
    sort(a.begin(), a.end(), std::less<int>()); //使用标准库比较对象,升序
    print(a);

    random_shuffle(a.begin(), a.end());
    sort(a.begin(), a.end(), std::greater<int>()); //使用标准库比较对象,降序
    print(a);

    return 0;
}

std::reverse()
用于翻转或部分翻转顺序容器的数据,例如:
vector<int> v;
...
reverse(v.begin() + 5, v.begin() + 8);  //翻转第6至第9区间内的元素

std::min_element()
给定区间的最小值,示例:

...