Wi-Fi CSI Introduction

Wi-Fi CSI (Channel State Information) is a technology used to describe the characteristics of wireless channels. It aims to quantify the aggregate effect of wireless phenomena (such as interference, multipath, doppler shift…) on wireless signals in a given environment by reporting complete CSIs. And can be used in applications such as human activity analysis, Wi-Fi indoor positioning, and gesture recognition.

Realtek Wi-Fi CSI is divided into Active CSI and Passive CSI schemes based on whether the Realtek device (STA mode or SoftAP mode) participates in transmitting the CSI triggering frames.

  • Active CSI: The Realtek device needs to actively transmit CSI triggering frames

    • Active CSI is divided into two modes based on the type of CSI triggering frame: unicast mode and broadcast mode. For details, refer to Active CSI: Unicast Mode and Active CSI: Broadcast Mode.

    • Using Public Action frame as CSI triggering frame in Active CSI.

  • Passive CSI: The Realtek device is not required to transmit CSI triggering frames

Active CSI: Unicast Mode

  • METHOD1: A Realtek STA transmits a unicast CSI triggering frame to the AP and derives CSI from the ACK response to the previous CSI triggering frame (one-to-one communication).

  • METHOD1_Variant: A Realtek STA transmits a unicast CSI triggering frame to another STAx and derives CSI from the ACK response to the previous CSI triggering frame (one-to-many communication via polling).

  • METHOD2: A Realtek SoftAP transmits a unicast CSI triggering frame to associated stations and derives CSI from the ACK response to the previous unicast CSI triggering frame (one-to-many communication via polling).

../../rst_wifi/2_wifi_csi/figures/collecting_csi_from_rx_ack_packet_response_mode.svg

Collect CSI from Rx ACK Packet in Rx Response Mode

Active CSI: Broadcast Mode

  • METHOD3: Realtek SoftAP transmits a broadcast CSI triggering frame, which are decoded by Realtek STAs to derive CSI.

  • METHOD4: A Realtek STA transmits a broadcast CSI triggering frame, which are decoded by neighboring Realtek STAs to derive CSI.

../../rst_wifi/2_wifi_csi/figures/collecting_csi_from_rx_broadcast_packet_normal_mode.svg

Collect CSI from Rx Broadcast Packet in Rx Normal Mode

Passive CSI

  • METHOD5: A Realtek STA/SoftAP derives CSI from received packets in Rx Normal Mode (one-to-one communication).

../../rst_wifi/2_wifi_csi/figures/collecting_csi_from_rx_packet_normal_mode.svg

Collect CSI from Rx packet in Rx Normal Mode

Wi-Fi CSI Interface Guide

Wi-Fi CSI report mainly consists of three modules:

  • Configure and Enable/Disbale Wi-Fi CSI

    • The application need to call the API to configure Wi-Fi CSI parameters as needed and then enable the Wi-Fi CSI function.

    • The application must call the API to disable the Wi-Fi CSI function when inactive.

  • Register/Deregister Wi-Fi CSI Callback

    • Register a Wi-Fi CSI callback function when enabling Wi-Fi CSI.

      • The Wi-Fi driver will directly send the CSI report and length information to the application through the callback function.

      • The callback function should perform minimal operations.

    • Release the Wi-Fi CSI callback function when disabling Wi-Fi CSI.

  • Report Wi-Fi CSI

    • The application must maintain a buffer queue to store and process Wi-Fi CSI packets.

    • The application must create a dedicated thread that waits for a Wi-Fi CSI-ready semaphore and processes the buffered Wi-Fi CSI packets.

    • The application should use a callback function to store Wi-Fi CSI packets in the buffer queue and releases a semaphore to wake up the dedicated thread.

../../rst_wifi/2_wifi_csi/figures/csi_architecture.svg

Wi-Fi CSI architecture

Configuring/Enabling/Disabling Wi-Fi CSI

Calling wifi_csi_config() to configure and enable/disable the Wi-Fi CSI function.

Configuration Parameter

Parameter

Type

Description

group_num

u8

Specify the CSI info subcarrier decimation

  • 0: per tone

  • 1: per 2 tone

  • 2: per 4 tone

  • 3: per 8 tone

accuracy

u8

Specify the CSI raw data (CH I: In-phase, real part / Q: Quadrature, imaginary part) word length

  • 0: S(8,3) -> a signed 8-bit number with 3 fractional bits

  • 1: S(16,11) -> a signed 16-bit number with 11 fractional bits

alg_opt

u8

Reserved

ch_opt

u8

Configure CSI acquisition from leagcy or non-legacy LTF

csi_role

u8

Specify the operational role of devices with Wi-Fi CSI enabled

mode

u8

Specify which mode for fetching Wi-Fi CSI

  • 0: Rx Normal Mode (estimating CSI by the currently received packet)

  • 2: Rx Response Mode (estimating CSI by receiving ACK for the previous transmission)

  • others reserved

act

u8

Enable Wi-Fi CSI or configure Wi-Fi CSI parameters

trig_frame_mgnt

u16

Specify frame type(s) of CSI triggering frame for fetching CSI (used for Rx Normal Mode and no need for Rx Response Mode)

trig_frame_ctrl

u16

Specify frame type(s) of CSI triggering frame for fetching CSI (used for Rx Normal Mode and no need for Rx Response Mode)

trig_frame_data

u16

Specify frame type(s) of CSI triggering frame for fetching CSI (used for Rx Normal Mode and no need for Rx Response Mode)

enable

u8

  • 0: disable Wi-Fi CSI function

  • 1: enable Wi-Fi CSI function

trig_period

u8

Wi-Fi CSI sounding rate, unit: 320us (recommended value: 15~255)

data_rate

u8

Specify Tx data rate of CSI triggering frame, but the parameters is invalid in Rx Response Mode for getting Wi-Fi CSI

because Wi-Fi CSI dependeds on the data rate of the response ACK frame.

  • Only support OFDM/HT rate

data_bw

u8

Specify the bandwidth of CSI triggering frame, but the parameters is invalid in Rx Response Mode for getting Wi-Fi CSI

because Wi-Fi CSI dependeds on the bandwidth of the response ACK frame.

  • 0: 20MHz

  • 1: 40MHz

  • Others: reserved

Note

If data_bw = 1, data_rate must be set to at least RTW_RATE_MCS0

mac_addr[6]

u8

Specify destination address (MAC address) for CSI triggering frame (purpose to fetch CSI information from response packet)

  • If multi_type = 1, the mac_addr is reserved.

multi_type

u8

Specify whether the CSI triggering frame is unicast or broadcast, only valid in Active CSI.

  • 0: unicast (using unicast packet and fetching CSI from the ACK for unicast packet)

  • 1: broadcast (using broadcast packet and other devices fetching CSI from the broadcast packet)

trig_flag

u8

Specify role for transmitting CSI triggering frame in METHOD4 and role for transmitting response ACK for CSI triggering

frame in METHOD1_Variant, others are reserved.

  • Value = 1 ~ 15 (0 is reserved)

Parameter Values

  • The values of group_num:

    /**
    * @brief csi group num.
    */
    enum {
       RTW_CSI_GROUP_NUM_1 = 0,  /**< per tone */
       RTW_CSI_GROUP_NUM_2,      /**< per 2tone */
       RTW_CSI_GROUP_NUM_4,      /**< per 4tone */
       RTW_CSI_GROUP_NUM_8_16,   /**< per 8tone for dplus; per 16tone for others */
       RTW_CSI_GROUP_NUM_MAX
    };
    
  • The values of accuracy:

    /**
    * @brief csi accuracy.
    */
    enum {
       RTW_CSI_ACCU_1BYTE = 0,   /**< S(8,3) for dplus and S(8,4) for others */
       RTW_CSI_ACCU_2BYTES,      /**< S(16,11) for dplus and S(16,12) for others */
       RTW_CSI_ACCU_MAX
    };
    
  • The values of ch_opt:

    /**
    * @brief csi ch_opt.
    */
    enum {
       RTW_CSI_CH_LEGACY = 0,    /**< legacy part(L-LTF) channel estmation result */
       RTW_CSI_CH_NON_LEGACY,    /**< non-legacy(HT-LTF) part */
       RTW_CSI_CH_MAX
    };
    
  • The values of csi_role:

    /**
    * @brief csi csi_role.
    */
    enum {
       RTW_CSI_OP_ROLE_TRX = 0,  /**< both trx */
       RTW_CSI_OP_ROLE_TX  = 1,  /**< only tx csi triggering frame */
       RTW_CSI_OP_ROLE_RX  = 2,  /**< only rx csi triggering frame for fetching csi report */
       RTW_CSI_OP_ROLE_MAX
    };
    
  • The values of mode:

    /**
    * @brief csi mode.
    */
    enum {
       RTW_CSI_MODE_NORMAL = 0,  /**< rx normal mode */
       RTW_CSI_MODE_NDP,         /**< rx ndp mode: not support */
       RTW_CSI_MODE_RX_RESP,     /**< rx response mode */
       RTW_CSI_MODE_MAX,
    };
    
  • The values of act:

    /**
    * @brief csi enable or config.
    */
    enum {
       RTW_CSI_ACT_EN,           /**< enable or disable csi func */
       RTW_CSI_ACT_CFG,          /**< config csi parameters */
       RTW_CSI_ACT_MAX
    };
    
  • The values of trig_frame_mgnt:

    /**
    * @brief csi trig management frame subtype.
    */
    enum {
       RTW_CSI_TRIG_ASSOCREQ   = BIT(0),
       RTW_CSI_TRIG_ASSOCRSP   = BIT(1),
       RTW_CSI_TRIG_REASSOCREQ = BIT(2),
       RTW_CSI_TRIG_REASSOCRSP = BIT(3),
       RTW_CSI_TRIG_PROBEREQ   = BIT(4),
       RTW_CSI_TRIG_PROBERSP   = BIT(5),
       RTW_CSI_TRIG_BEACON     = BIT(8),
       RTW_CSI_TRIG_ATIM       = BIT(9),
       RTW_CSI_TRIG_DISASSOC   = BIT(10),
       RTW_CSI_TRIG_AUTH       = BIT(11),
       RTW_CSI_TRIG_DEAUTH     = BIT(12),
       RTW_CSI_TRIG_ACTION     = BIT(13)
    };
    
  • The values of trig_frame_ctrl:

    /**
    * @brief csi trig control frame subtype.
    */
    enum {
       RTW_CSI_TRIG_TRIGGER     = BIT(2),
       RTW_CSI_TRIG_BA          = BIT(9),
       RTW_CSI_TRIG_PSPOLL      = BIT(10),
       RTW_CSI_TRIG_RTS         = BIT(11),
       RTW_CSI_TRIG_CTS         = BIT(12),
       RTW_CSI_TRIG_ACK         = BIT(13),
       RTW_CSI_TRIG_CFEND       = BIT(14),
       RTW_CSI_TRIG_CFEND_CFACK = BIT(15)
    };
    
  • The values of trig_frame_data:

    /**
    * @brief csi trig data frame subtype.
    */
    enum {
       RTW_CSI_TRIG_DATA           = BIT(0),
       RTW_CSI_TRIG_DATA_CFACK     = BIT(1),
       RTW_CSI_TRIG_DATA_CFPOLL    = BIT(2),
       RTW_CSI_TRIG_DATA_CFACKPOLL = BIT(3),
       RTW_CSI_TRIG_DATA_NULL      = BIT(4),
       RTW_CSI_TRIG_CF_ACK         = BIT(5),
       RTW_CSI_TRIG_CF_POLL        = BIT(6),
       RTW_CSI_TRIG_CF_ACKPOLL     = BIT(7),
       RTW_CSI_TRIG_QOS_DATA       = BIT(8),
       RTW_CSI_TRIG_QOS_DATA_NULL  = BIT(12)
    };
    
  • The values of data_rate:

    /**
    * @brief The enumeration lists the BIT 7 HT Rate.
    */
    enum {
       RTW_RATE_1M      = 0x02,     /**< 0x02 */
       RTW_RATE_2M      = 0x04,     /**< 0x04 */
       RTW_RATE_5_5M    = 0x0B,     /**< 0x0B */
       RTW_RATE_6M      = 0x0C,     /**< 0x0C */
       RTW_RATE_9M      = 0x12,     /**< 0x12 */
       RTW_RATE_11M     = 0x16,     /**< 0x16 */
       RTW_RATE_12M     = 0x18,     /**< 0x18 */
       RTW_RATE_18M     = 0x24,     /**< 0x24 */
       RTW_RATE_24M     = 0x30,     /**< 0x30 */
       RTW_RATE_36M     = 0x48,     /**< 0x48 */
       RTW_RATE_48M     = 0x60,     /**< 0x60 */
       RTW_RATE_54M     = 0x6C,     /**< 0x6C */
    
       RTW_RATE_MCS0    = 0x80,     /**< 0x80 */
       RTW_RATE_MCS1,               /**< 0x81 */
       RTW_RATE_MCS2,               /**< 0x82 */
       RTW_RATE_MCS3,               /**< 0x83 */
       RTW_RATE_MCS4,               /**< 0x84 */
       RTW_RATE_MCS5,               /**< 0x85 */
       RTW_RATE_MCS6,               /**< 0x86 */
       RTW_RATE_MCS7,               /**< 0x87 */
    
       RTW_RATE_UNKNOWN = 0xFF      /**< MAX */
    };
    

Registering/Unregistering Wi-Fi CSI Callback Function

Registering a callback function for the RTW_EVENT_CSI_DONE event by calling wifi_reg_event_handler(). The application will be notified via this callback when a Wi-Fi CSI report is ready.

  • Minimize time-consuming operations in the callback function. It is recommended to perform memory copying and release a semaphore to notify a dedicated thread to process the Wi-Fi CSI packets.

When the Wi-Fi CSI function is disabled, wifi_unreg_event_handler() must be called synchronously to unregister the previously registered RTW_EVENT_CSI_DONE event callback.

Wi-Fi CSI Reporting

The callback function stores the Wi-Fi CSI packets in a local buffer queue and wake up a dedicated thread for subsequent processing of the local CSI data.

CSI Report Layout

The CSI report is divided into two sections: CSI header information and CSI raw data. The size of the raw data is indicated by csi_data_length field within the CSI header information.

../../rst_wifi/2_wifi_csi/figures/csi_buffer_layout.svg

CSI buffer layout

CSI Header Information

The CSI header information follows a fixed-order format consisting of predefined fields. The diagram below illustrates the structure of the CSI header information.

../../rst_wifi/2_wifi_csi/figures/csi_header_information_format.svg

CSI header information format

The following list shows the description of each field.

Subfield

Size (bytes)

Definition

csi_signature

2

Pattern that may be used to detect a new CSI packet.

The unique pattern is set to the value 0xABCD.

hdr_len

1

Length of the CSI header information except the subfields of csi_signature and hdr_len.

mac_addr

6

Device MAC address, indicates transmitter address of CSI triggering frame in Active CSI

and receiver address of CSI triggering frame in Passive CSI.

trig_addr

6

Device MAC address, indicates destination address of CSI triggering frame in Active CSI

and source address of CSI triggering frame in Passive CSI.

  • Reserved in METHOD4

hw_assigned_timestamp

4

CSI timestamp, unit: us.

csi_sequence

4

CSI packet sequence number (invalid in METHOD4).

csi_data_length

4

CSI raw_data length, unit: byte.

csi_valid

1

Indicate the current CSI raw data whether valid.

channel

1

Operation channel of current device.

bandwidth

1

Operation bandwidth.

  • 0: 20MHz

  • 1: 40MHz

rx_rate

1

Indicate the rate of packet which used to derive CSI.

protocol_mode

1

Inidcate the protocol mode of the packet which is used to fetch CSI.

  • 0: OFDM

  • 1: HT

  • 2: VHT

  • 3: HE

num_sub_carrier

2

Number of subcarriers contain in CSI raw data.

num_bit_per_tone

1

CSI data word length (sum of I and Q).

Accuracy: S(8,X) or S(16,X)

rssi[2]

1

Received signal strength, dBm, rssi[1] is reserved.

evm[2]

2

Error vector magnitude, dB, Reserved.

rxsc

1

Indicate which sub 20M channel is used to transmit packet.

n_rx

1

Reserved.

n_sts

1

Reserved.

trig_flag

1

Idicates source of role for triggering CSI

Valid in only METHOD4 and reserved in other METHODs.

rsvd

5

Reserved.

Example of CSI header information & raw data

The following is a comparison of CSI buffer content and parsed CSI header information:

../../rst_wifi/2_wifi_csi/figures/comparison_between_parsed_csi_header_information_data_and_csi_buffer_data.svg

Comparison between the parsed CSI header information and the data in the CSI buffer

CSI Raw Data Layout

A tone index of -20MHz~0 corresponds to 64:127, and 0~20MHz corresponds to 0:63.

  • legacy 20MHz: tone_index (102, 103, …, 127, 1, 2, …, 26)

  • non-legacy 20MHz: tone_index (100, 101, 102, 103, …, 127, 1, 2, …, 26, 27, 28)

  • legacy 40MHz: tone_index (70, 71, …, 94, 95, 97, 98, …, 122, 6, 7, …, 30, 31, 33, 34, …, 57, 58)

  • non-legacy 40MHz: tone_index (71, 72, …, 127, 1, 2, …, 56, 57)

Example of CSI Raw Data (without Decimation): 20MHz

Each subcarrier (tone) has an Nrx*Nsts CSI matrix. Take a VHT MIMO 1x2 matrix as an example (group_num: 1 + accuracy: 0), the sequences of H are H11 and H12.

The layout of CSI raw data is:

../../rst_wifi/2_wifi_csi/figures/csi_raw_data_layout_without_decimation_dplus.svg

CSI raw data layout (without decimation)

Example of CSI Raw Data (with Decimation): 20MHz

Each subcarrier (tone) has an Nrx*Nsts CSI matrix. Take a VHT MIMO 1x2 matrix as an example (group_num: 3 + accuracy: 0), the sequences of H are H11 and H12. Select tone idx based on the principle of tone_idx%group_num==0.

The layout of CSI raw data is:

../../rst_wifi/2_wifi_csi/figures/csi_raw_data_layout_with_decimation_dplus.svg

CSI raw data layout (with decimation)

CSI Data Parsing Guide

Extract the first 4 bytes [f7 fd 0d ed] from CSI raw data and decode I/Q components as follows:

// 16-bit to float (Q5.11)
float get_csi_val_16(uint16_t data)
{
   float ret;
   if (data > 0x8000) {
      ret = (data - 0xffff - 1) * 1.0 / (1 << 11);
   } else {
      ret = data * 1.0 / (1 << 11);
   }

   return ret;
}

// 8-bit to float (Q5.3)
float get_csi_val_8(uint8_t data)
{
   float ret;
   if (data > 0x80) {
      ret = (data - 0xff - 1) * 1.0 / (1 << 3);
   } else {
      ret = data * 1.0 / (1 << 3);
   }

   return ret;
}

int main()
{
   /* accuracy = 1: S(16,11) */
   uint16_t Q_16 = 0xfdf7;
   uint16_t I_16 = 0xed0d;
   printf("CSI(16-bit): I=%04x Q=%04x -> (%f, %fj)\n", I_16, Q_16, get_csi_val_16(I_16), get_csi_val_16(Q_16));

   /* accuracy = 0: S(8,3) */
   uint8_t Q_8_1 = 0xf7;
   uint8_t I_8_1 = 0xfd;
   uint8_t Q_8_2 = 0x0d;
   uint8_t I_8_2 = 0xed;
   printf("CSI(8-bit): I=%02x Q=%02x -> (%f, %fj)\n", I_8_1, Q_8_1, get_csi_val_8(I_8_1), get_csi_val_8(Q_8_1));
   printf("CSI(8-bit): I=%02x Q=%02x -> (%f, %fj)\n", I_8_2, Q_8_2, get_csi_val_8(I_8_2), get_csi_val_8(Q_8_2));
}

//CSI(16-bit): I=ef0d Q=fdf7 -> (-2.368652, -0.254395j)
//CSI(8-bit): I=fd Q=f7 -> (-0.375000, -1.125000j)
//CSI(8-bit): I=ed Q=0d -> (-2.375000, 1.625000j)

Number of Subcarriers/Size for CSI Raw Data

Number of subcarriers ≈ N_tone(BW) * group_num

max_csi_report_size = Number of subcarriers * (accuracy + 1) + (hdr_len + 3)

BW

1

1/2

1/4

1/8

Non-HT

20M

52

26

12

6

208 + (hdr_len + 3)

HT

56

28

14

6

224 + (hdr_len + 3)

VHT

56

28

14

6

224 + (hdr_len + 3)

Non-HT

40M

104

52

24

12

416 + (hdr_len + 3)

HT

114

56

28

14

456 + (hdr_len + 3)

VHT

114

56

28

14

456 + (hdr_len + 3)

Wi-Fi CSI Notes

Basic Requirements

METHOD4 Design Considerations

METHOD1, METHOD2, METHOD3 and METHOD5 are normal interactions between STA and AP in infrastructure mode, Realtek driver will construct the MAC address of CSI triggering frame in accordance with Wi-Fi protocol standards.

For example, if the Ameba chip acts as the STA role, the frame format specified by the Wi-Fi standards is shown in the following figure:

../../rst_wifi/2_wifi_csi/figures/interaction_between_sta_and_ap_infrastructure_mode.svg

Interaction between STA and AP in infrastructure mode

However, METHOD4 involves interaction between STAs in infrastructure mode, which is not fully compliant with Wi-Fi protocol standards. To ensure other STAs can receive packets from the target STA, the Ameba chip will forge CSI triggering frame by modifying the MAC address fields of the CSI trigger frames to A1=broadcast address and A2=BSSID. This ensures that the MAC layer of Realtek receiving devices does not filter out the packets.

Note

Only when the Realtek MAC layer receives the Wi-Fi packet will it trigger the CSI circuit to capture CSI reports.

../../rst_wifi/2_wifi_csi/figures/interaction_between_sta_and_sta_infrastructure_mode.svg

Interaction between STA and STA in infrastructure mode

Additionally, METHOD4 has another issue: as shown in the figure above, Ameba2 receives Wi-Fi packets from both Ameba3 and Ameba1 with identical content, making it impossible for Ameba2 to distinguish whether the CSI packet was triggered by Ameba1 or Ameba3. To resolve this issue, we will fill the unique identifier trig_flag into the Fragment Number subfield in Sequence Control filed of Wi-Fi packet, and this identifier will be carried in the corresponding CSI packet. The application layer can distinguish which device the CSI belongs to base on trig_flag.

../../rst_wifi/2_wifi_csi/figures/mapping_trig_flag_with_sta.svg

Mapping of trig_flag with STAx

Compiling Wi-Fi CSI Image

  1. Navigate to {SDK}/amebaxxx_gcc_project and run the following command:

    ./menuconfig.py
    
  2. Locate CONFIG WIFI > Enable CSI, select Enable CSI, then save and exit.

    ----Connectivity config----
        CONFIG WHC INTF --->
        CONFIG WIFI --->
                 SDK MODE (NORMAL INIC)  --->
          [ ]    Enable WPS
          [*]    Enable CSI
          [ ]    Enable ANTDIV
          ---
        CONFIG BT --->
        ... --->
    
  3. Navigate to {SDK}/amebaxxx_gcc_project again and run the following command:

    ./build.py -a wifi_csi     /* compile image with Wi-Fi CSI example */
    ./build.py                 /* compile image without Wi-Fi CSI example */
    

The image bin files (xxx_app.bin & xxx_boot_all.bin) can be found in {SDK}/amebaxxx_gcc_project after compile done.

Wi-Fi CSI Example

This section describes the framework and implementation details of the Wi-Fi CSI example. The file path is {SDK}\component\example\wifi\wifi_csi.

Overview of Wi-Fi CSI Example

../../rst_wifi/2_wifi_csi/figures/csi_example_diagram.svg

Wi-Fi CSI example implementation block diagram

Details of Wi-Fi CSI Example

For guidance on integrating the Ameba SDK and compiling examples, refer to application_example. The following section details the implementation specifics of the Wi-Fi CSI example.

Example Initialization

The entry function for the Wi-Fi CSI example is defined in app_example().

void app_example(void)
{
   example_wifi_csi();  /* calling the entry function of Wi-Fi CSI example */
}

Wi-Fi CSI Entry Function

After executing Wi-Fi CSI example entry function: example_wifi_csi(),a CSI processing thread is created.

void example_wifi_csi(void)
{
   if (rtos_task_create(NULL, ((const char *)"wifi_csi_thread"), wifi_csi_thread, NULL, 1024 * 4, 1) != RTK_SUCCESS) {
      RTK_LOGA(NOTAG, "\n\r%s rtos_task_create(wifi_csi_thread) failed", __FUNCTION__);
   }

   return;
}

Wi-Fi CSI Thread

  1. Waiting for Wi-Fi power-up and connection success.

    1. If the SoftAP role is enabled, Wi-Fi CSI function will only be initiated by the SoftAP, regardless of whether STA role is in an associated state. Once other devices connect to the SoftAP role, the first connected device will be selected to enable the Wi-Fi CSI function.

      If no other devices connect to the SoftAP role, execute rtos_time_delay_ms(2000).

    2. If the SoftAP role is not enabled, the Wi-Fi CSI function will be enabled after the STA role connects to a realAP.

      If STA role is not connected, execute rtos_time_delay_ms(2000).

    while (1) {
       NEXT:
          if (wifi_is_running(SOFTAP_WLAN_INDEX)) {
             wifi_get_associated_client_list(&client_info);
             if (client_info.count) {
                memcpy(act_param.mac_addr, client_info.mac_list[0].octet, 6);
                RTK_LOGA(NOTAG, "### SOFTAP Break ###\r\n");
                break;
             }
             rtos_time_delay_ms(2000);  /* 2s */
             goto NEXT;
    
          }
          if (wifi_is_running(STA_WLAN_INDEX) && (wifi_get_join_status() == RTW_JOINSTATUS_SUCCESS) && (*(u32 *)LwIP_GetIP(0) != IP_ADDR_INVALID)) {
             rtos_time_delay_ms(2000);  /* 2s */
             RTK_LOGA(NOTAG, "### STA Break ###\r\n");
             break;
          }
          rtos_time_delay_ms(2000);  /* 2s */
    }
    
  2. Registering a Wi-Fi CSI callback function example_wifi_csi_report_cb().

    /* register Wi-Fi event callback function */
    wifi_reg_event_handler(RTW_EVENT_CSI_DONE, example_wifi_csi_report_cb, NULL);
    
  3. Initialize the Wi-Fi CSI buffer queue.

    /* init csi report buffer pool */
    if (wifi_csi_buffer_init() != RTK_SUCCESS) {
       goto done;
    }
    
  4. Initializing a semephore wc_ready_sema and use it to indicate that a Wi-Fi CSI packet is ready.

    /**
    * should use semaphore to wait wifi csi report happen
    * the following example shows that we wait for semaphore: `wc_ready_sema`
    */
    rtos_sema_create(&wc_ready_sema, 0, 0xFFFFFFFF);
    if (!wc_ready_sema) {
       RTK_LOGA(NOTAG, "ERR: wc_ready_sema failed\r\n");
    }
    
  5. Wi-Fi CSI parameters assignment (example configuration for METHOD1/ METHOD2).

    /* config csi parameters */
    act_param.group_num = RTW_CSI_GROUP_NUM_1;
    act_param.mode = RTW_CSI_MODE_RX_RESP;
    act_param.accuracy = RTW_CSI_ACCU_1BYTE;
    act_param.trig_period = 200;                  /* units: 320us */
    act_param.data_rate = RTW_RATE_6M;            /* ofdm 6 mpbs*/
    act_param.trig_frame_mgnt = 0;                /* no need for rx resp mode, default 0*/
    act_param.trig_frame_ctrl = 0;                /* no need for rx resp mode, default 0*/
    act_param.trig_frame_data = 0;                /* no need for rx resp mode, default 0*/
    act_param.csi_role = RTW_CSI_OP_ROLE_TRX;
    
  6. Configuring Wi-Fi CSI parameters and enabling Wi-Fi CSI.

    /* cis cfg and csi en */
    act_param.act = RTW_CSI_ACT_CFG;  /* csi cfg */
    wifi_csi_config(&act_param);
    
    act_param.act = RTW_CSI_ACT_EN;   /* csi en */
    act_param.enable = 1;
    wifi_csi_config(&act_param);
    
  7. Upon waiting for the wc_ready_sema semaphore to be signaled, dequeue Wi-Fi CSI packets from the buffer queue and process them accordingly.

    while (1) {
       /* example: when wifi csi rx done, dequeue csi report and do some process. */
       if (rtos_sema_take(wc_ready_sema, 0xFFFFFFFF) != RTK_SUCCESS) {
          RTK_LOGA(NOTAG,  "ERR: get wc_ready_sema failed");
    
          act_param.act = RTW_CSI_ACT_EN;  /* csi dis */
          act_param.enable = 0;
          wifi_csi_config(&act_param);
          break;
       }
    
       csi_rpt_pkt = wifi_csi_dequeue_busy_q(TRUE);
       if (csi_rpt_pkt != NULL) {
    
          /*do something for handing csi info: like show csi data */
          wifi_csi_show(csi_rpt_pkt);
    
          wifi_csi_enqueue_idle_q(csi_rpt_pkt);
          csi_rpt_pkt = NULL;
       } else {
          RTK_LOGA(NOTAG, "WARN: deq csi_rpt_q fail\n");
       }
    }
    
  8. Exit

    1. Disable Wi-Fi CSI function and release the Wi-Fi CSI callback function.

    2. Free Wi-Fi CSI buffer queue.

    3. Free the semaphore wc_ready_sema.

    4. Delete the task.

    /* unregister Wi-Fi event callback function */
    wifi_unreg_event_handler(RTW_EVENT_CSI_DONE, example_wifi_csi_report_cb);
    
    /* free csi report buffer */
    wifi_csi_buffer_deinit();
    
    if (wc_ready_sema) {
       rtos_sema_delete(wc_ready_sema);
    }
    
    rtos_task_delete(NULL);
    

Wi-Fi CSI Callback Function

When the Wi-Fi driver prepares a Wi-Fi CSI packet, it delivers the packet to the application via the Wi-Fi CSI callback function.

In this callback function, the application must:

  • Perform a deep copy of the Wi-Fi CSI packet into a pre-allocated buffer.

  • Release the wc_ready_sema semaphore to trigger wifi_csi_thread() for processing buffered Wi-Fi CSI packets.

Note

  • Avoid performing heavy operations in the callback function to prevent impacting reception performance.

void example_wifi_csi_report_cb(u8 *buf, s32 buf_len, s32 flags, void *userdata)
{
   (void) flags;
   (void) userdata;
   struct csi_report_data    *csi_rpt_pkt = NULL;

   csi_rpt_pkt = wifi_csi_dequeue_idle_q();                 /* get local idle buffer */

   if (csi_rpt_pkt && (buf_len <= CSI_REPORT_BUF_SIZE)) {
      memcpy(csi_rpt_pkt->csi_buffer, buf, buf_len);        /* memory copy to local buffer */
      csi_rpt_pkt->length = buf_len;
      wifi_csi_enqueue_busy_q(csi_rpt_pkt);                 /* buffer queue management */
      rtos_sema_give(wc_ready_sema);                        /* trigger thread */
   } else {
      RTK_LOGA(NOTAG, "ERR: csi_callback fail(null_buf or smaller size)\n");
   }
}

Wi-Fi CSI Buffer Pool

  • Doubly linked list

    • Access buffers on their respective lists via idle_q / busy_q.

  • idle_q_cnt / busy_q_cnt: Track the count of buffers in the idle_q and busy_q lists.

  • csi_rpt_q_mutex: Ensures thread-safe access to shared memory.

../../rst_wifi/2_wifi_csi/figures/csi_report_buffer_pool.svg

Wi-Fi CSI Buffer Pool Design