topgear · 2022年12月09日 · 上海市

【聆思CSK6 视觉AI开发套件试用】AI识别能力之人脸识别能力的试用以及结合网络连接的应用

一、前言

本次参与【聆思CSK6 视觉AI开发套件试用】的活动,作为第一批试用名单的幸运儿其实在11月初期就拿到了开发套件,聆思第一次发布头肩识别的AI能力时,我也根据官方文档以及微信群内的讨论成功试用了头肩识别的AI能力。聆思第二次发布人脸识别的AI能力之后,我想到如果是单纯的运行一下Demo可能仅仅局限于AI功能的测试,如果能够把AI能力与应用结合起来使用,可以熟悉这颗芯片的硬件和外设资源。首先想到的一个应用就是基于人脸识别的Demo,注册一个人脸,然后当摄像头捕获到的人脸信息与注册的人脸相似度触发某一个阈值之后,发送一条消息到服务器。基于这种设想,需要用到开发套件自带的WIFI模组,并选择某种网络协议实现数据传输,最终我选择了CSK6+Wifi(ESP-C3)+Websocket。不过受限于本人的能力以及对zephyr rtos的不熟悉,花费了不少时间去调试net方面的功能,最终实现的代码还是很不稳定,不过我还是把自己的实现思路记录下来,未来有时间再加以完善。在试用开发套件的过程中,遇到了不少问题,从聆思的覃工那里得到了不少技术支持,再次也感谢覃工。

二、环境搭建

关于开发环境的搭建,聆思的官方文档非常详细,直接参考环境搭建这一章节:
https://docs.listenai.com/chi...
我的开发环境如下:

  • 操作系统:Windows 10
  • Git版本:git version 2.38.1.windows.1
  • CSK 开发环境:csk6_integration_installer_v1.6.5.exe
    注意:根据之前的经验教训,我在安装过程中,暂时关闭了360安全卫士。

三、示例程序的编译测试

  1. 创建示例程序

在Windows命令行输入 lisa zep create 会弹出以树形目录排列的示例程序,我主要选择了三个示例程序做了编译测试,分别为:

  • hello_world
  • basic->blinky
  • board->csk6->network->wifi_sta
  1. 编译

输入命令lisa zep build -b csk6011a_c3_nano进行编译,编译会比较费时间;

  1. 烧录
    输入命令lisa zep flash,默认调用pyocd通过daplink进行烧录,我的感觉是烧录速度很慢。
    后来发现通过命令lisa zep config flash.pyocd.frequency 200000000可以改善烧录速度。
  2. 通过lisa zep create创建的示例程序仅包含示例代码、kconfig配置文件和CMakeLists,编译时会默认使用之前安装的SDK(C:\Users\xxx\AppData\Roaming\LISTENAI\LISA\csk-sdk\),并在示例程序目录生成 build 目录。

三、人脸识别Demo的测试

  1. 人脸识别Demo的环境,我是完全按照官方教程去配置的,链接如下:
    https://docs.listenai.com/chi...
  2. 遇到的问题:
  • 烧录算法资源时经常会失败:

    lisa zep exec cskburn -s \\.\COMx -C 6 0x400000 .\resource\cp.bin -b 748800
    lisa zep exec cskburn -s \\.\COMx -C 6 0x500000 .\resource\res.bin -b 748800

    解决方法是插拔USB,因为这个算法资源是官方提供的,所以只需要烧录一次即可;

  • PC查看工具版本不对导致显示图像有问题:
    csk_view_finder_spd 仓库有多个分支,确保是master分支或者feature/face分支。假如PC查看工具在第一次发布头肩识别能力checkout的,需要update到最新的版本。
  1. csk_viewe_finder_spd通过webusb访问摄像头捕获的实时画面以及传输人脸识别的结果数据,如下:
    fd_webusb.png
  2. 关于人脸识别Demo与示例程序的区别
    示例程序会使用安装在系统目录的SDK,而人脸识别Demo会根据west.yml去拉取指定分支或者指定版本的zephyr rtos和modules,并存放于.sdk目录。

四、在人脸识别Demo的基础上增加网络连接功能

  1. 实现思路
    在main()函数初始化video以及算法之前初始化wifi,并在按钮单击的注册事件中,如果人脸识别得分大于0.95,则发送消息到webusb,同时发送websocket到服务器。
  2. 增加wifi_sta功能
  • 创建 csk6011a_c3_nano 对应的overlay文件
    copy boards/csk6011a_nano.overlay boards/csk6011a_c3_nano.overlay
  • 因为C3 wifi模块是通过SPI控制的,所以需要修改csk6011a_c3_nano.overlay文件,取消屏蔽spi0、spi1

    /delete-node/ &psram_ap;
    /delete-node/ &psram_cp;
    /delete-node/ &psram_share;
    
    / {
      chosen {
          /*
           * shared memory reserved for the inter-processor communication
           */
          zephyr,ipc_shm = &psram_share;
          zephyr,ipc = &mailbox0;
      };
    
    };
    
    &psram0 {
      psram_cp: psram_cp@30000000 {
          compatible = "listenai,csk6-psram-partition";
          reg = <0x30000000 0x400000>;
          status = "okay";
      };
      psram_ap: psram_ap@30400000 {
          compatible = "zephyr,memory-region","listenai,csk6-psram-partition";
          reg = <0x30400000 0x21d000>;
          status = "okay";
          zephyr,memory-region = "PSRAMAP";
      };
      psram_ap_nocache: psram@3061d000 {
          compatible = "zephyr,memory-region","listenai,csk6-psram-partition";
          reg = <0x3061d000 0x1c3000>;
          status = "okay";
          zephyr,memory-region = "PSRAMAP_NOCACHE";
          zephyr,memory-region-mpu = "RAM_NOCACHE";
      };
      psram_share: psram_share@307e0000 {
          compatible = "listenai,csk6-psram-partition";
          reg = <0x307e0000 0x20000>;
          status = "okay";
      };
    };
    
    &csk6011a_c3_nano_pinctrl{
                  pinctrl_i2c0_scl_default: i2c0_scl_default{
                          pinctrls = <I2C0_SCL_GPIOB_04>;
                  };
                  
                  pinctrl_i2c0_sda_default: i2c0_sda_default{
                          pinctrls = <I2C0_SDA_GPIOB_03>;
                  };
    
                  pinctrl_dvp_clkout_default: dvp_clkout_default{
                      pinctrls = <CLKP_OUT_GPIOA_07>;
                  };
    
                  pinctrl_dvp_vsync_default: dvp_vsync_default{
                      pinctrls = <I_V_SYNC_GPIOA_14>;
                  };
    
                  pinctrl_dvp_hsync_default: dvp_hync_default{
                      pinctrls = <I_H_SYNC_GPIOA_13>;
                  };
    
                  pinctrl_dvp_pclk_default: dvp_pclk_default{
                      pinctrls = <I_PIXEL_CLK_GPIOA_12>;
                  };
    
                  pinctrl_dvp_d4_default: dvp_d4_default{
                      pinctrls = <I_PIXEL_DATA4_GPIOA_04>;
                  };
    
                  pinctrl_dvp_d5_default: dvp_d5_default{
                      pinctrls = <I_PIXEL_DATA5_GPIOA_05>;
                  };
    
                  pinctrl_dvp_d6_default: dvp_d6_default{
                      pinctrls = <I_PIXEL_DATA6_GPIOA_06>;
                  };
    
                  pinctrl_dvp_d7_default: dvp_d7_default{
                      pinctrls = <I_PIXEL_DATA7_GPIOB_07>;
                  };
    
                  
                  pinctrl_dvp_d8_default: dvp_d8_default{
                      pinctrls = <I_PIXEL_DATA8_GPIOB_08>;
                  };
    
                  
                  pinctrl_dvp_d9_default: dvp_d9_default{
                      pinctrls = <I_PIXEL_DATA9_GPIOB_09>;
                  };
    
                  
                  pinctrl_dvp_d10_default: dvp_d10_default{
                      pinctrls = <I_PIXEL_DATA10_GPIOA_08>;
                  };
    
                  
                  pinctrl_dvp_d11_default: dvp_d11_default{
                      pinctrls = <I_PIXEL_DATA11_GPIOA_09>;
                  };
    };
    
    /*
    &spi0 {
      status = "disabled";
    };
    
    &spi1 {
      status = "disabled";
    };
    */
    
    &i2c0 {
          status = "okay";
          pinctrl-0 = <&pinctrl_i2c0_scl_default &pinctrl_i2c0_sda_default>; 
          pinctrl-names = "default";
    
          gc032a: gc032a@21 {
              compatible = "galaxyc,gc032a";
              status = "okay";
              label = "GC032A";
              reg = <0x21>;
              reset-gpios = <&gpioa 6 0>;
    
              port {
                  gc032a_ep_out: endpoint {
                      remote-endpoint = <&dvp_ep_in>;
                  };
              };
          };
    
    };
    
    &uart0 {
          current-speed = <115200>;
    };
    
    &dvp {
      status = "okay";
      sensor-label = "GC032A";
      clock-prescaler = <6>;
      data-align-type = "high_align";
      pclk-polarity = "post_edge_sampling";
      hsync-polarity = "active_high";
      vsync-polarity = "active_low";
    
      pinctrl-0 = <
                  &pinctrl_dvp_clkout_default 
                  &pinctrl_dvp_vsync_default
                  &pinctrl_dvp_hsync_default
                  &pinctrl_dvp_pclk_default
                  &pinctrl_dvp_d4_default
                  &pinctrl_dvp_d5_default
                  &pinctrl_dvp_d6_default
                  &pinctrl_dvp_d7_default
                  &pinctrl_dvp_d8_default
                  &pinctrl_dvp_d9_default
                  &pinctrl_dvp_d10_default
                  &pinctrl_dvp_d11_default
                  >; 
      pinctrl-names = "default";
    
      port {
          dvp_ep_in: endpoint {
              remote-endpoint = <&gc032a_ep_out>;
          };
      };
    
    };
  • 在 src 目录增加 wifi 初始化代码 wifi_connnect.c

    /*
     * SPDX-License-Identifier: Apache-2.0
     */
    
    #include <stdlib.h>
    #include <sys/printk.h>
    #include <sys/sys_heap.h>
    
    #include <net/net_if.h>
    #include <net/net_core.h>
    #include <net/net_context.h>
    #include <net/net_mgmt.h>
    
    #include "csk6/csk_wifi.h"
    #include "wifi_connect.h"
    
    K_SEM_DEFINE(wifi_mutex_test, 0, 1);
    
    static csk_wifi_event_cb_t wifi_event_cb;
    static struct net_mgmt_event_callback dhcp_cb;
    static void handler_cb(struct net_mgmt_event_callback *cb, uint32_t mgmt_event, struct net_if *iface)
    {
      if (mgmt_event != NET_EVENT_IPV4_DHCP_BOUND) {
          return;
      }
    
      char buf[NET_IPV4_ADDR_LEN];
    
      printk("Your address: %s\n", net_addr_ntop(AF_INET, &iface->config.dhcpv4.requested_ip, buf, sizeof(buf)));
      printk("Lease time: %u seconds\n", iface->config.dhcpv4.lease_time);
      printk("Subnet: %s\n", net_addr_ntop(AF_INET, &iface->config.ip.ipv4->netmask, buf, sizeof(buf)));
      printk("Router: %s\n", net_addr_ntop(AF_INET, &iface->config.ip.ipv4->gw, buf, sizeof(buf)));
    
      k_sem_give(&wifi_mutex_test);
    }
    
    static void wifi_event_handler(csk_wifi_event_t events, void *event_data, uint32_t data_len, void *arg)
    {
      if (events & CSK_WIFI_EVT_STA_CONNECTED) {
          printk("[WiFi sta] connected\n");
      } else if (events & CSK_WIFI_EVT_STA_DISCONNECTED) {
          printk("[WiFi sta] disconnected\n");
      } else {
          abort();
      }
    }
    
    void wifi_connect(void)
    {
      int ret;
      csk_wifi_init();
      uint8_t mac_addr[6] = {0};
      ret = csk_wifi_get_mac(CSK_WIFI_MODE_STA, mac_addr);
      if (ret != 0) {
          printk("wifi get mac failed, ret: %d\n", ret);
          return;
      }
      printk("wifi station mac addr: %x:%x:%x:%x:%x:%x\n", 
              mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3],
              mac_addr[4], mac_addr[5]);
      wifi_event_cb.handler = &wifi_event_handler;
      wifi_event_cb.events = CSK_WIFI_EVT_STA_CONNECTED | CSK_WIFI_EVT_STA_DISCONNECTED;
      wifi_event_cb.arg = NULL;
      csk_wifi_add_callback(&wifi_event_cb);
    
      csk_wifi_sta_config_t sta_config = {
          .ssid = "your-ssid", //CONFIG_EXAMPLE_WIFI_SSID,
          .pwd = "your-password", //CONFIG_EXAMPLE_WIFI_PASSWORD,
          .encryption_mode = CSK_WIFI_AUTH_WPA2_PSK
      };
    
      int retry_count = 0;
      csk_wifi_result_t wifi_result;
      do {
          printk("connecting to wifi: %s ...\n", sta_config.ssid);
          ret = csk_wifi_sta_connect(&sta_config, &wifi_result, K_FOREVER);
          if (ret == 0) {
              break;
          } else {
              if (wifi_result == CSK_WIFI_ERR_STA_FAILED) {
                  retry_count++;
                  printk("retry to connecting wifi ... %d\n", retry_count);
              } else {
                  printk("AP not found or invalid password\n");
                  return;
              }
          }
      } while (retry_count < 10);
      printk("--------------------------Current AP info-------------------------------\n");
      printk("ssid: %s  pwd: %s  bssid: %s  channel: %d  rssi: %d\n",
          sta_config.ssid, sta_config.pwd, sta_config.bssid, sta_config.channel,
          sta_config.rssi);
      printk("------------------------------------------------------------------------\n");
      net_mgmt_init_event_callback(&dhcp_cb, handler_cb, NET_EVENT_IPV4_DHCP_BOUND);
      net_mgmt_add_event_callback(&dhcp_cb);
      struct net_if *iface = net_if_get_default();
      if (!iface) {
          printk("wifi interface not available");
          return;
      }
      net_dhcpv4_start(iface);
    
      k_sem_take(&wifi_mutex_test, K_FOREVER);
    }
  1. 在 src 目录增加 websocket 代码 websocket.c

    /*
     * Copyright (c) 2019 Intel Corporation
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    #include <logging/log.h>
    LOG_MODULE_REGISTER(net_websocket_client_sample, LOG_LEVEL_DBG);
    
    #include <net/net_ip.h>
    #include <net/socket.h>
    #include <net/tls_credentials.h>
    #include <net/websocket.h>
    #include <random/rand32.h>
    #include <shell/shell.h>
    
    #define SERVER_ADDR4 "192.168.0.130" // websocket server address
    #define SERVER_PORT 9001
    
    static const char lorem_ipsum[] = "face detected\n";
    
    #define MAX_RECV_BUF_LEN (sizeof(lorem_ipsum) - 1)
    
    const int ipsum_len = MAX_RECV_BUF_LEN;
    
    static uint8_t recv_buf_ipv4[MAX_RECV_BUF_LEN];
    static uint8_t recv_buf_ipv6[MAX_RECV_BUF_LEN];
    
    #define EXTRA_BUF_SPACE 30
    
    static uint8_t temp_recv_buf_ipv4[MAX_RECV_BUF_LEN + EXTRA_BUF_SPACE];
    static uint8_t temp_recv_buf_ipv6[MAX_RECV_BUF_LEN + EXTRA_BUF_SPACE];
    
    static int setup_socket(sa_family_t family, const char *server, int port,
             int *sock, struct sockaddr *addr, socklen_t addr_len)
    {
     const char *family_str = family == AF_INET ? "IPv4" : "IPv6";
     int ret = 0;
    
     memset(addr, 0, addr_len);
    
     if (family == AF_INET) {
         net_sin(addr)->sin_family = AF_INET;
         net_sin(addr)->sin_port = htons(port);
         inet_pton(family, server, &net_sin(addr)->sin_addr);
     } else {
         net_sin6(addr)->sin6_family = AF_INET6;
         net_sin6(addr)->sin6_port = htons(port);
         inet_pton(family, server, &net_sin6(addr)->sin6_addr);
     }
    
     *sock = socket(family, SOCK_STREAM, IPPROTO_TCP);
    
     if (*sock < 0) {
         LOG_ERR("Failed to create %s HTTP socket (%d)", family_str,
             -errno);
     }
     return ret;
    fail:
     if (*sock >= 0) {
         close(*sock);
         *sock = -1;
     }
    
     return ret;
    }
    
    static int connect_socket(sa_family_t family, const char *server, int port,
               int *sock, struct sockaddr *addr, socklen_t addr_len)
    {
     int ret;
    
     ret = setup_socket(family, server, port, sock, addr, addr_len);
     if (ret < 0 || *sock < 0) {
         return -1;
     }
    
     ret = connect(*sock, addr, addr_len);
     if (ret < 0) {
         LOG_ERR("Cannot connect to %s remote (%d)",
             family == AF_INET ? "IPv4" : "IPv6",
             -errno);
         ret = -errno;
     }
    
     return ret;
    }
    
    static int connect_cb(int sock, struct http_request *req, void *user_data)
    {
     printk("Websocket %d for %s connected.", sock, (char *)user_data);
     return 0;
    }
    
    static size_t how_much_to_send(size_t max_len)
    {
     size_t amount;
    
     do {
         amount = sys_rand32_get() % max_len;
     } while (amount == 0U);
    
     return amount;
    }
    
    static ssize_t sendall_with_ws_api(int sock, const void *buf, size_t len)
    {
     return websocket_send_msg(sock, buf, len, WEBSOCKET_OPCODE_DATA_TEXT,
                   true, true, SYS_FOREVER_MS);
    }
    
    static ssize_t sendall_with_bsd_api(int sock, const void *buf, size_t len)
    {
     return send(sock, buf, len, 0);
    }
    
    static void recv_data_wso_api(int sock, size_t amount, uint8_t *buf,
                   size_t buf_len, const char *proto)
    {
     uint64_t remaining = ULLONG_MAX;
     int total_read;
     uint32_t message_type;
     int ret, read_pos;
    
     read_pos = 0;
     total_read = 0;
    
     while (remaining > 0) {
         ret = websocket_recv_msg(sock, buf + read_pos,
                      buf_len - read_pos,
                      &message_type,
                      &remaining,
                      0);
         if (ret <= 0) {
             if (ret == -EAGAIN) {
                 k_sleep(K_MSEC(50));
                 continue;
             }
    
             LOG_DBG("%s connection closed while "
                 "waiting (%d/%d)", proto, ret, errno);
             break;
         }
    
         read_pos += ret;
         total_read += ret;
     }
    
     if (remaining != 0 || total_read != amount ||
         /* Do not check the final \n at the end of the msg */
         memcmp(lorem_ipsum, buf, amount - 1) != 0) {
         LOG_ERR("%s data recv failure %zd/%d bytes (remaining %" PRId64 ")",
             proto, amount, total_read, remaining);
         LOG_HEXDUMP_DBG(buf, total_read, "received ws buf");
         LOG_HEXDUMP_DBG(lorem_ipsum, total_read, "sent ws buf");
     } else {
         LOG_DBG("%s recv %d bytes", proto, total_read);
     }
    }
    
    static void recv_data_bsd_api(int sock, size_t amount, uint8_t *buf,
                   size_t buf_len, const char *proto)
    {
     int remaining;
     int ret, read_pos;
    
     remaining = amount;
     read_pos = 0;
    
     while (remaining > 0) {
         ret = recv(sock, buf + read_pos, buf_len - read_pos, 0);
         if (ret <= 0) {
             if (errno == EAGAIN || errno == ETIMEDOUT) {
                 k_sleep(K_MSEC(50));
                 continue;
             }
    
             LOG_DBG("%s connection closed while "
                 "waiting (%d/%d)", proto, ret, errno);
             break;
         }
    
         read_pos += ret;
         remaining -= ret;
     }
    
     if (remaining != 0 ||
         memcmp(lorem_ipsum, buf, amount - 1) != 0) {
         LOG_ERR("%s data recv failure %zd/%d bytes (remaining %d)",
             proto, amount, read_pos, remaining);
         LOG_HEXDUMP_DBG(buf, read_pos, "received bsd buf");
         LOG_HEXDUMP_DBG(lorem_ipsum, read_pos, "sent bsd buf");
     } else {
         LOG_DBG("%s recv %d bytes", proto, read_pos);
     }
    }
    
    static bool send_and_wait_msg(int sock, size_t amount, const char *proto,
                   uint8_t *buf, size_t buf_len)
    {
     static int count;
     int ret;
    
     if (sock < 0) {
         return true;
     }
    
     memcpy(buf, lorem_ipsum, amount);
     buf[amount] = '\n';
    
     if (count % 2) {
         ret = sendall_with_ws_api(sock, buf, amount + 1);
     } else {
         ret = sendall_with_bsd_api(sock, buf, amount + 1);
     }
    
     if (ret <= 0) {
         if (ret < 0) {
             LOG_ERR("%s failed to send data using %s (%d)", proto,
                 (count % 2) ? "ws API" : "socket API", ret);
         } else {
             LOG_DBG("%s connection closed", proto);
         }
    
         return false;
     } else {
         LOG_DBG("%s sent %d bytes", proto, ret);
     }
    
     if (count % 2) {
         recv_data_wso_api(sock, amount + 1, buf, buf_len, proto);
     } else {
         recv_data_bsd_api(sock, amount + 1, buf, buf_len, proto);
     }
    
     count++;
    
     return true;
    }
    
    void websocket(void)
    {
     const char *extra_headers[] = {
         "Origin: http://foobar\r\n",
         NULL
     };
     int sock4 = -1;
     int websock4 = -1;
     int32_t timeout = 3 * MSEC_PER_SEC;
     struct sockaddr_in addr4;
     size_t amount;
     int ret;
    
     if (IS_ENABLED(CONFIG_NET_IPV4)) {
         (void)connect_socket(AF_INET, SERVER_ADDR4, SERVER_PORT,
                      &sock4, (struct sockaddr *)&addr4,
                      sizeof(addr4));
     }
    
     if (sock4 < 0) {
         LOG_ERR("Cannot create HTTP connection.");
         return;
         // k_sleep(K_FOREVER);
     }
    
     printk("socket =(%d) \r\n", sock4);
     k_sleep(K_MSEC(100));
    
     if (sock4 >= 0 && IS_ENABLED(CONFIG_NET_IPV4)) {
         struct websocket_request req;
    
         memset(&req, 0, sizeof(req));
    
         req.host = SERVER_ADDR4;
         req.url = "/";
         req.optional_headers = extra_headers;
         req.cb = connect_cb;
         req.tmp_buf = temp_recv_buf_ipv4;
         req.tmp_buf_len = sizeof(temp_recv_buf_ipv4);
    
         websock4 = websocket_connect(sock4, &req, timeout, "IPv4");
         if (websock4 < 0) {
             LOG_ERR("Cannot connect to %s:%d", SERVER_ADDR4, SERVER_PORT);
             close(sock4);
         }
     }
    
     printk(" websock4 =(%d) \r\n", websock4);
     k_sleep(K_MSEC(100));
    
     if (websock4 < 0) {
         LOG_ERR("No IPv4 connectivity");
         return;
         //k_sleep(K_FOREVER);
     }
    
     while (1) {
         amount = how_much_to_send(ipsum_len);
    
         if (websock4 >= 0 &&
             !send_and_wait_msg(websock4, amount, "IPv4",
                        recv_buf_ipv4, sizeof(recv_buf_ipv4))) {
             break;
         }
    
         k_sleep(K_MSEC(250));
     }
    
     if (websock4 >= 0) {
         close(websock4);
     }
    
     //k_sleep(K_FOREVER);
    }
  2. 修改人脸识别Demo程序
  • main() 函数开始处调用 wifi_connect(),在初始化video和算法之前,先初始化 wifi,并且wifi初始化函数以阻塞模式执行,初始化完成之后才会继续其他初始化;
  • 修改 button_callback() 函数中,单击按钮事件的处理代码:

          case BUTTON_SINGLE_CLICK:
              if(fr.get_new_feature){
                  uint16_t cnt = 0;
                  uint8_t done = 0;
                  fr.get_new_feature = false;
                  
                  fd_cmd_compare_feature_data_t data;
                  fd_cmd_compare_feature_result_t result;
                  data.feature_dim = FD_MAX_FEATURE_DIMS;
                  data.feature_src = fr.feature_nvs;
                  data.feature_dst = fr.feature;
    
                  storage_get_data_cnt(&cnt);
                  for(uint32_t i = 0; i < cnt; i++){
                      storage_read_data(i, (void *)fr.feature_nvs, sizeof(fr.feature));
                      ret = fd_control(fr.fd, FD_CMD_COMPARE_FEATURE, &data, &result);
                      if(ret != 0){
                          LOG_ERR("feature_compare faild %d", ret);
                      }
    
                      LOG_INF("feature_compare score = %f", result.score);
                      if(result.score > 0.95){
                          done = 1;
                      }
                  }
                  if(done){
                      webusb_send_message("face_calc_similar: success, notify websocket server");
                      websocket();
                  }else{
                      webusb_send_message("face_calc_similar: fail");
                  } 
              }else{
                  webusb_send_message("face_calc_similar: fail");
                  LOG_INF("not detected face feature");
              }      
              break;
  1. 修改prj.conf和CMakeLists.txt
  • prj.conf

    CONFIG_PRINTK=y
    CONFIG_DEBUG=y
    CONFIG_LOG=y
    CONFIG_LOG_MODE_IMMEDIATE=y
    # CONFIG_LOG_BUFFER_SIZE=4096
    CONFIG_LOG_DETECT_MISSED_STRDUP=n
    CONFIG_LOG_BACKEND_SHOW_COLOR=y
    CONFIG_LOG_BACKEND_FORMAT_TIMESTAMP=y
    CONFIG_LOG_BACKEND_UART=y
    CONFIG_LOG_BACKEND_UART_OUTPUT_TEXT=y
    CONFIG_MAIN_STACK_SIZE=8192
    
    #system heap size,users can define it according to the actual usage
    CONFIG_HEAP_MEM_POOL_SIZE=90000
    CONFIG_CSK_HEAP=y
    CONFIG_CSK_HEAP_MEM_POOL_SIZE=342736
    
    #avf
    CONFIG_AVF=y
    CONFIG_AVF_DEBUG_LEVEL=1
    CONFIG_AVF_USE_BINARY_ARRAY=y
    # CONFIG_AVF_DSP_FIRMWARE_LOAD_DEBUG=y
    
    # dvp
    CONFIG_GPIO=y
    CONFIG_I2C=y
    CONFIG_VIDEO=y
    CONFIG_VIDEO_CSK6_DVP=y
    CONFIG_VIDEO_GC032A=y
    
    CONFIG_VIDEO_BUFFER_POOL_SZ_MAX=624400
    CONFIG_VIDEO_BUFFER_POOL_NUM_MAX=2
    CONFIG_VIDEO_CUSTOM_SECTION=y
    CONFIG_VIDEO_CUSTOM_SECTION_NAME=".psram_section"
    
    #licak
    CONFIG_LICAK=y
    CONFIG_LICAK_MODULES_ALG_FD=y
    
    #IPM and GPIO for avf driver
    CONFIG_IPM=y
    
    #cache
    CONFIG_CACHE_MANAGEMENT=y
    
    # nothing here
    CONFIG_WEBUSB=y
    CONFIG_WEBUSB_LOG_LEVEL_DBG=y
    
    CONFIG_STDOUT_CONSOLE=y
    CONFIG_USB_DEVICE_STACK=y
    CONFIG_USB_DEVICE_BOS=y
    CONFIG_SERIAL=y
    CONFIG_UART_INTERRUPT_DRIVEN=y
    CONFIG_UART_LINE_CTRL=y
    
    CONFIG_LOG=y
    CONFIG_LOG_PRINTK=y
    CONFIG_USB_DRIVER_LOG_LEVEL_ERR=y
    CONFIG_USB_DEVICE_LOG_LEVEL_ERR=y
    CONFIG_CONSOLE=y
    
    CONFIG_FPU=y
    CONFIG_NEWLIB_LIBC=y
    CONFIG_NEWLIB_LIBC_NANO=y
    
    CONFIG_CAMERA_MONITOR=n
    CONFIG_SPEED_OPTIMIZATIONS=y
    CONFIG_SHARED_MULTI_HEAP=y
    
    
    CONFIG_WIFI=y
    CONFIG_CSK_WIFI_STATION=y
    CONFIG_NET_L2_ETHERNET=y
    
    CONFIG_NETWORKING=y
    CONFIG_NET_DHCPV4=y
    CONFIG_NET_IPV4=y
    CONFIG_NET_SOCKETS=y
    CONFIG_NET_SOCKETS_POSIX_NAMES=y
    
    CONFIG_NET_MGMT=y
    CONFIG_NET_MGMT_EVENT=y
    CONFIG_NET_MGMT_EVENT_STACK_SIZE=4096
    
    CONFIG_NET_RX_STACK_SIZE=2048
    CONFIG_NET_TX_STACK_SIZE=2048
    CONFIG_NET_PKT_RX_COUNT=16
    CONFIG_NET_PKT_TX_COUNT=16
    CONFIG_NET_BUF_RX_COUNT=64
    CONFIG_NET_BUF_TX_COUNT=64
    CONFIG_NET_CONTEXT_NET_PKT_POOL=y
    
    CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
    CONFIG_INIT_STACKS=y
    
    CONFIG_WIFI_LOG_LEVEL_DBG=y
    
    
    # Networking config
    CONFIG_NETWORKING=y
    CONFIG_NET_IPV4=y
    #CONFIG_NET_IPV6=y
    CONFIG_NET_TCP=y
    CONFIG_NET_SHELL=y
    CONFIG_NET_STATISTICS=y
    
    # Sockets
    CONFIG_NET_SOCKETS=y
    CONFIG_NET_SOCKETS_POSIX_NAMES=y
    CONFIG_NET_SOCKETS_POLL_MAX=4
    
    # Network driver config
    CONFIG_TEST_RANDOM_GENERATOR=y
    
    # Network address config
    #CONFIG_NET_CONFIG_SETTINGS=y
    #CONFIG_NET_CONFIG_NEED_IPV4=y
    #CONFIG_NET_CONFIG_NEED_IPV6=y
    #CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.0.2.1"
    #CONFIG_NET_CONFIG_MY_IPV4_GW="192.0.2.2"
    # Address of HTTP IPv4 server
    #CONFIG_NET_CONFIG_PEER_IPV4_ADDR="192.0.2.2"
    #CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8::1"
    # Address of HTTP IPv6 server
    #CONFIG_NET_CONFIG_PEER_IPV6_ADDR="2001:db8::2"
    
    # HTTP & Websocket
    CONFIG_HTTP_CLIENT=y
    CONFIG_WEBSOCKET_CLIENT=y
    
    # Network debug config
    CONFIG_LOG=y
    CONFIG_LOG_MODE_IMMEDIATE=y
    CONFIG_NET_LOG=y
    #CONFIG_NET_SOCKETS_LOG_LEVEL_DBG=y
    #CONFIG_NET_HTTP_LOG_LEVEL_DBG=y
    #CONFIG_NET_WEBSOCKET_LOG_LEVEL_DBG=y
    #CONFIG_NET_CONTEXT_LOG_LEVEL_DBG=y
    #CONFIG_NET_TCP_LOG_LEVEL_DBG=y
    
    
    # 打开NET网络配置
    CONFIG_NETWORKING=y
    CONFIG_NET_DHCPV4=y
    CONFIG_NET_IPV4=y
    CONFIG_NET_SOCKETS=y
    CONFIG_TEST_RANDOM_GENERATOR=y
    CONFIG_NET_SOCKETS_POSIX_NAMES=y
    
    # 网络管理配置
    CONFIG_NET_MGMT=y
    CONFIG_NET_MGMT_EVENT=y
    CONFIG_NET_MGMT_EVENT_STACK_SIZE=4096
    
    # 网络线程栈配置
    CONFIG_NET_RX_STACK_SIZE=2048
    CONFIG_NET_TX_STACK_SIZE=2048
    # 网络的内存池配置
    CONFIG_NET_PKT_RX_COUNT=16
    CONFIG_NET_PKT_TX_COUNT=16
    CONFIG_NET_BUF_RX_COUNT=64
    CONFIG_NET_BUF_TX_COUNT=64
    CONFIG_NET_CONTEXT_NET_PKT_POOL=y
    
    # 引用名为newlib的libc标准库
    CONFIG_NEWLIB_LIBC=y
    
    # SYSTEM WORKQUEUE线程栈
    CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096
    # 系统堆,分配内存,可根据实际使用配置
    #CONFIG_HEAP_MEM_POOL_SIZE=60000
    CONFIG_MAIN_STACK_SIZE=20000
    CONFIG_INIT_STACKS=y
    
    # 打开LOG配置
    CONFIG_LOG=y
    CONFIG_WIFI_LOG_LEVEL_DBG=y
    
    CONFIG_NET_TCP=y
    CONFIG_NET_SHELL=y
    CONFIG_NET_STATISTICS=y
    
    # Sockets
    CONFIG_NET_SOCKETS_POLL_MAX=4
    
    # HTTP & Websocket
    CONFIG_HTTP_CLIENT=y
    CONFIG_WEBSOCKET_CLIENT=y
    
    CONFIG_LOG_MODE_IMMEDIATE=y
    CONFIG_NET_LOG=y
    
    CONFIG_HWINFO=n
  • CMakeLists.txt

    FILE(GLOB app_sources
    src/bitmap.c
    src/storage.c
    src/button.c
    src/multi_button.c
    src/wifi_connect.c
    src/websocket.c
    ${MAIN_SRC}
    )
推荐阅读
关注数
5165
内容数
98
聆思科技官方专栏,专注AIOT芯片,持续分享有趣的解决方案。商务合作微信:listenai-csk 技术交流QQ群:825206462
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息