wifi_csi: add aml_wisense demo [1/1]
PD#SWPL-182948
Problem:
Only wifi driver supports obtaining CSI information.
There is no interface for get CSI info at the userspace.
Solution:
Add to obtain the csi lib, and add demo to send the csi
data to the algorithm library to obtain motion.
Verify:
A113L2 BA401 (W2l) Boards.
Change-Id: I0cae335345d3c7c152eff47a6f4e66d2847acbd1
Signed-off-by: shuai.liu <shuai.liu@amlogic.com>
diff --git a/aml_csi/CMakeLists.txt b/aml_csi/CMakeLists.txt
new file mode 100644
index 0000000..182976b
--- /dev/null
+++ b/aml_csi/CMakeLists.txt
@@ -0,0 +1,43 @@
+# Copyright (C) 2024 Amlogic, Inc. All rights reserved.
+#
+# All information contained herein is Amlogic confidential.
+#
+# This software is provided to you pursuant to Software License
+# Agreement (SLA) with Amlogic Inc ("Amlogic"). This software may be
+# used only in accordance with the terms of this agreement.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification is strictly prohibited without prior written permission
+# from Amlogic.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+cmake_minimum_required(VERSION 3.0)
+project(WiSense)
+
+set(CMAKE_CXX_STANDARD 17)
+
+add_executable(WiFiSensing ./main.cpp)
+set_target_properties(WiFiSensing PROPERTIES COMPILE_FLAGS "-pthread" LINK_FLAGS "-pthread")
+target_link_libraries(WiFiSensing ${ROOT_DIR}/test/aml_csi/alg_lib/libaaisdk.so
+ ${ROOT_DIR}/test/aml_csi/csi_lib/libamlcsi.so)
+target_include_directories(WiFiSensing PUBLIC ./alg_lib/include/common
+ ./alg_lib/include/common
+ ./csi_lib )
+
+install(TARGETS WiFiSensing
+ EXPORT ${PROJECT_NAME}Targets
+ RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}
+ )
diff --git a/aml_csi/Makefile b/aml_csi/Makefile
new file mode 100644
index 0000000..85d7e93
--- /dev/null
+++ b/aml_csi/Makefile
@@ -0,0 +1,23 @@
+OUT_DIR ?= .
+TARGET= aml_wisense
+
+CFLAGS += -g -DAML_DEBUG -fPIC -lpthread -std=c++11
+LDFLAGS += -lamlcsi -laaisdk
+LDFLAGS += -L ./csi_lib \
+ -L ./alg_lib
+
+SRCS= main.cpp
+
+all: $(TARGET)
+
+${TARGET}: ${SRCS}
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $(OUT_DIR)/$@ $^
+
+clean:
+ rm $(TARGET)
+
+install:
+ install -m 0755 ${TARGET} $(TARGET_DIR)/usr/bin/
+
+uninstall:
+ rm -f $(TARGET_DIR)/usr/bin/${TARGET}
diff --git a/aml_csi/README.md b/aml_csi/README.md
new file mode 100644
index 0000000..0524159
--- /dev/null
+++ b/aml_csi/README.md
@@ -0,0 +1,74 @@
+# Usage
+## prepare
+Request algorithm library and place the algorithm library to `${SDK}/vendor/amlogic/aml_csi/alg_lib/libaaisdk.so`.
+And place related header files to following path:
+`${SDK}/vendor/amlogic/aml_csi/alg_lib/include/iva/iva_wisense_ppd.hpp`
+`${SDK}/vendor/amlogic/aml_csi/alg_lib/include/iva/iva.hpp`
+`${SDK}/vendor/amlogic/aml_csi/alg_lib/include/iva/iva_wisense_ppd.hpp`
+
+## Custom led
+`${SDK}/vendor/amlogic/aml_csi/main.cpp` adaptation wisense_led_init()& wisense_led_set() function.
+
+
+## Compile
+Take ba401 as an example, add the following configuration to `${SDK}/buildroot/configs/amlogic/a4_ba401.config` file:
+```
+BR2_PACKAGE_AML_CSI=y
+```
+
+run the following command to compile:
+```bash
+make aml-csi-rebuild && make
+```
+
+## Config network
+Start the system and then close system log(Optional):
+```bash
+echo 1 4 1 7 > /proc/sys/kernel/printk
+```
+
+Connect to wifi:
+```bash
+wpa_cli -iwlan0 remove_network 0
+wpa_cli -iwlan0 add_network 0
+wpa_cli -iwlan0 set_network 0 ssid '"WiFi name"'
+wpa_cli -iwlan0 set_network 0 key_mgmt WPA-PSK
+wpa_cli -iwlan0 set_network 0 psk '"password"'
+wpa_cli -iwlan0 set_network 0 pairwise CCMP TKIP
+wpa_cli -iwlan0 set_network 0 group CCMP TKIP
+wpa_cli -iwlan0 set_network 0 proto RSN
+wpa_cli -iwlan0 enable_network 0
+wpa_cli -iwlan0 status
+wpa_cli -iwlan0 save
+dhcpcd wlan0
+```
+
+## Run aml_wisense demo
+
+```bash
+aml_wisense -l level
+```
+
+level represents the detection sensitivity level, and the specified parameters are 1, 2, 3, and 4. The larger of the number, the higher the detection sensitivity of the algorithm.
+
+# Development
+## Pipeline
+ csi data csi data wi_out_ret
+wifi driver ---------> aml_wisense --------> wisense alg ----------> result
+
+## parameter
+aml_wisense will automatically obtain csi data and send it to the algorithm interface, and the algorithm will return the operation result(wi_out_ret).
+
+wi_out_ret as follows:
+
+- wi_out_ret.motion_status(int):
+ - 1: There is motion that meets the level requirements.
+ - 0: There is no motion that meets the level requirements.
+
+- wi_out_ret.motion_class(int): The motion level detected by the algorithm, the larger of the value, the smaller the motion.
+ - 1 or 2: Small motion, detect close range motion. A single person is within 3m range, and multiple people is within 5m range.
+ - 3 or 4: Large motion, detect long distance motion or close range slight motion. Range up to 12m.
+ - 0: There is no motion.
+
+- wi_out_ret.motion_value(float): Motion complex value.
+ Float value from 0 to 1, it reflects the complexity of the current motion environment. The larger of the value, the more complex of the current motion environment is.
diff --git a/aml_csi/csi_lib/aml_csi.h b/aml_csi/csi_lib/aml_csi.h
new file mode 100644
index 0000000..f143427
--- /dev/null
+++ b/aml_csi/csi_lib/aml_csi.h
@@ -0,0 +1,179 @@
+// Copyright (C) 2024 Amlogic, Inc. All rights reserved.
+//
+// All information contained herein is Amlogic confidential.
+//
+// This software is provided to you pursuant to Software License
+// Agreement (SLA) with Amlogic Inc ("Amlogic"). This software may be
+// used only in accordance with the terms of this agreement.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification is strictly prohibited without prior written permission
+// from Amlogic.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef AML_CSI_H
+#define AML_CSI_H
+
+#define CONFIG_W1 0
+#define CONFIG_W2 1
+
+#define IFNAME "wlan0"
+
+#define USE_POLL 0
+#define USE_NETLINK 1
+
+#define LINUX_PLATFORM
+
+#ifdef LINUX_PLATFORM
+#define USE_APK 0
+#else
+#define USE_APK 1
+#endif
+
+#define FILTER_MASK_NSS (1 << 0)
+#define FILTER_MASK_AP_CAP (1 << 1)
+#define FILTER_MASK_BW (1 << 2)
+#define FILTER_MASK_FR_TYPE (1 << 3)
+#define FILTER_MASK_TX_ADDR (1 << 4)
+#define FILTER_MASK_RX_ADDR (1 << 5)
+
+/****AP capability*******/
+enum {
+ FORMATMOD_NON_HT = 1, //0 for not setting
+ FORMATMOD_NON_HT_DUP_OFDM,
+ FORMATMOD_HT_MF,
+ FORMATMOD_HT_GF,
+ FORMATMOD_VHT,
+ FORMATMOD_HE_SU,
+ FORMATMOD_HE_MU,
+ FORMATMOD_HE_ER,
+};
+/****Bandwidth*****/
+enum {
+ BW_20M = 1, //0 for not setting
+ BW_40M,
+ BW_80M,
+};
+
+enum {
+ CSI_COM_DATA = 1,
+ CSI_LINK_INFO_DATA,
+};
+
+#if CONFIG_W1
+typedef struct {
+ unsigned long long time_stamp;
+ unsigned char mac_ra[6];
+ unsigned char mac_ta[6];
+ unsigned char frequency_band;
+ unsigned char bw;
+ char rssi;
+ unsigned char protocol_mode;
+ unsigned char frame_type;
+ unsigned char chain_num;
+ unsigned char csi_len;
+ unsigned char snr;
+ unsigned char primary_channel_index;
+ unsigned char noise;
+ unsigned char phyerr;
+ unsigned char rate;
+ unsigned int extra_information;
+ unsigned short agc_code;
+ short phase_incr;
+ unsigned short channel;
+ unsigned char reserved[2];
+ unsigned int packet_idx;
+ unsigned char csi[1024];
+}csi_stream;
+#else
+typedef struct {
+ unsigned long long time_stamp;
+ unsigned char mac_ra[6];
+ unsigned char mac_ta[6];
+ unsigned char frequency_band;
+ unsigned char bw;
+ unsigned short sequence_no;
+ char rssi[4];
+ unsigned char snr[4];
+ unsigned char noise[4];
+ char phase_incr[4];
+ unsigned int protocol_mode;
+ unsigned char frame_type;
+ unsigned char chain_num;
+ unsigned char tones_num;
+ unsigned char phyerr;
+ unsigned short primary_channel_index;
+ unsigned char rate;
+ unsigned char csi_ready;
+ unsigned short agc_code[2];
+ unsigned short channel;
+ unsigned short reserved3;
+ unsigned int packet_idx;
+ /*add*/
+ unsigned int nrx;
+ unsigned int ntx;
+ unsigned int perm;
+ unsigned int csi_len;
+ unsigned int payload_len;
+ unsigned int extra_info;
+ unsigned char csi[4][1024];
+}csi_stream;
+
+
+typedef struct {
+ unsigned char bw;
+ unsigned char nss;
+ unsigned char protocol_mode;
+}csi_link_info;
+
+#define H11 0x01
+#define H12 0x02
+#define H21 0x04
+#define H22 0x08
+#endif
+
+
+#if USE_APK
+typedef void (*csi_data_cb)(void);
+#else
+typedef void (*csi_data_cb)(unsigned char *csi_data, int csi_data_len);
+#endif
+
+/* csi_start: start csi capture thread
+ * period: capture time, uint: second
+*/
+int csi_start(int *period);
+int csi_stop(char *ra);
+/* csi_set_config: config csi capture interval
+ * interval: uint: millisecond
+*/
+int csi_set_config(char *ra, unsigned int interval, unsigned char frame_mode);
+int csi_set_chain(int chain_flag);
+int csi_register_data_recv_func(char *ra, csi_data_cb cb);
+void csi_enable_debug(int enable);
+int csi_get_data(csi_stream *cs, int *data_len);
+/* ping_start: ping target
+ * ip: target ip
+ * interval: uint: millisecond
+*/
+int ping_start(const char *ip, int interval);
+void ping_stop(void);
+
+/*csi_set_filter
+ *value of param, 0 or NULL for not setting is Auto mode
+ -1 is Do not filter any packages---Only for the first four parameters
+ */
+void csi_set_filter(int nss, int ap_capability, int bandwitdh, int frame_type, char* tx_mac, char* rx_mac, int ping_interval, char *ip);
+
+#endif
diff --git a/aml_csi/main.cpp b/aml_csi/main.cpp
new file mode 100644
index 0000000..794adda
--- /dev/null
+++ b/aml_csi/main.cpp
@@ -0,0 +1,236 @@
+// Copyright (C) 2024 Amlogic, Inc. All rights reserved.
+//
+// All information contained herein is Amlogic confidential.
+//
+// This software is provided to you pursuant to Software License
+// Agreement (SLA) with Amlogic Inc ("Amlogic"). This software may be
+// used only in accordance with the terms of this agreement.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification is strictly prohibited without prior written permission
+// from Amlogic.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <string.h>
+#include <semaphore.h>
+#include <time.h>
+
+#include <thread>
+#include <string>
+#include <iostream>
+#include <chrono>
+
+#include "alg_lib/include/iva/iva_wisense_ppd.hpp"
+
+extern "C" {
+#include "csi_lib/aml_csi.h"
+}
+
+static int cnt = 0;
+static int motion_status = -1;
+static WiSenseIn g_csi_buffer;
+static WiSenseIn *g_csi_detail = &g_csi_buffer;
+
+static aai_iva_wisense_ppd_handle_t iva_wisense_ppd_handle;
+static aai_iva_wisense_ppd_output_t wi_out_ret;
+static aai_iva_wisense_ppd_input_t wi_in;
+static aai_iva_wisense_ppd_mlevel_t mlevel;
+static aai_iva_wisense_ppd_param_t params;
+static std::string g_ctimes = "";
+
+static volatile bool keep_running = true;
+static sem_t semaphore;
+
+/*print different colors*/
+#define RED "\033[31m" /* Red */
+#define GREEN "\033[32m" /* Green */
+#define YELLOW "\033[33m" /* Yellow */
+#define BLUE "\033[34m" /* Blue */
+#define MAGENTA "\033[35m" /* Magenta */
+#define CYAN "\033[36m" /* Cyan */
+#define WHITE "\033[37m" /* White */
+
+/*
+copy csi to WiSenseIn struct,when get csi about 20 packets, send them to algorithm api
+*/
+void csi_cb(unsigned char *csi_data, int csi_data_lean) {
+ csi_stream *c = (csi_stream *)csi_data;
+
+ if (keep_running) {
+ if (cnt < 20) {
+ g_csi_detail->time_stamp[cnt] = c->time_stamp;
+ g_csi_detail->rssi[cnt][0] = c->rssi[0];
+ g_csi_detail->rssi[cnt][1] = c->rssi[1];
+ g_csi_detail->bw[cnt] = static_cast<int>((unsigned char)c->bw);
+ g_csi_detail->ntx[cnt] = c->ntx;
+ g_csi_detail->channel[cnt] = c->channel;
+ g_csi_detail->protocol_mode[cnt] = c->protocol_mode;
+ memcpy(g_csi_detail->csi[cnt], c->csi, 4 * 1024);
+
+ cnt++;
+ if (cnt == 20) {
+ sem_post(&semaphore);
+ }
+ }
+ }
+}
+
+void csi_data_collection_start(void)
+{
+ int interval = 50;
+ int period = 0;
+
+ csi_enable_debug(0);
+ ping_start(NULL, 50);
+ csi_register_data_recv_func(NULL, csi_cb);
+ csi_set_config(NULL, interval, 1);
+ csi_set_filter(0, 0, 0, 0, NULL, NULL,0, NULL);
+ csi_start(&period);
+
+ return;
+}
+
+void csi_data_collection_end(void)
+{
+ csi_stop(NULL);
+ ping_stop();
+}
+
+/*
+ * @brief If you want to turn on the light when motion is wisense detected,
+ * you can define WISENSE_LED_ACTION macro and specify the gpio num on your board.
+ * */
+void wisense_led_init(void)
+{
+#if WISENSE_LED_ACTION
+ system("echo 449 > /sys/class/gpio/export");
+ system("echo out > /sys/class/gpio/gpio449/direction");
+#endif
+}
+
+/*
+ * @brief If you want to turn on the light when wisense motion is detected,
+ * you can define WISENSE_LED_ACTION macro and specify the gpio num on your board.
+ * */
+void wisense_led_set(int value)
+{
+#if WISENSE_DEBUG
+ std::chrono::milliseconds ms = std::chrono::duration_cast< std::chrono::milliseconds >(
+ std::chrono::system_clock::now().time_since_epoch()
+ );
+ std::cout << ms.count()/100 << std::endl;
+#endif
+
+ std::cout << "--->motion status is " << value << std::endl;
+#if WISENSE_LED_ACTION
+ if (value) {
+ system("echo 1 > /sys/class/gpio/gpio449/value"); // Red led
+ else
+ system("echo 0 > /sys/class/gpio/gpio449/value"); // Green led
+#endif
+}
+
+void update_current_time(void) {
+ auto now = std::chrono::system_clock::now();
+ auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);
+ std::time_t t = std::chrono::system_clock::to_time_t(now_ms);
+ std::tm *now_tm = std::localtime(&t);
+ char buffer[100];
+ std::strftime(buffer, sizeof(buffer), "%Y%m%d%H%M%S", now_tm);
+ g_ctimes = buffer;
+}
+
+void* wisense_processing_thread(void* arg)
+{
+ while (keep_running) {
+ sem_wait(&semaphore);
+ if (cnt >= 20) {
+ cnt = 0;
+ update_current_time();
+ wi_in.wisenseIn = g_csi_detail;
+ aai_iva_wisense_ppd_detect(iva_wisense_ppd_handle, wi_in, wi_out_ret, params);
+ motion_status = wi_out_ret.motion_status;
+ wisense_led_set(motion_status);
+ switch (wi_out_ret.motion_class) {
+ case 1:
+ std::cout << RED << "Motion class is 1. Large human activity in close range[TX/RX] at " << g_ctimes << "\033[0m\n";
+ break;
+ case 2:
+ std::cout << MAGENTA << "Motion class is 2. Human activity at " << g_ctimes << "\033[0m\n";
+ break;
+ case 3:
+ std::cout << GREEN << "Motion class is 3. Human activity at " << g_ctimes << "\033[0m\n";
+ break;
+ case 4:
+ std::cout << GREEN << "Motion class is 4. Lightweight motion. Human activity at " << g_ctimes << "\033[0m\n";
+ break;
+ case 5:
+ std::cout << GREEN << "Motion class is 5. Lightweight motion. Human activity at " << g_ctimes << "\033[0m\n";
+ break;
+ default:
+ std::cout << YELLOW << "Motion class is 0, No person activity detect at " << g_ctimes << "\033[0m\n";
+ break;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+int main(int argc, char** argv)
+{
+ int opt;
+ int mlevel = 4;
+
+ while ((opt = getopt(argc, argv, "l:")) != -1) {
+ switch (opt)
+ {
+ case 'l':
+ mlevel = atoi(optarg);
+ break;
+ default:
+ break;
+ }
+ }
+
+
+ sem_init(&semaphore, 0, 0);
+
+ wisense_led_init();
+ csi_data_collection_start();
+
+ iva_wisense_ppd_handle = aai_iva_wisense_ppd_init(params);
+
+ if (iva_wisense_ppd_handle != NULL) {
+ params.e_mlevel = static_cast<aai_iva_wisense_ppd_mlevel_t>(mlevel);
+ aai_iva_wisense_ppd_param_set(iva_wisense_ppd_handle, params);
+ std::thread wisense_thread(wisense_processing_thread, nullptr);
+ wisense_thread.join();
+ }
+
+ csi_data_collection_end();
+
+ if (iva_wisense_ppd_handle != NULL) {
+ aai_iva_wisense_ppd_deinit(iva_wisense_ppd_handle);
+ }
+
+ sem_destroy(&semaphore);
+
+ return 0;
+}
+