mirror of
https://github.com/open-sdr/openwifi.git
synced 2024-12-19 21:58:13 +00:00
the side channel (timestamp, frequency offset, CSI, equalizer) feature
This commit is contained in:
parent
7da3f8ba0e
commit
22dd0cc486
16
README.md
16
README.md
@ -25,6 +25,7 @@ Openwifi code has dual licenses. AGPLv3 is the opensource license. For non-opens
|
||||
- Easy to change bandwidth and frequency:
|
||||
- 2MHz for 802.11ah in sub-GHz
|
||||
- 10MHz for 802.11p/vehicle in 5.9GHz
|
||||
- CSI monitor (timestamp, frequency offset, channel response, equalizer) [[CSI notes](doc/app_notes/csi.md)]
|
||||
- On roadmap: **802.11ax**
|
||||
|
||||
**Performance (AP: openwifi at channel 44, client: TL-WDN4200 N900 USB Dongle):**
|
||||
@ -35,12 +36,12 @@ Openwifi code has dual licenses. AGPLv3 is the opensource license. For non-opens
|
||||
|
||||
board_name|board combination|status|SD card img
|
||||
-------|-------|----|----
|
||||
zc706_fmcs2|Xilinx ZC706 dev board + FMCOMMS2/3/4|Done|[32bit img](https://users.ugent.be/~xjiao/openwifi-1.1.0-taiyuan-4-32bit.img.xz)
|
||||
zed_fmcs2|Xilinx zed board + FMCOMMS2/3/4|Done|[32bit img](https://users.ugent.be/~xjiao/openwifi-1.1.0-taiyuan-4-32bit.img.xz)
|
||||
adrv9364z7020|ADRV9364-Z7020 + ADRV1CRR-BOB|Done|[32bit img](https://users.ugent.be/~xjiao/openwifi-1.1.0-taiyuan-4-32bit.img.xz)
|
||||
adrv9361z7035|ADRV9361-Z7035 + ADRV1CRR-BOB/FMC|Done|[32bit img](https://users.ugent.be/~xjiao/openwifi-1.1.0-taiyuan-4-32bit.img.xz)
|
||||
zc702_fmcs2|Xilinx ZC702 dev board + FMCOMMS2/3/4|Done|[32bit img](https://users.ugent.be/~xjiao/openwifi-1.1.0-taiyuan-4-32bit.img.xz)
|
||||
zcu102_fmcs2|Xilinx ZCU102 dev board + FMCOMMS2/3/4|Done|[64bit img](https://users.ugent.be/~xjiao/openwifi-1.1.0-taiyuan-4-64bit.img.xz)
|
||||
zc706_fmcs2|Xilinx ZC706 dev board + FMCOMMS2/3/4|Done|[32bit img](https://users.ugent.be/~xjiao/openwifi-1.1.0-taiyuan-5-32bit.img.xz)
|
||||
zed_fmcs2|Xilinx zed board + FMCOMMS2/3/4|Done|[32bit img](https://users.ugent.be/~xjiao/openwifi-1.1.0-taiyuan-5-32bit.img.xz)
|
||||
adrv9364z7020|ADRV9364-Z7020 + ADRV1CRR-BOB|Done|[32bit img](https://users.ugent.be/~xjiao/openwifi-1.1.0-taiyuan-5-32bit.img.xz)
|
||||
adrv9361z7035|ADRV9361-Z7035 + ADRV1CRR-BOB/FMC|Done|[32bit img](https://users.ugent.be/~xjiao/openwifi-1.1.0-taiyuan-5-32bit.img.xz)
|
||||
zc702_fmcs2|Xilinx ZC702 dev board + FMCOMMS2/3/4|Done|[32bit img](https://users.ugent.be/~xjiao/openwifi-1.1.0-taiyuan-5-32bit.img.xz)
|
||||
zcu102_fmcs2|Xilinx ZCU102 dev board + FMCOMMS2/3/4|Done|[64bit img](https://users.ugent.be/~xjiao/openwifi-1.1.0-taiyuan-5-64bit.img.xz)
|
||||
zcu102_9371|Xilinx ZCU102 dev board + ADRV9371|Future|None
|
||||
|
||||
- board_name is used to identify FPGA design in openwifi-hw/boards/
|
||||
@ -85,6 +86,7 @@ zcu102_9371|Xilinx ZCU102 dev board + ADRV9371|Future|None
|
||||
**ethX** is the PC NIC name connecting the board. **ethY** is the PC NIC name connecting internet.
|
||||
|
||||
If you want, uncommenting "net.ipv4.ip_forward=1" in /etc/sysctl.conf to make IP forwarding persistent on PC.
|
||||
- To monitor **real-time CSI (Chip State Information)**, such as timestamp, frequency offset, channel state, equalizer, please refer to [[CSI notes](doc/app_notes/csi.md)].
|
||||
|
||||
## Basic operations
|
||||
The board actually is an Linux/Ubuntu computer which is running **hostapd** to offer Wi-Fi AP functionality over the Wi-Fi Network Interface (NIC). The NIC is implemented by openwifi-hw FPGA design. We use the term **"On board"** to indicate that the commands should be executed after ssh login to the board. **"On PC"** means the commands should run on PC.
|
||||
@ -244,7 +246,7 @@ Low latency for gaming and introduction [[youtube](https://youtu.be/Notn9X482LI)
|
||||
|
||||
## Papers
|
||||
|
||||
- [openwifi: a free and open-source IEEE802.11 SDR implementation on SoC](https://biblio.ugent.be/publication/8663043/file/8663044.pdf)
|
||||
- [openwifi: a free and open-source IEEE802.11 SDR implementation on SoC](https://www.orca-project.eu/wp-content/uploads/sites/4/2020/03/openwifi-vtc-antwerp-PID1249076.pdf)
|
||||
- [csi murder](https://ans.unibs.it/projects/csi-murder/)
|
||||
|
||||
Openwifi was born in [ORCA project](https://www.orca-project.eu/) (EU's Horizon2020 programme under agreement number 732174).
|
||||
|
@ -3,3 +3,4 @@ Application notes collect many small topics about using openwifi in different sc
|
||||
- [Use openwifi on the w-iLab.t testbed remotely](https://doc.ilabt.imec.be/ilabt/wilab/tutorials/openwifi.html)
|
||||
- [Communication between two SDR boards under AP and client mode](ap-client-two-sdr.md)
|
||||
- [Communication between two SDR boards under ad-hoc mode](ad-hoc-two-sdr.md)
|
||||
- [From CSI (Channel State Information) to CSI (Chip State Information)](csi.md)
|
||||
|
BIN
doc/app_notes/csi-architecture.jpg
Normal file
BIN
doc/app_notes/csi-architecture.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 110 KiB |
BIN
doc/app_notes/csi-information-format.jpg
Normal file
BIN
doc/app_notes/csi-information-format.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 87 KiB |
110
doc/app_notes/csi.md
Normal file
110
doc/app_notes/csi.md
Normal file
@ -0,0 +1,110 @@
|
||||
## Quick start
|
||||
- Power on the SDR board.
|
||||
- Connect a computer to the SDR board via Ethernet cable. The computer should have static IP 192.168.10.1. Open a terminal on the computer, and then in the terminal:
|
||||
```
|
||||
ssh root@192.168.10.122
|
||||
(password: openwifi)
|
||||
cd openwifi
|
||||
./wgd.sh
|
||||
(Wait for the script completed)
|
||||
./monitor_ch.sh sdr0 11
|
||||
(Monitor on channel 11. You can change 11 to other channel that is busy)
|
||||
insmod side_ch.ko
|
||||
./side_ch_ctl g
|
||||
```
|
||||
You should see on board outputs like:
|
||||
```
|
||||
loop 64 side info count 61
|
||||
loop 128 side info count 99
|
||||
...
|
||||
```
|
||||
If the second number (61, 99, ...) is not zero and keeps increasing, that means the CSI (Chip State Information) is going to the computer smoothly.
|
||||
|
||||
- Open another terminal on the computer, and run:
|
||||
```
|
||||
cd openwifi/user_space/side_ch_ctl_src
|
||||
python3 side_info_display.py
|
||||
```
|
||||
The python script needs "matplotlib.pyplot" and "numpy" packages installed. Now you should see 3 figures showing run-time **frequency offset**, **channel state/response** and **constellation form equalizer**. Meanwhile the python script prints the **timestamp**.
|
||||
|
||||
While running, all informations are also stored into a file side_info.txt. A matlab script **test_side_info_file_display.m** is offered to help you do analysis on the Chip State Information offline.
|
||||
|
||||
## Config the capture condition and interval
|
||||
The quick start guide will monitor all CSI informations of all packets decoded by the WiFi ofdm receiver. To monitor only specific packets that match the specific FC (Frame Control), addr1 (target MAC address), addr2 (source MAC address), configuration command should be issued before executing "**side_ch_ctl g**". The configuration command is realized by feeding a different parameter to "**side_ch_ctl**".
|
||||
|
||||
A quick example: Capture only CSI of those packets from the device with MAC address 56:5b:01:ec:e2:8f
|
||||
```
|
||||
./side_ch_ctl wh1h4001
|
||||
./side_ch_ctl wh7h01ece28f
|
||||
./side_ch_ctl g
|
||||
```
|
||||
The parameter string format is explained in detail:
|
||||
```
|
||||
whXhY
|
||||
```
|
||||
The X is the register index, and the Y is the value in hex format. The remaining "w", "h" and "h" should be kept untouched.
|
||||
- To turn on conditional capture, X should be 1. For Y: bit11~bit0 should be 001(hex), bit12: on/off of FC match, bit13: on/off of addr1 match, bit14 : on/off of addr2 match. Examples:
|
||||
```
|
||||
Turn on FC match:
|
||||
./side_ch_ctl wh1h1001
|
||||
|
||||
Turn on addr2 (source address) match:
|
||||
./side_ch_ctl wh1h4001
|
||||
|
||||
Turn on FC and addr1 (target address) match:
|
||||
./side_ch_ctl wh1h3001
|
||||
|
||||
Turn off conditional capture (all packets will be captured):
|
||||
./side_ch_ctl wh1h0001
|
||||
```
|
||||
- To specify the condition matching target:
|
||||
```
|
||||
Specify the FC matching target:
|
||||
./side_ch_ctl wh5hY
|
||||
|
||||
Specify the addr1 (target address) matching target:
|
||||
./side_ch_ctl wh6hY
|
||||
|
||||
Specify the addr2 (source address) matching target:
|
||||
./side_ch_ctl wh7hY
|
||||
```
|
||||
The command "**side_ch_ctl g**" will perform CSI capture every 100ms until you press ctrl+C. To use a different capture interval:
|
||||
```
|
||||
side_ch_ctl gN
|
||||
```
|
||||
The interval will become N*100ms
|
||||
|
||||
## Understand CSI feature
|
||||
The CSI information is extracted via the openwifi **side channel** infrastructure. This figure explains the related module (and related source code file name) and how the information goes from the board to the computer.
|
||||
![](./csi-architecture.jpg)
|
||||
|
||||
The CSI information format is shown in this figure.
|
||||
![](./csi-information-format.jpg)
|
||||
|
||||
For each element, the actual size is 64bit.
|
||||
- timestamp: 64bit TSF timer value, which is the same timestamp value shown by other sniffer software, like tcpdump, wireshark or openwifi printing in dmesg.
|
||||
- freq_offset: Only the 1st 16bit is used.
|
||||
- csi (channel state/response) and equalizer: Only the first two 16bit are used for I/Q of channel response and equalizer output. The remaining two 16bit are reserved for future multi-antenna cases.
|
||||
|
||||
The python and Matlab scripts are recommended for you to understand the CSI packet format precisely.
|
||||
|
||||
## Config the num_eq
|
||||
The num_eq (number of equalizer output) is configurable in case you don't need so many equalizer informations. The valid value is 0~8. You should align the num_eq value at the side_ch.ko, side_info_display.py and test_side_info_file_display.m.
|
||||
- When insert the kernel module, use:
|
||||
```
|
||||
insmod side_ch.ko num_eq_init=3
|
||||
```
|
||||
You can replace 3 by number 0~8. (8 is the default value. You don't need to specify it like in the Quick start section)
|
||||
- When launch the python script, use:
|
||||
```
|
||||
side_info_display.py 3
|
||||
```
|
||||
- When use the Matlab script, please change the num_eq variable in the script to 3 (3 is just an example).
|
||||
|
||||
## Run CSI together with mode other than monitor
|
||||
The CSI could run with not only monitor mode. When you run openwifi in AP-Client or ad-hoc mode, after your communication functionality is fully up, you can start from "**insmod side_ch.ko**" and "**./side_ch_ctl g**" on board as described in the quick start section to extract CSI to your computer.
|
||||
|
||||
## Map the CSI information to the WiFi packet
|
||||
If you want to relate the CSI information to the WiFi packet, you need to capture WiFi packets (tcpdump/wireshark/etc) while capturing CSI. Then you can match the timestamp (TSF timer value) between WiFi packet and CSI information, because this is the unique same identity of a Wifi packet and related CSI.
|
||||
|
||||
Please read the python and Matlab script to extract CSI information per packet according to your requirement.
|
10
driver/sdr.c
10
driver/sdr.c
@ -123,7 +123,7 @@ static void ad9361_rf_set_channel(struct ieee80211_hw *dev,
|
||||
struct ieee80211_conf *conf)
|
||||
{
|
||||
struct openwifi_priv *priv = dev->priv;
|
||||
u32 actual_rx_lo = conf->chandef.chan->center_freq - priv->rx_freq_offset_to_lo_MHz;
|
||||
u32 actual_rx_lo = conf->chandef.chan->center_freq - priv->rx_freq_offset_to_lo_MHz + priv->drv_rx_reg_val[DRV_RX_REG_IDX_EXTRA_FO];
|
||||
u32 actual_tx_lo;
|
||||
bool change_flag = (actual_rx_lo != priv->actual_rx_lo);
|
||||
|
||||
@ -810,7 +810,7 @@ static void openwifi_tx(struct ieee80211_hw *dev,
|
||||
goto openwifi_tx_early_out_after_lock;
|
||||
}
|
||||
|
||||
// sg_init_table(&tx_sg, 1); // only need to be initialized once in openwifi_start
|
||||
sg_init_table(&(priv->tx_sg), 1); // only need to be initialized once in openwifi_start
|
||||
sg_dma_address( &(priv->tx_sg) ) = dma_mapping_addr;
|
||||
sg_dma_len( &(priv->tx_sg) ) = num_dma_byte;
|
||||
|
||||
@ -969,7 +969,7 @@ static int openwifi_start(struct ieee80211_hw *dev)
|
||||
printk("%s openwifi_start: rx_intf_cfg %d openofdm_rx_cfg %d tx_intf_cfg %d openofdm_tx_cfg %d\n",sdr_compatible_str, priv->rx_intf_cfg, priv->openofdm_rx_cfg, priv->tx_intf_cfg, priv->openofdm_tx_cfg);
|
||||
printk("%s openwifi_start: rx_freq_offset_to_lo_MHz %d tx_freq_offset_to_lo_MHz %d\n",sdr_compatible_str, priv->rx_freq_offset_to_lo_MHz, priv->tx_freq_offset_to_lo_MHz);
|
||||
|
||||
tx_intf_api->TX_INTF_REG_INTERRUPT_SEL_write(0x3004F); //disable tx interrupt
|
||||
tx_intf_api->TX_INTF_REG_INTERRUPT_SEL_write(0x30004); //disable tx interrupt
|
||||
rx_intf_api->RX_INTF_REG_INTERRUPT_TEST_write(0x100); // disable rx interrupt by interrupt test mode
|
||||
rx_intf_api->RX_INTF_REG_M_AXIS_RST_write(1); // hold M AXIS in reset status
|
||||
|
||||
@ -1033,7 +1033,7 @@ static int openwifi_start(struct ieee80211_hw *dev)
|
||||
}
|
||||
|
||||
rx_intf_api->RX_INTF_REG_INTERRUPT_TEST_write(0x000); // enable rx interrupt get normal fcs valid pass through ddc to ARM
|
||||
tx_intf_api->TX_INTF_REG_INTERRUPT_SEL_write(0x4F); //enable tx interrupt
|
||||
tx_intf_api->TX_INTF_REG_INTERRUPT_SEL_write(0x4); //enable tx interrupt
|
||||
rx_intf_api->RX_INTF_REG_M_AXIS_RST_write(0); // release M AXIS
|
||||
xpu_api->XPU_REG_TSF_LOAD_VAL_write(0,0); // reset tsf timer
|
||||
|
||||
@ -1080,7 +1080,7 @@ static void openwifi_stop(struct ieee80211_hw *dev)
|
||||
|
||||
//ieee80211_stop_queue(dev, 0);
|
||||
|
||||
tx_intf_api->TX_INTF_REG_INTERRUPT_SEL_write(0x3004F); //disable tx interrupt
|
||||
tx_intf_api->TX_INTF_REG_INTERRUPT_SEL_write(0x30004); //disable tx interrupt
|
||||
rx_intf_api->RX_INTF_REG_INTERRUPT_TEST_write(0x100); // disable fcs_valid by interrupt test mode
|
||||
rx_intf_api->RX_INTF_REG_M_AXIS_RST_write(1); // hold M AXIS in reset status
|
||||
|
||||
|
11
driver/sdr.h
11
driver/sdr.h
@ -68,15 +68,16 @@ union u16_byte2 {
|
||||
#define OPENWIFI_LED_MAX_NAME_LEN 32
|
||||
|
||||
// ------------ software reg definition ------------
|
||||
#define MAX_NUM_DRV_REG 8
|
||||
#define DRV_TX_REG_IDX_RATE 0
|
||||
#define MAX_NUM_DRV_REG 8
|
||||
#define DRV_TX_REG_IDX_RATE 0
|
||||
#define DRV_TX_REG_IDX_FREQ_BW_CFG 1
|
||||
#define DRV_TX_REG_IDX_PRINT_CFG (MAX_NUM_DRV_REG-1)
|
||||
#define DRV_TX_REG_IDX_PRINT_CFG (MAX_NUM_DRV_REG-1)
|
||||
|
||||
#define DRV_RX_REG_IDX_FREQ_BW_CFG 1
|
||||
#define DRV_RX_REG_IDX_PRINT_CFG (MAX_NUM_DRV_REG-1)
|
||||
#define DRV_RX_REG_IDX_EXTRA_FO 2
|
||||
#define DRV_RX_REG_IDX_PRINT_CFG (MAX_NUM_DRV_REG-1)
|
||||
|
||||
#define DRV_XPU_REG_IDX_GIT_REV (MAX_NUM_DRV_REG-1)
|
||||
#define DRV_XPU_REG_IDX_GIT_REV (MAX_NUM_DRV_REG-1)
|
||||
|
||||
// ------end of software reg definition ------------
|
||||
|
||||
|
11
driver/side_ch/Makefile
Normal file
11
driver/side_ch/Makefile
Normal file
@ -0,0 +1,11 @@
|
||||
# by Xianjun jiao. putaoshu@msn.com; xianjun.jiao@imec.be
|
||||
|
||||
obj-m += side_ch.o
|
||||
# obj-m += axidmatest.o
|
||||
|
||||
all:
|
||||
make -C $(KDIR) M=$(PWD) modules
|
||||
# ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
|
||||
|
||||
clean:
|
||||
rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.order
|
58
driver/side_ch/make_driver.sh
Executable file
58
driver/side_ch/make_driver.sh
Executable file
@ -0,0 +1,58 @@
|
||||
#!/bin/bash
|
||||
if [ "$#" -ne 3 ]; then
|
||||
echo "You must enter exactly 3 arguments: \$OPENWIFI_DIR \$XILINX_DIR ARCH_BIT(32 or 64)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
OPENWIFI_DIR=$1
|
||||
XILINX_DIR=$2
|
||||
ARCH_OPTION=$3
|
||||
|
||||
if [ -f "$OPENWIFI_DIR/LICENSE" ]; then
|
||||
echo "\$OPENWIFI_DIR is found!"
|
||||
else
|
||||
echo "\$OPENWIFI_DIR is not correct. Please check!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -d "$XILINX_DIR/SDK" ]; then
|
||||
echo "\$XILINX_DIR is found!"
|
||||
else
|
||||
echo "\$XILINX_DIR is not correct. Please check!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$ARCH_OPTION" != "32" ] && [ "$ARCH_OPTION" != "64" ]; then
|
||||
echo "\$ARCH_OPTION is not correct. Should be 32 or 64. Please check!"
|
||||
exit 1
|
||||
else
|
||||
echo "\$ARCH_OPTION is valid!"
|
||||
fi
|
||||
|
||||
source $XILINX_DIR/SDK/2018.3/settings64.sh
|
||||
if [ "$ARCH_OPTION" == "64" ]; then
|
||||
LINUX_KERNEL_SRC_DIR=$OPENWIFI_DIR/adi-linux-64/
|
||||
ARCH="arm64"
|
||||
CROSS_COMPILE="aarch64-linux-gnu-"
|
||||
else
|
||||
LINUX_KERNEL_SRC_DIR=$OPENWIFI_DIR/adi-linux/
|
||||
ARCH="arm"
|
||||
CROSS_COMPILE="arm-linux-gnueabihf-"
|
||||
fi
|
||||
|
||||
# check if user entered the right path to analog device linux
|
||||
if [ -d "$LINUX_KERNEL_SRC_DIR" ]; then
|
||||
echo " setup linux kernel path ${LINUX_KERNEL_SRC_DIR}"
|
||||
else
|
||||
echo "Error: path to adi linux: ${LINUX_KERNEL_SRC_DIR} not found. Can not continue."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -x
|
||||
|
||||
home_dir=$(pwd)
|
||||
|
||||
cd $OPENWIFI_DIR/driver/side_ch
|
||||
make KDIR=$LINUX_KERNEL_SRC_DIR ARCH=$ARCH CROSS_COMPILE=$CROSS_COMPILE
|
||||
|
||||
cd $home_dir
|
613
driver/side_ch/side_ch.c
Normal file
613
driver/side_ch/side_ch.c
Normal file
@ -0,0 +1,613 @@
|
||||
/*
|
||||
* openwifi side channel driver
|
||||
* Xianjun jiao. putaoshu@msn.com; xianjun.jiao@imec.be
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/dmapool.h>
|
||||
#include <linux/dma/xilinx_dma.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_dma.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io-64-nonatomic-lo-hi.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dmaengine.h>
|
||||
|
||||
#include <net/sock.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#include "side_ch.h"
|
||||
|
||||
static int num_eq_init = 8; // should be 0~8
|
||||
|
||||
module_param(num_eq_init, int, 0);
|
||||
MODULE_PARM_DESC(num_eq_init, "num_eq_init. 0~8. number of equalizer output (52 each) appended to CSI");
|
||||
|
||||
static void __iomem *base_addr; // to store driver specific base address needed for mmu to translate virtual address to physical address in our FPGA design
|
||||
|
||||
struct dma_chan *chan_to_pl = NULL;
|
||||
struct dma_chan *chan_to_ps = NULL;
|
||||
u8 *side_info_buf = NULL;
|
||||
dma_cookie_t chan_to_ps_cookie;
|
||||
const int max_side_info_buf_size = MAX_NUM_DMA_SYMBOL*8;
|
||||
|
||||
/* IO accessors */
|
||||
static inline u32 reg_read(u32 reg)
|
||||
{
|
||||
return ioread32(base_addr + reg);
|
||||
}
|
||||
|
||||
static inline void reg_write(u32 reg, u32 value)
|
||||
{
|
||||
iowrite32(value, base_addr + reg);
|
||||
}
|
||||
|
||||
static inline void SIDE_CH_REG_MULTI_RST_write(u32 Data) {
|
||||
reg_write(SIDE_CH_REG_MULTI_RST_ADDR, Data);
|
||||
}
|
||||
|
||||
static inline u32 SIDE_CH_REG_CONFIG_read(void){
|
||||
return reg_read(SIDE_CH_REG_CONFIG_ADDR);
|
||||
}
|
||||
|
||||
static inline void SIDE_CH_REG_CONFIG_write(u32 value){
|
||||
reg_write(SIDE_CH_REG_CONFIG_ADDR, value);
|
||||
}
|
||||
|
||||
static inline u32 SIDE_CH_REG_NUM_DMA_SYMBOL_read(void){
|
||||
return reg_read(SIDE_CH_REG_NUM_DMA_SYMBOL_ADDR);
|
||||
}
|
||||
|
||||
static inline void SIDE_CH_REG_NUM_DMA_SYMBOL_write(u32 value){
|
||||
reg_write(SIDE_CH_REG_NUM_DMA_SYMBOL_ADDR, value);
|
||||
}
|
||||
|
||||
static inline u32 SIDE_CH_REG_START_DMA_TO_PS_read(void){
|
||||
return reg_read(SIDE_CH_REG_START_DMA_TO_PS_ADDR);
|
||||
}
|
||||
|
||||
static inline void SIDE_CH_REG_START_DMA_TO_PS_write(u32 value){
|
||||
reg_write(SIDE_CH_REG_START_DMA_TO_PS_ADDR, value);
|
||||
}
|
||||
|
||||
static inline u32 SIDE_CH_REG_NUM_EQ_read(void){
|
||||
return reg_read(SIDE_CH_REG_NUM_EQ_ADDR);
|
||||
}
|
||||
|
||||
static inline void SIDE_CH_REG_NUM_EQ_write(u32 value){
|
||||
reg_write(SIDE_CH_REG_NUM_EQ_ADDR, value);
|
||||
}
|
||||
|
||||
static inline u32 SIDE_CH_REG_FC_TARGET_read(void){
|
||||
return reg_read(SIDE_CH_REG_FC_TARGET_ADDR);
|
||||
}
|
||||
|
||||
static inline void SIDE_CH_REG_FC_TARGET_write(u32 value){
|
||||
reg_write(SIDE_CH_REG_FC_TARGET_ADDR, value);
|
||||
}
|
||||
|
||||
static inline u32 SIDE_CH_REG_ADDR1_TARGET_read(void){
|
||||
return reg_read(SIDE_CH_REG_ADDR1_TARGET_ADDR);
|
||||
}
|
||||
|
||||
static inline void SIDE_CH_REG_ADDR1_TARGET_write(u32 value){
|
||||
reg_write(SIDE_CH_REG_ADDR1_TARGET_ADDR, value);
|
||||
}
|
||||
|
||||
static inline u32 SIDE_CH_REG_ADDR2_TARGET_read(void){
|
||||
return reg_read(SIDE_CH_REG_ADDR2_TARGET_ADDR);
|
||||
}
|
||||
|
||||
static inline void SIDE_CH_REG_ADDR2_TARGET_write(u32 value){
|
||||
reg_write(SIDE_CH_REG_ADDR2_TARGET_ADDR, value);
|
||||
}
|
||||
|
||||
static inline u32 SIDE_CH_REG_M_AXIS_DATA_COUNT_read(void){
|
||||
return reg_read(SIDE_CH_REG_M_AXIS_DATA_COUNT_ADDR);
|
||||
}
|
||||
|
||||
static inline void SIDE_CH_REG_M_AXIS_DATA_COUNT_write(u32 value){
|
||||
reg_write(SIDE_CH_REG_M_AXIS_DATA_COUNT_ADDR, value);
|
||||
}
|
||||
|
||||
static const struct of_device_id dev_of_ids[] = {
|
||||
{ .compatible = "sdr,side_ch", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, dev_of_ids);
|
||||
|
||||
static void chan_to_ps_callback(void *completion)
|
||||
{
|
||||
complete(completion);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void chan_to_pl_callback(void *completion)
|
||||
{
|
||||
complete(completion);
|
||||
}
|
||||
|
||||
static int dma_loopback_test(int num_test, int num_dma_symbol) {
|
||||
int i, err = 0;
|
||||
|
||||
// -----------dma loop back test-------------------------
|
||||
enum dma_status status;
|
||||
enum dma_ctrl_flags flags;
|
||||
u8 *src_buf, *dst_buf;
|
||||
// int num_dma_symbol = 16;
|
||||
int test_buf_size = num_dma_symbol*8;
|
||||
dma_addr_t src_buf_dma;
|
||||
dma_addr_t dst_buf_dma;
|
||||
struct dma_device *chan_to_pl_dev = chan_to_pl->device;
|
||||
struct dma_device *chan_to_ps_dev = chan_to_ps->device;
|
||||
struct scatterlist chan_to_pl_sg[1];
|
||||
struct scatterlist chan_to_ps_sg[1];
|
||||
dma_cookie_t chan_to_pl_cookie;
|
||||
dma_cookie_t chan_to_ps_cookie;
|
||||
struct completion chan_to_pl_cmp;
|
||||
struct completion chan_to_ps_cmp;
|
||||
struct dma_async_tx_descriptor *chan_to_pl_d = NULL;
|
||||
struct dma_async_tx_descriptor *chan_to_ps_d = NULL;
|
||||
unsigned long chan_to_ps_tmo = msecs_to_jiffies(300000);
|
||||
unsigned long chan_to_pl_tmo = msecs_to_jiffies(30000);
|
||||
int test_idx;
|
||||
|
||||
for (test_idx=0; test_idx<num_test; test_idx++) {
|
||||
printk("%s test_idx %d\n", side_ch_compatible_str, test_idx);
|
||||
//set number of dma symbols expected to pl and ps
|
||||
SIDE_CH_REG_NUM_DMA_SYMBOL_write((num_dma_symbol<<16)|num_dma_symbol);
|
||||
|
||||
src_buf = kmalloc(test_buf_size, GFP_KERNEL);
|
||||
if (!src_buf)
|
||||
goto err_src_buf;
|
||||
|
||||
dst_buf = kmalloc(test_buf_size, GFP_KERNEL);
|
||||
if (!dst_buf)
|
||||
goto err_dst_buf;
|
||||
|
||||
// test buf init
|
||||
for (i=0; i<test_buf_size; i++) {
|
||||
src_buf[i] = (test_idx+test_buf_size-i-1);
|
||||
dst_buf[i] = 0;
|
||||
}
|
||||
|
||||
set_user_nice(current, 10);
|
||||
flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
|
||||
|
||||
src_buf_dma = dma_map_single(chan_to_pl_dev->dev, src_buf, test_buf_size, DMA_MEM_TO_DEV);
|
||||
if (dma_mapping_error(chan_to_pl_dev->dev, src_buf_dma)) {
|
||||
printk("%s dma_loopback_test WARNING chan_to_pl_dev DMA mapping error\n", side_ch_compatible_str);
|
||||
goto err_src_buf_dma_mapping;
|
||||
}
|
||||
|
||||
dst_buf_dma = dma_map_single(chan_to_ps_dev->dev, dst_buf, test_buf_size, DMA_DEV_TO_MEM);
|
||||
if (dma_mapping_error(chan_to_ps_dev->dev, dst_buf_dma)) {
|
||||
printk("%s dma_loopback_test WARNING chan_to_ps_dev DMA mapping error\n", side_ch_compatible_str);
|
||||
goto err_dst_buf_dma_mapping;
|
||||
}
|
||||
|
||||
sg_init_table(chan_to_ps_sg, 1);
|
||||
sg_init_table(chan_to_pl_sg, 1);
|
||||
|
||||
sg_dma_address(&chan_to_ps_sg[0]) = dst_buf_dma;
|
||||
sg_dma_address(&chan_to_pl_sg[0]) = src_buf_dma;
|
||||
|
||||
sg_dma_len(&chan_to_ps_sg[0]) = test_buf_size;
|
||||
sg_dma_len(&chan_to_pl_sg[0]) = test_buf_size;
|
||||
|
||||
chan_to_ps_d = chan_to_ps_dev->device_prep_slave_sg(chan_to_ps, chan_to_ps_sg, 1, DMA_DEV_TO_MEM, flags, NULL);
|
||||
chan_to_pl_d = chan_to_pl_dev->device_prep_slave_sg(chan_to_pl, chan_to_pl_sg, 1, DMA_MEM_TO_DEV, flags, NULL);
|
||||
|
||||
if (!chan_to_ps_d || !chan_to_pl_d) {
|
||||
printk("%s dma_loopback_test WARNING !chan_to_ps_d || !chan_to_pl_d\n", side_ch_compatible_str);
|
||||
goto err_dst_buf_with_unmap;
|
||||
}
|
||||
|
||||
init_completion(&chan_to_pl_cmp);
|
||||
chan_to_pl_d->callback = chan_to_pl_callback;
|
||||
chan_to_pl_d->callback_param = &chan_to_pl_cmp;
|
||||
chan_to_pl_cookie = chan_to_pl_d->tx_submit(chan_to_pl_d);
|
||||
|
||||
init_completion(&chan_to_ps_cmp);
|
||||
chan_to_ps_d->callback = chan_to_ps_callback;
|
||||
chan_to_ps_d->callback_param = &chan_to_ps_cmp;
|
||||
chan_to_ps_cookie = chan_to_ps_d->tx_submit(chan_to_ps_d);
|
||||
|
||||
if (dma_submit_error(chan_to_pl_cookie) || dma_submit_error(chan_to_ps_cookie)) {
|
||||
printk("%s dma_loopback_test WARNING dma_submit_error\n", side_ch_compatible_str);
|
||||
goto err_dst_buf_with_unmap;
|
||||
}
|
||||
|
||||
dma_async_issue_pending(chan_to_pl);
|
||||
dma_async_issue_pending(chan_to_ps);
|
||||
|
||||
chan_to_pl_tmo = wait_for_completion_timeout(&chan_to_pl_cmp, chan_to_pl_tmo);
|
||||
|
||||
status = dma_async_is_tx_complete(chan_to_pl, chan_to_pl_cookie, NULL, NULL);
|
||||
if (chan_to_pl_tmo == 0) {
|
||||
printk("%s dma_loopback_test chan_to_pl_tmo == 0\n", side_ch_compatible_str);
|
||||
goto err_dst_buf_with_unmap;
|
||||
} else if (status != DMA_COMPLETE) {
|
||||
printk("%s dma_loopback_test chan_to_pl status != DMA_COMPLETE\n", side_ch_compatible_str);
|
||||
goto err_dst_buf_with_unmap;
|
||||
}
|
||||
|
||||
chan_to_ps_tmo = wait_for_completion_timeout(&chan_to_ps_cmp, chan_to_ps_tmo);
|
||||
status = dma_async_is_tx_complete(chan_to_ps, chan_to_ps_cookie, NULL, NULL);
|
||||
if (chan_to_ps_tmo == 0) {
|
||||
printk("%s dma_loopback_test chan_to_ps_tmo == 0\n", side_ch_compatible_str);
|
||||
goto err_dst_buf_with_unmap;
|
||||
} else if (status != DMA_COMPLETE) {
|
||||
printk("%s dma_loopback_test chan_to_ps status != DMA_COMPLETE\n", side_ch_compatible_str);
|
||||
goto err_dst_buf_with_unmap;
|
||||
}
|
||||
|
||||
dma_unmap_single(chan_to_pl_dev->dev, src_buf_dma, test_buf_size, DMA_MEM_TO_DEV);
|
||||
dma_unmap_single(chan_to_ps_dev->dev, dst_buf_dma, test_buf_size, DMA_DEV_TO_MEM);
|
||||
|
||||
// test buf verification
|
||||
for (i=0; i<test_buf_size; i++) {
|
||||
//printk("%d ", dst_buf[i]);
|
||||
if ( dst_buf[i] != ((test_idx+test_buf_size-i-1)%256) )
|
||||
break;
|
||||
}
|
||||
printk("\n");
|
||||
printk("%s dma_loopback_test buf verification end idx %d (test_buf_size %d)\n", side_ch_compatible_str, i, test_buf_size);
|
||||
|
||||
kfree(src_buf);
|
||||
kfree(dst_buf);
|
||||
}
|
||||
|
||||
printk("%s dma_loopback_test err %d\n", side_ch_compatible_str, err);
|
||||
return(err);
|
||||
|
||||
err_dst_buf_with_unmap:
|
||||
dma_unmap_single(chan_to_ps_dev->dev, dst_buf_dma, test_buf_size, DMA_DEV_TO_MEM);
|
||||
|
||||
err_dst_buf_dma_mapping:
|
||||
dma_unmap_single(chan_to_pl_dev->dev, src_buf_dma, test_buf_size, DMA_MEM_TO_DEV);
|
||||
|
||||
err_src_buf_dma_mapping:
|
||||
|
||||
err_dst_buf:
|
||||
err = -4;
|
||||
kfree((void*)dst_buf);
|
||||
|
||||
err_src_buf:
|
||||
err = -3;
|
||||
kfree(src_buf);
|
||||
|
||||
return(err);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int init_side_channel(void) {
|
||||
side_info_buf = kmalloc(max_side_info_buf_size, GFP_KERNEL);
|
||||
if (!side_info_buf)
|
||||
return(-1);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int get_side_info(int num_eq) {
|
||||
// int err = 0;//, i;
|
||||
struct scatterlist chan_to_ps_sg[1];
|
||||
enum dma_status status;
|
||||
enum dma_ctrl_flags flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
|
||||
int num_dma_symbol, num_dma_symbol_per_trans, side_info_buf_size;
|
||||
dma_addr_t side_info_buf_dma;
|
||||
struct dma_device *chan_to_ps_dev = chan_to_ps->device;
|
||||
struct completion chan_to_ps_cmp;
|
||||
struct dma_async_tx_descriptor *chan_to_ps_d = NULL;
|
||||
unsigned long chan_to_ps_tmo = msecs_to_jiffies(100);
|
||||
|
||||
if (side_info_buf==NULL) {
|
||||
printk("%s get_side_info WARNING side_info_buf==NULL\n", side_ch_compatible_str);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
status = dma_async_is_tx_complete(chan_to_ps, chan_to_ps_cookie, NULL, NULL);
|
||||
if (status!=DMA_COMPLETE) {
|
||||
printk("%s get_side_info WARNING status!=DMA_COMPLETE\n", side_ch_compatible_str);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
set_user_nice(current, 10);
|
||||
|
||||
num_dma_symbol_per_trans = HEADER_LEN + CSI_LEN + num_eq*EQUALIZER_LEN;
|
||||
//set number of dma symbols expected to ps
|
||||
num_dma_symbol = SIDE_CH_REG_M_AXIS_DATA_COUNT_read();
|
||||
printk("%s get_side_info m axis data count %d per trans %d\n", side_ch_compatible_str, num_dma_symbol, num_dma_symbol_per_trans);
|
||||
num_dma_symbol = num_dma_symbol_per_trans*(num_dma_symbol/num_dma_symbol_per_trans);
|
||||
printk("%s get_side_info actual num dma symbol %d\n", side_ch_compatible_str, num_dma_symbol);
|
||||
if (num_dma_symbol == 0)
|
||||
return(-2);
|
||||
|
||||
side_info_buf_size = num_dma_symbol*8;
|
||||
side_info_buf_dma = dma_map_single(chan_to_ps_dev->dev, side_info_buf, side_info_buf_size, DMA_DEV_TO_MEM);
|
||||
if (dma_mapping_error(chan_to_ps_dev->dev, side_info_buf_dma)) {
|
||||
printk("%s get_side_info WARNING chan_to_ps_dev DMA mapping error\n", side_ch_compatible_str);
|
||||
return(-3);
|
||||
}
|
||||
|
||||
sg_init_table(chan_to_ps_sg, 1);
|
||||
sg_dma_address(&chan_to_ps_sg[0]) = side_info_buf_dma;
|
||||
sg_dma_len(&chan_to_ps_sg[0]) = side_info_buf_size;
|
||||
|
||||
chan_to_ps_d = chan_to_ps_dev->device_prep_slave_sg(chan_to_ps, chan_to_ps_sg, 1, DMA_DEV_TO_MEM, flags, NULL);
|
||||
if (!chan_to_ps_d) {
|
||||
printk("%s get_side_info WARNING !chan_to_ps_d\n", side_ch_compatible_str);
|
||||
goto err_dst_buf_with_unmap;
|
||||
}
|
||||
|
||||
init_completion(&chan_to_ps_cmp);
|
||||
chan_to_ps_d->callback = chan_to_ps_callback;
|
||||
chan_to_ps_d->callback_param = &chan_to_ps_cmp;
|
||||
|
||||
chan_to_ps_cookie = chan_to_ps_d->tx_submit(chan_to_ps_d);
|
||||
if (dma_submit_error(chan_to_ps_cookie)) {
|
||||
printk("%s get_side_info WARNING dma_submit_error\n", side_ch_compatible_str);
|
||||
goto err_dst_buf_with_unmap;
|
||||
}
|
||||
|
||||
SIDE_CH_REG_NUM_DMA_SYMBOL_write(num_dma_symbol); //dma from fpga will start automatically
|
||||
|
||||
dma_async_issue_pending(chan_to_ps);
|
||||
|
||||
chan_to_ps_tmo = wait_for_completion_timeout(&chan_to_ps_cmp, chan_to_ps_tmo);
|
||||
status = dma_async_is_tx_complete(chan_to_ps, chan_to_ps_cookie, NULL, NULL);
|
||||
if (chan_to_ps_tmo == 0) {
|
||||
printk("%s get_side_info WARNING chan_to_ps_tmo == 0\n", side_ch_compatible_str);
|
||||
goto err_dst_buf_with_unmap;
|
||||
} else if (status != DMA_COMPLETE) {
|
||||
printk("%s get_side_info WARNING chan_to_ps status != DMA_COMPLETE\n", side_ch_compatible_str);
|
||||
goto err_dst_buf_with_unmap;
|
||||
}
|
||||
|
||||
dma_unmap_single(chan_to_ps_dev->dev, side_info_buf_dma, side_info_buf_size, DMA_DEV_TO_MEM);
|
||||
return(side_info_buf_size);
|
||||
|
||||
err_dst_buf_with_unmap:
|
||||
dma_unmap_single(chan_to_ps_dev->dev, side_info_buf_dma, side_info_buf_size, DMA_DEV_TO_MEM);
|
||||
return(-100);
|
||||
}
|
||||
|
||||
// -----------------netlink recv and send-----------------
|
||||
// should align with side_ch_ctl.c in user_space
|
||||
#define ACTION_INVALID 0
|
||||
#define ACTION_REG_WRITE 1
|
||||
#define ACTION_REG_READ 2
|
||||
#define ACTION_SIDE_INFO_GET 3
|
||||
|
||||
#define REG_TYPE_INVALID 0
|
||||
#define REG_TYPE_HARDWARE 1
|
||||
#define REG_TYPE_SOFTWARE 2
|
||||
|
||||
// #define NETLINK_USER 31
|
||||
struct sock *nl_sk = NULL;
|
||||
static void side_ch_nl_recv_msg(struct sk_buff *skb) {
|
||||
struct nlmsghdr *nlh;
|
||||
int pid;
|
||||
struct sk_buff *skb_out;
|
||||
int msg_size;
|
||||
int *msg=(int*)side_info_buf;
|
||||
int action_flag, reg_type, reg_idx;
|
||||
u32 reg_val, *cmd_buf;
|
||||
int res;
|
||||
|
||||
// printk(KERN_INFO "Entering: %s\n", __FUNCTION__);
|
||||
|
||||
// msg_size=strlen(msg);
|
||||
|
||||
nlh=(struct nlmsghdr*)skb->data;
|
||||
cmd_buf = (u32*)nlmsg_data(nlh);
|
||||
// printk(KERN_INFO "Netlink received msg payload:%s\n",(char*)nlmsg_data(nlh));
|
||||
action_flag = cmd_buf[0];
|
||||
reg_type = cmd_buf[1];
|
||||
reg_idx = cmd_buf[2];
|
||||
reg_val = cmd_buf[3];
|
||||
printk("%s recv msg: len %d action_flag %d reg_type %d reg_idx %d reg_val %u\n", side_ch_compatible_str, nlmsg_len(nlh), action_flag, reg_type, reg_idx, reg_val);
|
||||
|
||||
pid = nlh->nlmsg_pid; /*pid of sending process */
|
||||
|
||||
if (action_flag==ACTION_SIDE_INFO_GET) {
|
||||
res = get_side_info(num_eq_init);
|
||||
printk(KERN_INFO "%s recv msg: get_side_info(%d) res %d\n", side_ch_compatible_str, num_eq_init, res);
|
||||
if (res>0) {
|
||||
msg_size = res;
|
||||
// printk("%s recv msg: %d %d %d %d %d %d %d %d\n", side_ch_compatible_str, msg[0], msg[1], msg[2], msg[3], msg[4], msg[5], msg[6], msg[7]);
|
||||
} else {
|
||||
msg_size = 4;
|
||||
msg[0] = -2;
|
||||
}
|
||||
} else if (action_flag==ACTION_REG_READ) {
|
||||
msg_size = 4;
|
||||
// if (reg_idx<0 || reg_idx>31) {
|
||||
// msg[0] = -3;
|
||||
// printk("%s recv msg: invalid reg_idx\n", side_ch_compatible_str);
|
||||
// } else {
|
||||
msg[0] = reg_read(reg_idx*4);
|
||||
// }
|
||||
} else if (action_flag==ACTION_REG_WRITE) {
|
||||
msg_size = 4;
|
||||
// if (reg_idx<0 || reg_idx>31) {
|
||||
// msg[0] = -4;
|
||||
// printk("%s recv msg: invalid reg_idx\n", side_ch_compatible_str);
|
||||
// } else {
|
||||
msg[0] = 0;
|
||||
reg_write(reg_idx*4, reg_val);
|
||||
// }
|
||||
} else {
|
||||
msg_size = 4;
|
||||
msg[0] = -1;
|
||||
printk("%s recv msg: invalid action_flag\n", side_ch_compatible_str);
|
||||
}
|
||||
|
||||
skb_out = nlmsg_new(msg_size,0);
|
||||
if(!skb_out)
|
||||
{
|
||||
printk(KERN_ERR "Failed to allocate new skb\n");
|
||||
return;
|
||||
}
|
||||
nlh=nlmsg_put(skb_out,0,0,NLMSG_DONE,msg_size,0);
|
||||
NETLINK_CB(skb_out).dst_group = 0; /* not in mcast group */
|
||||
|
||||
memcpy(nlmsg_data(nlh),msg,msg_size);
|
||||
|
||||
res=nlmsg_unicast(nl_sk,skb_out,pid);
|
||||
|
||||
if(res<0)
|
||||
printk(KERN_INFO "Error while sending bak to user\n");
|
||||
}
|
||||
|
||||
static int dev_probe(struct platform_device *pdev) {
|
||||
struct netlink_kernel_cfg cfg = {
|
||||
.input = side_ch_nl_recv_msg,
|
||||
};
|
||||
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct resource *io;
|
||||
int err=1, i;
|
||||
|
||||
printk("\n");
|
||||
|
||||
if (np) {
|
||||
const struct of_device_id *match;
|
||||
|
||||
match = of_match_node(dev_of_ids, np);
|
||||
if (match) {
|
||||
printk("%s dev_probe: match!\n", side_ch_compatible_str);
|
||||
err = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Request and map I/O memory */
|
||||
io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base_addr = devm_ioremap_resource(&pdev->dev, io);
|
||||
if (IS_ERR(base_addr))
|
||||
return PTR_ERR(base_addr);
|
||||
|
||||
printk("%s dev_probe: io start 0x%p end 0x%p name %s flags 0x%08x desc %s\n", side_ch_compatible_str, (void*)io->start, (void*)io->end, io->name, (u32)io->flags, (char*)io->desc);
|
||||
printk("%s dev_probe: base_addr 0x%p\n", side_ch_compatible_str, base_addr);
|
||||
|
||||
printk("%s dev_probe: succeed!\n", side_ch_compatible_str);
|
||||
|
||||
// --------------initialize netlink--------------
|
||||
//nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, &cfg);
|
||||
nl_sk = netlink_kernel_create(&init_net, NETLINK_USERSOCK, &cfg);
|
||||
if(!nl_sk) {
|
||||
printk(KERN_ALERT "%s dev_probe: Error creating socket.\n", side_ch_compatible_str);
|
||||
return -10;
|
||||
}
|
||||
|
||||
//-----------------initialize fpga----------------
|
||||
//rst
|
||||
for (i=0;i<8;i++)
|
||||
SIDE_CH_REG_MULTI_RST_write(0);
|
||||
for (i=0;i<32;i++)
|
||||
SIDE_CH_REG_MULTI_RST_write(0xFFFFFFFF);
|
||||
for (i=0;i<8;i++)
|
||||
SIDE_CH_REG_MULTI_RST_write(0);
|
||||
|
||||
// chan_to_pl = dma_request_slave_channel(&(pdev->dev), "rx_dma_mm2s");
|
||||
// if (IS_ERR(chan_to_pl)) {
|
||||
// err = PTR_ERR(chan_to_pl);
|
||||
// pr_err("%s dev_probe: No channel to PL. %d\n",side_ch_compatible_str,err);
|
||||
// goto free_chan_to_pl;
|
||||
// }
|
||||
|
||||
chan_to_ps = dma_request_slave_channel(&(pdev->dev), "tx_dma_s2mm");
|
||||
if (IS_ERR(chan_to_ps)) {
|
||||
err = PTR_ERR(chan_to_ps);
|
||||
pr_err("%s dev_probe: No channel to PS. %d\n",side_ch_compatible_str,err);
|
||||
goto free_chan_to_ps;
|
||||
}
|
||||
|
||||
printk("%s dev_probe: DMA channel setup successfully. chan_to_pl 0x%p chan_to_ps 0x%p\n",side_ch_compatible_str, chan_to_pl, chan_to_ps);
|
||||
|
||||
// res = dma_loopback_test(3, 512);
|
||||
// printk(KERN_INFO "dma_loopback_test(3, 512) res %d\n", res);
|
||||
|
||||
err = init_side_channel();
|
||||
printk("%s dev_probe: init_side_channel() err %d\n",side_ch_compatible_str, err);
|
||||
|
||||
printk("%s dev_probe: num_eq_init %d\n",side_ch_compatible_str, num_eq_init);
|
||||
// SIDE_CH_REG_CONFIG_write(0X6001); // match addr1 and addr2; bit12 FC; bit13 addr1; bit14 addr2
|
||||
SIDE_CH_REG_CONFIG_write(0x0001); // match all packets by default; bit12 FC; bit13 addr1; bit14 addr2
|
||||
SIDE_CH_REG_NUM_EQ_write(num_eq_init); // capture CSI + 8*equalizer by default
|
||||
|
||||
return(err);
|
||||
|
||||
// err = dma_loopback_test(7, 512);
|
||||
// if (err == 0)
|
||||
// return(err);
|
||||
// else
|
||||
// dma_release_channel(chan_to_ps);
|
||||
|
||||
free_chan_to_ps:
|
||||
err = -2;
|
||||
dma_release_channel(chan_to_ps);
|
||||
return err;
|
||||
|
||||
// free_chan_to_pl:
|
||||
// err = -1;
|
||||
// dma_release_channel(chan_to_pl);
|
||||
// return err;
|
||||
}
|
||||
|
||||
static int dev_remove(struct platform_device *pdev)
|
||||
{
|
||||
printk("\n");
|
||||
|
||||
printk("%s dev_remove: release nl_sk\n", side_ch_compatible_str);
|
||||
netlink_kernel_release(nl_sk);
|
||||
|
||||
pr_info("%s dev_remove: dropped chan_to_pl 0x%p\n", side_ch_compatible_str, chan_to_pl);
|
||||
if (chan_to_pl != NULL) {
|
||||
pr_info("%s dev_remove: dropped channel %s\n", side_ch_compatible_str, dma_chan_name(chan_to_pl));
|
||||
// dmaengine_terminate_all(chan_to_pl); //this also terminate sdr.ko. do not use
|
||||
dma_release_channel(chan_to_pl);
|
||||
}
|
||||
|
||||
pr_info("%s dev_remove: dropped chan_to_ps 0x%p\n", side_ch_compatible_str, chan_to_ps);
|
||||
if (chan_to_pl != NULL) {
|
||||
pr_info("%s dev_remove: dropped channel %s\n", side_ch_compatible_str, dma_chan_name(chan_to_ps));
|
||||
// dmaengine_terminate_all(chan_to_ps); //this also terminate sdr.ko. do not use
|
||||
dma_release_channel(chan_to_ps);
|
||||
}
|
||||
|
||||
if (side_info_buf != NULL)
|
||||
kfree(side_info_buf);
|
||||
|
||||
printk("%s dev_remove: base_addr 0x%p\n", side_ch_compatible_str, base_addr);
|
||||
printk("%s dev_remove: succeed!\n", side_ch_compatible_str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver dev_driver = {
|
||||
.driver = {
|
||||
.name = "sdr,side_ch",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = dev_of_ids,
|
||||
},
|
||||
.probe = dev_probe,
|
||||
.remove = dev_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(dev_driver);
|
||||
|
||||
MODULE_AUTHOR("Xianjun Jiao");
|
||||
MODULE_DESCRIPTION("sdr,side_ch");
|
||||
MODULE_LICENSE("GPL v2");
|
22
driver/side_ch/side_ch.h
Normal file
22
driver/side_ch/side_ch.h
Normal file
@ -0,0 +1,22 @@
|
||||
// Xianjun jiao. putaoshu@msn.com; xianjun.jiao@imec.be
|
||||
|
||||
// ---------------------------------------side channel-------------------------------
|
||||
const char *side_ch_compatible_str = "sdr,side_ch";
|
||||
|
||||
//align with side_ch_control.v and all related user space, remote files
|
||||
#define CSI_LEN 56 // length of single CSI
|
||||
#define EQUALIZER_LEN (56-4) // for non HT, four {32767,32767} will be padded to achieve 52 (non HT should have 48)
|
||||
#define HEADER_LEN 2 //timestamp and frequency offset
|
||||
|
||||
#define MAX_NUM_DMA_SYMBOL 4096 //align with side_ch.v side_ch.h
|
||||
|
||||
#define SIDE_CH_REG_MULTI_RST_ADDR (0*4)
|
||||
#define SIDE_CH_REG_CONFIG_ADDR (1*4)
|
||||
#define SIDE_CH_REG_NUM_DMA_SYMBOL_ADDR (2*4) //low 16bit to PS; high 16bit to PL
|
||||
#define SIDE_CH_REG_START_DMA_TO_PS_ADDR (3*4)
|
||||
#define SIDE_CH_REG_NUM_EQ_ADDR (4*4)
|
||||
#define SIDE_CH_REG_FC_TARGET_ADDR (5*4)
|
||||
#define SIDE_CH_REG_ADDR1_TARGET_ADDR (6*4)
|
||||
#define SIDE_CH_REG_ADDR2_TARGET_ADDR (7*4)
|
||||
|
||||
#define SIDE_CH_REG_M_AXIS_DATA_COUNT_ADDR (20*4)
|
@ -283,8 +283,8 @@ static inline u32 hw_init(enum tx_intf_mode mode, u32 num_dma_symbol_to_pl, u32
|
||||
tx_intf_api->TX_INTF_REG_NUM_DMA_SYMBOL_TO_PS_write(num_dma_symbol_to_ps);
|
||||
tx_intf_api->TX_INTF_REG_CFG_DATA_TO_ANT_write(0);
|
||||
tx_intf_api->TX_INTF_REG_TX_HOLD_THRESHOLD_write(420);
|
||||
tx_intf_api->TX_INTF_REG_INTERRUPT_SEL_write(0x4F); //.src_sel0(slv_reg14[2:0]), .src_sel1(slv_reg14[6:4]), 0-s00_axis_tlast,1-ap_start,2-tx_start_from_acc,3-tx_end_from_acc,4-xpu signal
|
||||
tx_intf_api->TX_INTF_REG_INTERRUPT_SEL_write(0x3004F); //disable interrupt
|
||||
tx_intf_api->TX_INTF_REG_INTERRUPT_SEL_write(0x4); //.src_sel(slv_reg14[2:0]), 0-s00_axis_tlast,1-ap_start,2-tx_start_from_acc,3-tx_end_from_acc,4-tx_try_complete from xpu
|
||||
tx_intf_api->TX_INTF_REG_INTERRUPT_SEL_write(0x30004); //disable interrupt
|
||||
tx_intf_api->TX_INTF_REG_BB_GAIN_write(100);
|
||||
tx_intf_api->TX_INTF_REG_ANT_SEL_write(ant_sel);
|
||||
tx_intf_api->TX_INTF_REG_WIFI_TX_MODE_write((1<<3)|(2<<4));
|
||||
|
Binary file not shown.
@ -713,12 +713,10 @@
|
||||
|
||||
sdr: sdr {
|
||||
compatible ="sdr,sdr";
|
||||
dmas = <&rx_dma 0
|
||||
&rx_dma 1
|
||||
&tx_dma 0
|
||||
&tx_dma 1>;
|
||||
dma-names = "rx_dma_mm2s", "rx_dma_s2mm", "tx_dma_mm2s", "tx_dma_s2mm";
|
||||
interrupt-names = "not_valid_anymore", "rx_pkt_intr", "tx_itrpt0", "tx_itrpt1";
|
||||
dmas = <&rx_dma 1
|
||||
&tx_dma 0>;
|
||||
dma-names = "rx_dma_s2mm", "tx_dma_mm2s";
|
||||
interrupt-names = "not_valid_anymore", "rx_pkt_intr", "tx_itrpt";
|
||||
interrupt-parent = <1>;
|
||||
interrupts = <0 29 1 0 30 1 0 33 1 0 34 1>;
|
||||
} ;
|
||||
@ -788,20 +786,20 @@
|
||||
};
|
||||
|
||||
tx_intf_0: tx_intf@83c00000 {
|
||||
clock-names = "s00_axi_aclk", "s00_axis_aclk", "s01_axis_aclk", "m00_axis_aclk";
|
||||
clocks = <0x2 0x11>, <0x2 0x11>, <0x2 0x11>, <0x2 0x11>;
|
||||
clock-names = "s00_axi_aclk", "s00_axis_aclk";//, "s01_axis_aclk", "m00_axis_aclk";
|
||||
clocks = <0x2 0x11>, <0x2 0x11>;//, <0x2 0x11>, <0x2 0x11>;
|
||||
compatible = "sdr,tx_intf";
|
||||
interrupt-names = "tx_itrpt0", "tx_itrpt1";
|
||||
interrupt-names = "tx_itrpt";
|
||||
interrupt-parent = <1>;
|
||||
interrupts = <0 33 1 0 34 1>;
|
||||
interrupts = <0 34 1>;
|
||||
reg = <0x83c00000 0x10000>;
|
||||
xlnx,s00-axi-addr-width = <0x7>;
|
||||
xlnx,s00-axi-data-width = <0x20>;
|
||||
};
|
||||
|
||||
rx_intf_0: rx_intf@83c20000 {
|
||||
clock-names = "s00_axi_aclk", "s00_axis_aclk", "m00_axis_aclk";
|
||||
clocks = <0x2 0x11>, <0x2 0x11>, <0x2 0x11>;
|
||||
clock-names = "s00_axi_aclk", "m00_axis_aclk";//, "s00_axis_aclk";
|
||||
clocks = <0x2 0x11>, <0x2 0x11>;//, <0x2 0x11>;
|
||||
compatible = "sdr,rx_intf";
|
||||
interrupt-names = "not_valid_anymore", "rx_pkt_intr";
|
||||
interrupt-parent = <1>;
|
||||
@ -832,6 +830,16 @@
|
||||
reg = <0x83c40000 0x10000>;
|
||||
};
|
||||
|
||||
side_ch_0: side_ch@83c50000 {
|
||||
clock-names = "s00_axi_aclk";
|
||||
clocks = <0x2 0x11>;
|
||||
compatible = "sdr,side_ch";
|
||||
reg = <0x83c50000 0x10000>;
|
||||
dmas = <&rx_dma 0
|
||||
&tx_dma 1>;
|
||||
dma-names = "rx_dma_mm2s", "tx_dma_s2mm";
|
||||
};
|
||||
|
||||
cf-ad9361-lpc@79020000 {
|
||||
compatible = "adi,axi-ad9361-6.00.a";
|
||||
reg = <0x79020000 0x6000>;
|
||||
|
Binary file not shown.
@ -702,12 +702,10 @@
|
||||
|
||||
sdr: sdr {
|
||||
compatible ="sdr,sdr";
|
||||
dmas = <&rx_dma 0
|
||||
&rx_dma 1
|
||||
&tx_dma 0
|
||||
&tx_dma 1>;
|
||||
dma-names = "rx_dma_mm2s", "rx_dma_s2mm", "tx_dma_mm2s", "tx_dma_s2mm";
|
||||
interrupt-names = "not_valid_anymore", "rx_pkt_intr", "tx_itrpt0", "tx_itrpt1";
|
||||
dmas = <&rx_dma 1
|
||||
&tx_dma 0>;
|
||||
dma-names = "rx_dma_s2mm", "tx_dma_mm2s";
|
||||
interrupt-names = "not_valid_anymore", "rx_pkt_intr", "tx_itrpt";
|
||||
interrupt-parent = <1>;
|
||||
interrupts = <0 29 1 0 30 1 0 33 1 0 34 1>;
|
||||
} ;
|
||||
@ -777,20 +775,20 @@
|
||||
};
|
||||
|
||||
tx_intf_0: tx_intf@83c00000 {
|
||||
clock-names = "s00_axi_aclk", "s00_axis_aclk", "s01_axis_aclk", "m00_axis_aclk";
|
||||
clocks = <0x2 0x11>, <0x2 0x11>, <0x2 0x11>, <0x2 0x11>;
|
||||
clock-names = "s00_axi_aclk", "s00_axis_aclk";//, "s01_axis_aclk", "m00_axis_aclk";
|
||||
clocks = <0x2 0x11>, <0x2 0x11>;//, <0x2 0x11>, <0x2 0x11>;
|
||||
compatible = "sdr,tx_intf";
|
||||
interrupt-names = "tx_itrpt0", "tx_itrpt1";
|
||||
interrupt-names = "tx_itrpt";
|
||||
interrupt-parent = <1>;
|
||||
interrupts = <0 33 1 0 34 1>;
|
||||
interrupts = <0 34 1>;
|
||||
reg = <0x83c00000 0x10000>;
|
||||
xlnx,s00-axi-addr-width = <0x7>;
|
||||
xlnx,s00-axi-data-width = <0x20>;
|
||||
};
|
||||
|
||||
rx_intf_0: rx_intf@83c20000 {
|
||||
clock-names = "s00_axi_aclk", "s00_axis_aclk", "m00_axis_aclk";
|
||||
clocks = <0x2 0x11>, <0x2 0x11>, <0x2 0x11>;
|
||||
clock-names = "s00_axi_aclk", "m00_axis_aclk";//, "s00_axis_aclk";
|
||||
clocks = <0x2 0x11>, <0x2 0x11>;//, <0x2 0x11>;
|
||||
compatible = "sdr,rx_intf";
|
||||
interrupt-names = "not_valid_anymore", "rx_pkt_intr";
|
||||
interrupt-parent = <1>;
|
||||
@ -821,6 +819,16 @@
|
||||
reg = <0x83c40000 0x10000>;
|
||||
};
|
||||
|
||||
side_ch_0: side_ch@83c50000 {
|
||||
clock-names = "s00_axi_aclk";
|
||||
clocks = <0x2 0x11>;
|
||||
compatible = "sdr,side_ch";
|
||||
reg = <0x83c50000 0x10000>;
|
||||
dmas = <&rx_dma 0
|
||||
&tx_dma 1>;
|
||||
dma-names = "rx_dma_mm2s", "tx_dma_s2mm";
|
||||
};
|
||||
|
||||
cf-ad9361-lpc@79020000 {
|
||||
compatible = "adi,axi-ad9361-6.00.a";
|
||||
reg = <0x79020000 0x6000>;
|
||||
|
Binary file not shown.
@ -922,12 +922,10 @@
|
||||
|
||||
sdr: sdr {
|
||||
compatible ="sdr,sdr";
|
||||
dmas = <&rx_dma 0
|
||||
&rx_dma 1
|
||||
&tx_dma 0
|
||||
&tx_dma 1>;
|
||||
dma-names = "rx_dma_mm2s", "rx_dma_s2mm", "tx_dma_mm2s", "tx_dma_s2mm";
|
||||
interrupt-names = "not_valid_anymore", "rx_pkt_intr", "tx_itrpt0", "tx_itrpt1";
|
||||
dmas = <&rx_dma 1
|
||||
&tx_dma 0>;
|
||||
dma-names = "rx_dma_s2mm", "tx_dma_mm2s";
|
||||
interrupt-names = "not_valid_anymore", "rx_pkt_intr", "tx_itrpt";
|
||||
interrupt-parent = <1>;
|
||||
interrupts = <0 29 1 0 30 1 0 33 1 0 34 1>;
|
||||
} ;
|
||||
@ -997,20 +995,20 @@
|
||||
};
|
||||
|
||||
tx_intf_0: tx_intf@83c00000 {
|
||||
clock-names = "s00_axi_aclk", "s00_axis_aclk", "s01_axis_aclk", "m00_axis_aclk";
|
||||
clocks = <0x2 0x11>, <0x2 0x11>, <0x2 0x11>, <0x2 0x11>;
|
||||
clock-names = "s00_axi_aclk", "s00_axis_aclk";//, "s01_axis_aclk", "m00_axis_aclk";
|
||||
clocks = <0x2 0x11>, <0x2 0x11>;//, <0x2 0x11>, <0x2 0x11>;
|
||||
compatible = "sdr,tx_intf";
|
||||
interrupt-names = "tx_itrpt0", "tx_itrpt1";
|
||||
interrupt-names = "tx_itrpt";
|
||||
interrupt-parent = <1>;
|
||||
interrupts = <0 33 1 0 34 1>;
|
||||
interrupts = <0 34 1>;
|
||||
reg = <0x83c00000 0x10000>;
|
||||
xlnx,s00-axi-addr-width = <0x7>;
|
||||
xlnx,s00-axi-data-width = <0x20>;
|
||||
};
|
||||
|
||||
rx_intf_0: rx_intf@83c20000 {
|
||||
clock-names = "s00_axi_aclk", "s00_axis_aclk", "m00_axis_aclk";
|
||||
clocks = <0x2 0x11>, <0x2 0x11>, <0x2 0x11>;
|
||||
clock-names = "s00_axi_aclk", "m00_axis_aclk";//, "s00_axis_aclk";
|
||||
clocks = <0x2 0x11>, <0x2 0x11>;//, <0x2 0x11>;
|
||||
compatible = "sdr,rx_intf";
|
||||
interrupt-names = "not_valid_anymore", "rx_pkt_intr";
|
||||
interrupt-parent = <1>;
|
||||
@ -1041,6 +1039,16 @@
|
||||
reg = <0x83c40000 0x10000>;
|
||||
};
|
||||
|
||||
side_ch_0: side_ch@83c50000 {
|
||||
clock-names = "s00_axi_aclk";
|
||||
clocks = <0x2 0x11>;
|
||||
compatible = "sdr,side_ch";
|
||||
reg = <0x83c50000 0x10000>;
|
||||
dmas = <&rx_dma 0
|
||||
&tx_dma 1>;
|
||||
dma-names = "rx_dma_mm2s", "tx_dma_s2mm";
|
||||
};
|
||||
|
||||
cf-ad9361-lpc@79020000 {
|
||||
compatible = "adi,axi-ad9361-6.00.a";
|
||||
reg = <0x79020000 0x6000>;
|
||||
|
Binary file not shown.
@ -918,12 +918,10 @@
|
||||
|
||||
sdr: sdr {
|
||||
compatible ="sdr,sdr";
|
||||
dmas = <&rx_dma 0
|
||||
&rx_dma 1
|
||||
&tx_dma 0
|
||||
&tx_dma 1>;
|
||||
dma-names = "rx_dma_mm2s", "rx_dma_s2mm", "tx_dma_mm2s", "tx_dma_s2mm";
|
||||
interrupt-names = "not_valid_anymore", "rx_pkt_intr", "tx_itrpt0", "tx_itrpt1";
|
||||
dmas = <&rx_dma 1
|
||||
&tx_dma 0>;
|
||||
dma-names = "rx_dma_s2mm", "tx_dma_mm2s";
|
||||
interrupt-names = "not_valid_anymore", "rx_pkt_intr", "tx_itrpt";
|
||||
interrupt-parent = <1>;
|
||||
interrupts = <0 29 1 0 30 1 0 33 1 0 34 1>;
|
||||
} ;
|
||||
@ -993,20 +991,20 @@
|
||||
};
|
||||
|
||||
tx_intf_0: tx_intf@83c00000 {
|
||||
clock-names = "s00_axi_aclk", "s00_axis_aclk", "s01_axis_aclk", "m00_axis_aclk";
|
||||
clocks = <0x2 0x11>, <0x2 0x11>, <0x2 0x11>, <0x2 0x11>;
|
||||
clock-names = "s00_axi_aclk", "s00_axis_aclk";//, "s01_axis_aclk", "m00_axis_aclk";
|
||||
clocks = <0x2 0x11>, <0x2 0x11>;//, <0x2 0x11>, <0x2 0x11>;
|
||||
compatible = "sdr,tx_intf";
|
||||
interrupt-names = "tx_itrpt0", "tx_itrpt1";
|
||||
interrupt-names = "tx_itrpt";
|
||||
interrupt-parent = <1>;
|
||||
interrupts = <0 33 1 0 34 1>;
|
||||
interrupts = <0 34 1>;
|
||||
reg = <0x83c00000 0x10000>;
|
||||
xlnx,s00-axi-addr-width = <0x7>;
|
||||
xlnx,s00-axi-data-width = <0x20>;
|
||||
};
|
||||
|
||||
rx_intf_0: rx_intf@83c20000 {
|
||||
clock-names = "s00_axi_aclk", "s00_axis_aclk", "m00_axis_aclk";
|
||||
clocks = <0x2 0x11>, <0x2 0x11>, <0x2 0x11>;
|
||||
clock-names = "s00_axi_aclk", "m00_axis_aclk";//, "s00_axis_aclk";
|
||||
clocks = <0x2 0x11>, <0x2 0x11>;//, <0x2 0x11>;
|
||||
compatible = "sdr,rx_intf";
|
||||
interrupt-names = "not_valid_anymore", "rx_pkt_intr";
|
||||
interrupt-parent = <1>;
|
||||
@ -1037,6 +1035,16 @@
|
||||
reg = <0x83c40000 0x10000>;
|
||||
};
|
||||
|
||||
side_ch_0: side_ch@83c50000 {
|
||||
clock-names = "s00_axi_aclk";
|
||||
clocks = <0x2 0x11>;
|
||||
compatible = "sdr,side_ch";
|
||||
reg = <0x83c50000 0x10000>;
|
||||
dmas = <&rx_dma 0
|
||||
&tx_dma 1>;
|
||||
dma-names = "rx_dma_mm2s", "tx_dma_s2mm";
|
||||
};
|
||||
|
||||
cf-ad9361-lpc@79020000 {
|
||||
compatible = "adi,axi-ad9361-6.00.a";
|
||||
reg = <0x79020000 0x6000>;
|
||||
|
Binary file not shown.
@ -2438,12 +2438,10 @@
|
||||
|
||||
sdr: sdr {
|
||||
compatible ="sdr,sdr";
|
||||
dmas = <&rx_dma 0
|
||||
&rx_dma 1
|
||||
&tx_dma 0
|
||||
&tx_dma 1>;
|
||||
dma-names = "rx_dma_mm2s", "rx_dma_s2mm", "tx_dma_mm2s", "tx_dma_s2mm";
|
||||
interrupt-names = "not_valid_anymore", "rx_pkt_intr", "tx_itrpt0", "tx_itrpt1";
|
||||
dmas = <&rx_dma 1
|
||||
&tx_dma 0>;
|
||||
dma-names = "rx_dma_s2mm", "tx_dma_mm2s";
|
||||
interrupt-names = "not_valid_anymore", "rx_pkt_intr", "tx_itrpt_useless", "tx_itrpt";
|
||||
interrupts = <0 89 1 0 90 1 0 93 1 0 94 1>;
|
||||
} ;
|
||||
|
||||
@ -2510,19 +2508,19 @@
|
||||
};
|
||||
|
||||
tx_intf_0: tx_intf@a0005000 {
|
||||
clock-names = "s00_axi_aclk", "s00_axis_aclk", "s01_axis_aclk", "m00_axis_aclk";
|
||||
clocks = <0x3 0x49>, <0x3 0x49>, <0x3 0x49>, <0x3 0x49>;
|
||||
clock-names = "s00_axi_aclk", "s00_axis_aclk";//, "s01_axis_aclk", "m00_axis_aclk";
|
||||
clocks = <0x3 0x49>, <0x3 0x49>;//, <0x3 0x49>, <0x3 0x49>;
|
||||
compatible = "sdr,tx_intf";
|
||||
interrupt-names = "tx_itrpt0", "tx_itrpt1";
|
||||
interrupts = <0 93 1 0 94 1>;
|
||||
interrupt-names = "tx_itrpt";
|
||||
interrupts = <0 94 1>;
|
||||
reg = <0xA0005000 0x1000>;
|
||||
xlnx,s00-axi-addr-width = <0x7>;
|
||||
xlnx,s00-axi-data-width = <0x20>;
|
||||
};
|
||||
|
||||
rx_intf_0: rx_intf@a0004000 {
|
||||
clock-names = "s00_axi_aclk", "s00_axis_aclk", "m00_axis_aclk";
|
||||
clocks = <0x3 0x49>, <0x3 0x49>, <0x3 0x49>;
|
||||
clock-names = "s00_axi_aclk", "m00_axis_aclk";//, "s00_axis_aclk";
|
||||
clocks = <0x3 0x49>, <0x3 0x49>;//, <0x3 0x49>;
|
||||
compatible = "sdr,rx_intf";
|
||||
interrupt-names = "not_valid_anymore", "rx_pkt_intr";
|
||||
interrupts = <0 89 1 0 90 1>;
|
||||
@ -2552,6 +2550,16 @@
|
||||
reg = <0xA0006000 0x1000>;
|
||||
};
|
||||
|
||||
side_ch_0: side_ch@a0007000 {
|
||||
clock-names = "s00_axi_aclk";
|
||||
clocks = <0x3 0x49>;
|
||||
compatible = "sdr,side_ch";
|
||||
reg = <0xA0007000 0x1000>;
|
||||
dmas = <&rx_dma 0
|
||||
&tx_dma 1>;
|
||||
dma-names = "rx_dma_mm2s", "tx_dma_s2mm";
|
||||
};
|
||||
|
||||
cf-ad9361-lpc@99020000 {
|
||||
compatible = "adi,axi-ad9361-6.00.a";
|
||||
reg = <0x99020000 0x6000>;
|
||||
|
Binary file not shown.
@ -828,12 +828,10 @@
|
||||
|
||||
sdr: sdr {
|
||||
compatible ="sdr,sdr";
|
||||
dmas = <&rx_dma 0
|
||||
&rx_dma 1
|
||||
&tx_dma 0
|
||||
&tx_dma 1>;
|
||||
dma-names = "rx_dma_mm2s", "rx_dma_s2mm", "tx_dma_mm2s", "tx_dma_s2mm";
|
||||
interrupt-names = "not_valid_anymore", "rx_pkt_intr", "tx_itrpt0", "tx_itrpt1";
|
||||
dmas = <&rx_dma 1
|
||||
&tx_dma 0>;
|
||||
dma-names = "rx_dma_s2mm", "tx_dma_mm2s";
|
||||
interrupt-names = "not_valid_anymore", "rx_pkt_intr", "tx_itrpt";
|
||||
interrupt-parent = <1>;
|
||||
interrupts = <0 29 1 0 30 1 0 33 1 0 34 1>;
|
||||
} ;
|
||||
@ -903,20 +901,20 @@
|
||||
};
|
||||
|
||||
tx_intf_0: tx_intf@83c00000 {
|
||||
clock-names = "s00_axi_aclk", "s00_axis_aclk", "s01_axis_aclk", "m00_axis_aclk";
|
||||
clocks = <0x2 0x11>, <0x2 0x11>, <0x2 0x11>, <0x2 0x11>;
|
||||
clock-names = "s00_axi_aclk", "s00_axis_aclk";//, "s01_axis_aclk", "m00_axis_aclk";
|
||||
clocks = <0x2 0x11>, <0x2 0x11>;//, <0x2 0x11>, <0x2 0x11>;
|
||||
compatible = "sdr,tx_intf";
|
||||
interrupt-names = "tx_itrpt0", "tx_itrpt1";
|
||||
interrupt-names = "tx_itrpt";
|
||||
interrupt-parent = <1>;
|
||||
interrupts = <0 33 1 0 34 1>;
|
||||
interrupts = <0 34 1>;
|
||||
reg = <0x83c00000 0x10000>;
|
||||
xlnx,s00-axi-addr-width = <0x7>;
|
||||
xlnx,s00-axi-data-width = <0x20>;
|
||||
};
|
||||
|
||||
rx_intf_0: rx_intf@83c20000 {
|
||||
clock-names = "s00_axi_aclk", "s00_axis_aclk", "m00_axis_aclk";
|
||||
clocks = <0x2 0x11>, <0x2 0x11>, <0x2 0x11>;
|
||||
clock-names = "s00_axi_aclk", "m00_axis_aclk";//, "s00_axis_aclk";
|
||||
clocks = <0x2 0x11>, <0x2 0x11>;//, <0x2 0x11>;
|
||||
compatible = "sdr,rx_intf";
|
||||
interrupt-names = "not_valid_anymore", "rx_pkt_intr";
|
||||
interrupt-parent = <1>;
|
||||
@ -947,6 +945,16 @@
|
||||
reg = <0x83c40000 0x10000>;
|
||||
};
|
||||
|
||||
side_ch_0: side_ch@83c50000 {
|
||||
clock-names = "s00_axi_aclk";
|
||||
clocks = <0x2 0x11>;
|
||||
compatible = "sdr,side_ch";
|
||||
reg = <0x83c50000 0x10000>;
|
||||
dmas = <&rx_dma 0
|
||||
&tx_dma 1>;
|
||||
dma-names = "rx_dma_mm2s", "tx_dma_s2mm";
|
||||
};
|
||||
|
||||
cf-ad9361-lpc@79020000 {
|
||||
compatible = "adi,axi-ad9361-6.00.a";
|
||||
reg = <0x79020000 0x6000>;
|
||||
|
@ -32,6 +32,9 @@ sudo apt-get -y install libnl-genl-3-dev
|
||||
cd sdrctl_src
|
||||
make
|
||||
cp sdrctl ../
|
||||
cd ../side_ch_ctl_src/
|
||||
gcc -o side_ch_ctl side_ch_ctl.c
|
||||
cp side_ch_ctl ../
|
||||
cd ..
|
||||
|
||||
# install and setup dhcp server
|
||||
|
@ -1,5 +1,5 @@
|
||||
//---nl80211 cmd testmode definitions
|
||||
//---should be used in driver sdr.c and user space app like sdrctl, iw
|
||||
//---should be used in driver sdr.c and user space app
|
||||
|
||||
enum openwifi_testmode_attr {
|
||||
__OPENWIFI_ATTR_INVALID = 0,
|
||||
|
403
user_space/side_ch_ctl_src/side_ch_ctl.c
Normal file
403
user_space/side_ch_ctl_src/side_ch_ctl.c
Normal file
@ -0,0 +1,403 @@
|
||||
/*
|
||||
* openwifi side channel user space program
|
||||
* Xianjun jiao. putaoshu@msn.com; xianjun.jiao@imec.be
|
||||
*/
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
// #define NETLINK_USER 31
|
||||
#define MAX_NUM_DMA_SYMBOL 4096 //align with side_ch.v side_ch.h
|
||||
|
||||
#define MAX_PAYLOAD (8*MAX_NUM_DMA_SYMBOL) /* maximum payload size*/
|
||||
struct sockaddr_nl src_addr, dest_addr;
|
||||
struct nlmsghdr *nlh = NULL;
|
||||
struct iovec iov;
|
||||
int sock_fd;
|
||||
struct msghdr msg;
|
||||
|
||||
//align with side_ch_control.v and all related user space, remote files
|
||||
#define CSI_LEN 56 // length of single CSI
|
||||
#define EQUALIZER_LEN (56-4) // for non HT, four {32767,32767} will be padded to achieve 52 (non HT should have 48)
|
||||
#define HEADER_LEN 2 //timestamp and frequency offset
|
||||
|
||||
#define ACTION_INVALID 0
|
||||
#define ACTION_REG_WRITE 1
|
||||
#define ACTION_REG_READ 2
|
||||
#define ACTION_SIDE_INFO_GET 3
|
||||
|
||||
#define REG_TYPE_INVALID 0
|
||||
#define REG_TYPE_HARDWARE 1
|
||||
#define REG_TYPE_SOFTWARE 2
|
||||
|
||||
#define MAX_PARA_STRING_LEN 31
|
||||
char tmp_str[MAX_PARA_STRING_LEN+1];
|
||||
int take_reg_idx_string_for_write(char *para) { // return into tmp_str till 'd' 'D' 'h' 'H' or 0
|
||||
int i = 0;
|
||||
|
||||
// while (para[i] != 'd' && para[i] != 'D' && para[i] != 'h' && para[i] != 'H' && para[i] != 0) {
|
||||
while (para[i] != 'd' && para[i] != 'h' && para[i] != 0) {
|
||||
tmp_str[i] = para[i];
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i==0)
|
||||
return(-1);
|
||||
|
||||
if (para[i-1] == 0) // we expect d D h H, not 0!
|
||||
return(-2);
|
||||
|
||||
tmp_str[i] = 0;
|
||||
|
||||
return(i);
|
||||
}
|
||||
|
||||
int take_reg_val_string_for_write(char *para) {
|
||||
int i = 0;
|
||||
|
||||
while (para[i] != 0) {
|
||||
tmp_str[i] = para[i];
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i==0)
|
||||
return(-1);
|
||||
|
||||
tmp_str[i] = 0;
|
||||
|
||||
return(i);
|
||||
}
|
||||
|
||||
int all_zero_in_string(char *para) {
|
||||
int i;
|
||||
int check_len = strlen(para);
|
||||
|
||||
if (check_len == 0)
|
||||
return(-1);
|
||||
|
||||
i = 0;
|
||||
while (para[i] == '0')
|
||||
i++;
|
||||
|
||||
if (i == check_len)
|
||||
return(1);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
long int atoi_my(char *para) {
|
||||
long int ret = all_zero_in_string(para);
|
||||
|
||||
if (ret<0)
|
||||
return(-1);
|
||||
|
||||
if (ret==1)
|
||||
return(0);
|
||||
|
||||
ret = atol(para);
|
||||
|
||||
if (ret==0)
|
||||
return(-1);
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
long int hextoi_my(char *para) {
|
||||
long int ret = all_zero_in_string(para);
|
||||
|
||||
if (ret<0)
|
||||
return(-1);
|
||||
|
||||
if (ret==1)
|
||||
return(0);
|
||||
|
||||
ret = strtoul(para, NULL, 16);
|
||||
|
||||
if (ret==0)
|
||||
return(-1);
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
// parameter_string format:
|
||||
// write 987 to hardware register 3: wh3d987 (w--write; h--hardware; 3 --register idx; d--decimal; 987--value)
|
||||
// write 0x3db to software register 19: ws19h3db (w--write; s--software; 19--register idx; h--hex; 3db--value 0x3db)
|
||||
// read software register 23: rs23 (r-- read; s--software; 23--register idx)
|
||||
// get csi and equalizer output: g4 (g-- get; 4--every 4*100ms; no/wrong input means default 100ms)
|
||||
int parse_para_string(char *para, int *action_flag, int *reg_type, int *reg_idx, unsigned int *reg_val, int *interval_100ms) {
|
||||
int i, para_string_len, num_char_reg_idx, num_char_reg_val, hex_flag;
|
||||
|
||||
para_string_len = strlen(para);
|
||||
|
||||
if (para_string_len == 0 || para_string_len>MAX_PARA_STRING_LEN) {
|
||||
printf("Parameter string is too short/long!\n");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
// process the csi/equalizer get command
|
||||
if ( para[0] == 'g'){// || para[0] == 'G' ) {
|
||||
(*action_flag) = ACTION_SIDE_INFO_GET;
|
||||
|
||||
if (para_string_len == 1) { // no explict input
|
||||
(*interval_100ms) = 1;
|
||||
printf("The default 1*100ms side info getting period is taken!\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
// there is something input
|
||||
(*interval_100ms) = atoi_my(para+1);
|
||||
if ( (*interval_100ms)<0 ) { // for invalid input, we set it to the default 100ms = 1*100ms;
|
||||
(*interval_100ms) = 1;
|
||||
printf("Invalid side info getting period!\n");
|
||||
printf("The default 1*100ms side info getting period is taken!\n");
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (para_string_len == 2) {// this is invalid, for read and write, the length should be > 2
|
||||
printf("Lack of input (register index/value) for read/write action\n");
|
||||
return(-2);
|
||||
}
|
||||
|
||||
// process the register read command
|
||||
if ( para[0] == 'r'){// || para[0] == 'R' ) {
|
||||
(*action_flag) = ACTION_REG_READ;
|
||||
|
||||
if ( para[1] == 'h')// || para[1] == 'H' )
|
||||
(*reg_type) = REG_TYPE_HARDWARE;
|
||||
else if ( para[1] == 's')// || para[1] == 'S' )
|
||||
(*reg_type) = REG_TYPE_SOFTWARE;
|
||||
else {
|
||||
(*reg_type) = REG_TYPE_INVALID;
|
||||
printf("Invalid register type (s/h is expected)!\n");
|
||||
return(-3);
|
||||
}
|
||||
|
||||
(*reg_idx) = atoi_my(para+2);
|
||||
if ( (*reg_idx)<0 || (*reg_idx)>31) {
|
||||
printf("Invalid register index (should be 0~31)!\n");
|
||||
return(-4);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (para_string_len < 5) { // this is invalid, for write, the length should be >= 5. example wh3d9
|
||||
printf("Lack of input (register value/etc) for write action\n");
|
||||
return(-5);
|
||||
}
|
||||
|
||||
// process the register write command
|
||||
if ( para[0] == 'w'){// || para[0] == 'W' ) {
|
||||
(*action_flag) = ACTION_REG_WRITE;
|
||||
|
||||
if ( para[1] == 'h')// || para[1] == 'H' )
|
||||
(*reg_type) = REG_TYPE_HARDWARE;
|
||||
else if ( para[1] == 's')// || para[1] == 'S' )
|
||||
(*reg_type) = REG_TYPE_SOFTWARE;
|
||||
else {
|
||||
(*reg_type) = REG_TYPE_INVALID;
|
||||
printf("Invalid register type (s/h is expected)!\n");
|
||||
return(-6);
|
||||
}
|
||||
|
||||
num_char_reg_idx = take_reg_idx_string_for_write(para+2);
|
||||
if ( num_char_reg_idx<0 ) {
|
||||
printf("Invalid register index input!\n");
|
||||
return(-7);
|
||||
}
|
||||
|
||||
// if ((num_char_reg_idx+2)==para_string_len) //consume all string already
|
||||
// return(-8);
|
||||
|
||||
(*reg_idx) = atoi_my(tmp_str);
|
||||
if ( (*reg_idx)<0 || (*reg_idx)>31 ) {
|
||||
printf("Invalid register index (should be 0~31)!\n");
|
||||
return(-9);
|
||||
}
|
||||
|
||||
if (para[2+num_char_reg_idx] == 'd')// || para[2+num_char_reg_idx] == 'D')
|
||||
hex_flag=0;
|
||||
else if (para[2+num_char_reg_idx] == 'h')// || para[2+num_char_reg_idx] == 'H')
|
||||
hex_flag=1;
|
||||
else {
|
||||
printf("Invalid hex/decimal flag (d/h is expected)!\n");
|
||||
return(-10);
|
||||
}
|
||||
|
||||
num_char_reg_val = take_reg_val_string_for_write(para+2+num_char_reg_idx+1);
|
||||
if ( num_char_reg_val<0 ) {
|
||||
printf("Invalid register value input!\n");
|
||||
return(-11);
|
||||
}
|
||||
|
||||
if (hex_flag==0) {
|
||||
(*reg_val) = atoi_my(tmp_str);
|
||||
if ( (*reg_val)<0 ) {
|
||||
printf("Invalid register value input of decimal number!\n");
|
||||
return(-12);
|
||||
}
|
||||
} else {
|
||||
(*reg_val) = hextoi_my(tmp_str);
|
||||
// printf("%u %s\n", (*reg_val), tmp_str);
|
||||
if ( (*reg_val)<0 ) {
|
||||
printf("Invalid register value input of hex number!\n");
|
||||
return(-13);
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
return(-14);
|
||||
}
|
||||
|
||||
void print_usage(void) {
|
||||
printf("Usage: side_ch_ctl parameter_string\n");
|
||||
printf("Example:\n");
|
||||
printf("write 987 to hardware register 3: wh3d987 (w--write; h--hardware; 3 --register idx; d--decimal; 987--value)\n");
|
||||
printf("write 0x3db to software register 19: ws19h3db (w--write; s--software; 19--register idx; h--hex; 3db--value 0x3db)\n");
|
||||
printf(" read software register 23: rs23 (r-- read; s--software; 23--register idx)\n");
|
||||
printf(" get csi and equalizer output: g2 (g-- get; 4--every 4*100ms; no/wrong input means default 100ms)\n");
|
||||
}
|
||||
|
||||
volatile bool do_exit = false;
|
||||
|
||||
void sigint_callback_handler(int signum)
|
||||
{
|
||||
fprintf(stdout, "Caught signal %d\n", signum);
|
||||
do_exit = true;
|
||||
}
|
||||
|
||||
int main(const int argc, char * const argv[])
|
||||
{
|
||||
int action_flag, reg_type, reg_idx, interval_100ms, s, side_info_size, socket_ok = 1, loop_count=0, side_info_count=0;
|
||||
unsigned int reg_val, *cmd_buf;
|
||||
unsigned short port;
|
||||
struct sockaddr_in server;
|
||||
int ret = 0;
|
||||
|
||||
if (argc!=2) {
|
||||
printf("Wrong input!\n");
|
||||
print_usage();
|
||||
return(ret);
|
||||
}
|
||||
|
||||
ret = parse_para_string(argv[1], &action_flag, ®_type, ®_idx, ®_val, &interval_100ms);
|
||||
printf("parse: ret %d\n", ret);
|
||||
printf(" tx: action_flag %d reg_type %d reg_idx %d reg_val %u interval_100ms %d\n", action_flag, reg_type, reg_idx, reg_val, interval_100ms);
|
||||
if (ret<0) {
|
||||
printf("Wrong input!\n");
|
||||
print_usage();
|
||||
return(ret);
|
||||
}
|
||||
|
||||
// if (signal(SIGINT, &sigint_callback_handler)==SIG_ERR ||
|
||||
// signal(SIGILL, &sigint_callback_handler)==SIG_ERR ||
|
||||
// signal(SIGFPE, &sigint_callback_handler)==SIG_ERR ||
|
||||
// signal(SIGSEGV, &sigint_callback_handler)==SIG_ERR ||
|
||||
// signal(SIGTERM, &sigint_callback_handler)==SIG_ERR ||
|
||||
// signal(SIGABRT, &sigint_callback_handler)==SIG_ERR) {
|
||||
if (signal(SIGINT, &sigint_callback_handler)==SIG_ERR) {
|
||||
printf("SIG_ERR!\n");
|
||||
return(ret);
|
||||
}
|
||||
|
||||
sock_fd=socket(PF_NETLINK, SOCK_RAW, NETLINK_USERSOCK);
|
||||
if(sock_fd<0) {
|
||||
printf("sock_fd %d\n", sock_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&src_addr, 0, sizeof(src_addr));
|
||||
src_addr.nl_family = AF_NETLINK;
|
||||
src_addr.nl_pid = getpid(); /* self pid */
|
||||
|
||||
bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));
|
||||
|
||||
memset(&dest_addr, 0, sizeof(dest_addr));
|
||||
memset(&dest_addr, 0, sizeof(dest_addr));
|
||||
dest_addr.nl_family = AF_NETLINK;
|
||||
dest_addr.nl_pid = 0; /* For Linux Kernel */
|
||||
dest_addr.nl_groups = 0; /* unicast */
|
||||
|
||||
nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
|
||||
// memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
|
||||
|
||||
// nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
|
||||
|
||||
// strcpy(NLMSG_DATA(nlh), "Hello");
|
||||
|
||||
// udp socket setup
|
||||
port = htons(4000); // port 4000 at remote server
|
||||
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
|
||||
printf("socket() error! Will not send info to remote.\n");
|
||||
socket_ok = 0;
|
||||
}
|
||||
server.sin_family = AF_INET; /* Internet Domain */
|
||||
server.sin_port = port; /* Server Port */
|
||||
server.sin_addr.s_addr = inet_addr("192.168.10.1"); /* Server's Address */
|
||||
|
||||
while(do_exit==false) {
|
||||
nlh->nlmsg_len = NLMSG_SPACE(4*4);
|
||||
nlh->nlmsg_pid = getpid();
|
||||
nlh->nlmsg_flags = 0;
|
||||
|
||||
cmd_buf = (unsigned int*)NLMSG_DATA(nlh);
|
||||
cmd_buf[0] = action_flag;
|
||||
cmd_buf[1] = reg_type;
|
||||
cmd_buf[2] = reg_idx;
|
||||
cmd_buf[3] = reg_val;
|
||||
|
||||
iov.iov_base = (void *)nlh;
|
||||
iov.iov_len = nlh->nlmsg_len;
|
||||
msg.msg_name = (void *)&dest_addr;
|
||||
msg.msg_namelen = sizeof(dest_addr);
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
// printf("Sending message to kernel\n");
|
||||
sendmsg(sock_fd,&msg,0);
|
||||
// printf("Waiting for message from kernel\n");
|
||||
|
||||
nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
|
||||
iov.iov_len = nlh->nlmsg_len;
|
||||
/* Read message from kernel */
|
||||
recvmsg(sock_fd, &msg, 0);
|
||||
// printf("Received message payload: %s\n", (char *)NLMSG_DATA(nlh));
|
||||
|
||||
side_info_size = nlh->nlmsg_len-NLMSG_HDRLEN;
|
||||
// printf("%d %d %d %d %d %d %d %d\n", cmd_buf[0], cmd_buf[1], cmd_buf[2], cmd_buf[3], cmd_buf[4], cmd_buf[5], cmd_buf[6], cmd_buf[7]);
|
||||
|
||||
if (action_flag!=ACTION_SIDE_INFO_GET) {
|
||||
printf(" rx: size %d val %d 0x%08x\n", side_info_size, cmd_buf[0], cmd_buf[0]);
|
||||
break;
|
||||
}
|
||||
|
||||
if (socket_ok && (side_info_size >= ((CSI_LEN+0*EQUALIZER_LEN+HEADER_LEN)*8)))
|
||||
if (sendto(s, cmd_buf, side_info_size, 0, (struct sockaddr *)&server, sizeof(server)) < 0)
|
||||
printf("sendto() error!\n");
|
||||
|
||||
side_info_count = side_info_count + (side_info_size>4);
|
||||
loop_count++;
|
||||
if ((loop_count%64) == 0)
|
||||
printf("loop %d side info count %d\n", loop_count, side_info_count);
|
||||
|
||||
usleep(interval_100ms*100*1000);
|
||||
}
|
||||
|
||||
close(s);
|
||||
close(sock_fd);
|
||||
return(ret);
|
||||
}
|
161
user_space/side_ch_ctl_src/side_info_display.py
Executable file
161
user_space/side_ch_ctl_src/side_info_display.py
Executable file
@ -0,0 +1,161 @@
|
||||
#
|
||||
# openwifi side info receive and display program
|
||||
# Xianjun jiao. putaoshu@msn.com; xianjun.jiao@imec.be
|
||||
#
|
||||
import os
|
||||
import sys
|
||||
import socket
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
def display_side_info(freq_offset, csi, equalizer, CSI_LEN, EQUALIZER_LEN):
|
||||
if not hasattr(display_side_info, 'freq_offset_store'):
|
||||
display_side_info.freq_offset_store = np.zeros((256,))
|
||||
|
||||
len_freq_offset = len(freq_offset)
|
||||
display_side_info.freq_offset_store[:(256-len_freq_offset)] = display_side_info.freq_offset_store[len_freq_offset:]
|
||||
display_side_info.freq_offset_store[(256-len_freq_offset):] = freq_offset
|
||||
|
||||
fig_freq_offset = plt.figure(0)
|
||||
fig_freq_offset.clf()
|
||||
plt.xlabel("packet idx")
|
||||
plt.ylabel("Hz")
|
||||
plt.title("freq offset")
|
||||
plt.plot(display_side_info.freq_offset_store)
|
||||
fig_freq_offset.show()
|
||||
plt.pause(0.0001)
|
||||
|
||||
good_row_idx = 0
|
||||
if ( len(equalizer)==0 ):
|
||||
csi_for_plot = csi.T
|
||||
else:
|
||||
equalizer[equalizer == 32767+32767*1j] = 0
|
||||
num_row_equalizer, num_col_equalizer = equalizer.shape
|
||||
equalizer_for_plot = np.zeros((num_row_equalizer, num_col_equalizer)) + 1j*np.zeros((num_row_equalizer, num_col_equalizer))
|
||||
|
||||
num_row_csi, num_col_csi = csi.shape
|
||||
csi_for_plot = np.zeros((num_row_csi, num_col_csi)) + 1j*np.zeros((num_row_csi, num_col_csi))
|
||||
|
||||
# only take out the good equalizer result, when output > 2000, it is not good
|
||||
for i in range(num_row_equalizer):
|
||||
if (not (np.any(abs(equalizer[i,:].real)>2000) or np.any(abs(equalizer[i,:].imag)>2000)) ):
|
||||
equalizer_for_plot[good_row_idx,:] = equalizer[i,:]
|
||||
csi_for_plot[good_row_idx,:] = csi[i,:]
|
||||
good_row_idx = good_row_idx + 1
|
||||
|
||||
csi_for_plot = csi_for_plot[0:good_row_idx,:]
|
||||
equalizer_for_plot = equalizer_for_plot[0:good_row_idx,:]
|
||||
csi_for_plot = csi_for_plot.T
|
||||
equalizer_for_plot = equalizer_for_plot.T
|
||||
|
||||
if ( (len(equalizer)==0) or ((len(equalizer)>0)and(good_row_idx>0)) ):
|
||||
fig_csi = plt.figure(1)
|
||||
fig_csi.clf()
|
||||
ax_abs_csi = fig_csi.add_subplot(211)
|
||||
ax_abs_csi.set_xlabel("subcarrier idx")
|
||||
ax_abs_csi.set_ylabel("abs")
|
||||
ax_abs_csi.set_title("CSI")
|
||||
plt.plot(np.abs(csi_for_plot))
|
||||
ax_phase_csi = fig_csi.add_subplot(212)
|
||||
ax_phase_csi.set_xlabel("subcarrier idx")
|
||||
ax_phase_csi.set_ylabel("phase")
|
||||
plt.plot(np.angle(csi_for_plot))
|
||||
fig_csi.show()
|
||||
plt.pause(0.0001)
|
||||
|
||||
if ( (len(equalizer)>0) and (good_row_idx>0) ):
|
||||
fig_equalizer = plt.figure(2)
|
||||
fig_equalizer.clf()
|
||||
plt.xlabel("I")
|
||||
plt.ylabel("Q")
|
||||
plt.title("equalizer")
|
||||
plt.scatter(equalizer_for_plot.real, equalizer_for_plot.imag)
|
||||
fig_freq_offset.show()
|
||||
plt.pause(0.0001)
|
||||
|
||||
def parse_side_info(side_info, num_eq, CSI_LEN, EQUALIZER_LEN, HEADER_LEN):
|
||||
# print(len(side_info), num_eq, CSI_LEN, EQUALIZER_LEN, HEADER_LEN)
|
||||
CSI_LEN_HALF = round(CSI_LEN/2)
|
||||
num_dma_symbol_per_trans = HEADER_LEN + CSI_LEN + num_eq*EQUALIZER_LEN
|
||||
num_int16_per_trans = num_dma_symbol_per_trans*4 # 64bit per dma symbol
|
||||
num_trans = round(len(side_info)/num_int16_per_trans)
|
||||
# print(len(side_info), side_info.dtype, num_trans)
|
||||
side_info = side_info.reshape([num_trans, num_int16_per_trans])
|
||||
|
||||
timestamp = side_info[:,0] + pow(2,16)*side_info[:,1] + pow(2,32)*side_info[:,2] + pow(2,48)*side_info[:,3]
|
||||
|
||||
freq_offset = (20e6*side_info[:,4]/512)/(2*3.14159265358979323846)
|
||||
|
||||
csi = np.zeros((num_trans, CSI_LEN), dtype='int16')
|
||||
csi = csi + csi*1j
|
||||
|
||||
equalizer = np.zeros((0,0), dtype='int16')
|
||||
if num_eq>0:
|
||||
equalizer = np.zeros((num_trans, num_eq*EQUALIZER_LEN), dtype='int16')
|
||||
equalizer = equalizer + equalizer*1j
|
||||
|
||||
for i in range(num_trans):
|
||||
tmp_vec_i = side_info[i,8:(num_int16_per_trans-1):4]
|
||||
tmp_vec_q = side_info[i,9:(num_int16_per_trans-1):4]
|
||||
tmp_vec = tmp_vec_i + tmp_vec_q*1j
|
||||
# csi[i,:] = tmp_vec[0:CSI_LEN]
|
||||
csi[i,:CSI_LEN_HALF] = tmp_vec[CSI_LEN_HALF:CSI_LEN]
|
||||
csi[i,CSI_LEN_HALF:] = tmp_vec[0:CSI_LEN_HALF]
|
||||
if num_eq>0:
|
||||
equalizer[i,:] = tmp_vec[CSI_LEN:(CSI_LEN+num_eq*EQUALIZER_LEN)]
|
||||
# print(i, len(tmp_vec), len(tmp_vec[0:CSI_LEN]), len(tmp_vec[CSI_LEN:(CSI_LEN+num_eq*EQUALIZER_LEN)]))
|
||||
|
||||
return timestamp, freq_offset, csi, equalizer
|
||||
|
||||
UDP_IP = "192.168.10.1" #Local IP to listen
|
||||
UDP_PORT = 4000 #Local port to listen
|
||||
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP
|
||||
sock.bind((UDP_IP, UDP_PORT))
|
||||
|
||||
# align with side_ch_control.v and all related user space, remote files
|
||||
CSI_LEN = 56 # length of single CSI
|
||||
EQUALIZER_LEN = (56-4) # for non HT, four {32767,32767} will be padded to achieve 52 (non HT should have 48)
|
||||
HEADER_LEN = 2 # timestamp and frequency offset
|
||||
|
||||
if len(sys.argv)<2:
|
||||
print("Assume num_eq = 8!")
|
||||
num_eq = 8
|
||||
else:
|
||||
num_eq = int(sys.argv[1])
|
||||
print(num_eq)
|
||||
# print(type(num_eq))
|
||||
|
||||
num_dma_symbol_per_trans = HEADER_LEN + CSI_LEN + num_eq*EQUALIZER_LEN
|
||||
num_byte_per_trans = 8*num_dma_symbol_per_trans
|
||||
|
||||
if os.path.exists("side_info.txt"):
|
||||
os.remove("side_info.txt")
|
||||
side_info_fd=open('side_info.txt','a')
|
||||
|
||||
while True:
|
||||
try:
|
||||
data, addr = sock.recvfrom(32768) # buffer size
|
||||
# print(addr)
|
||||
print(len(data), num_byte_per_trans)
|
||||
test_residual = len(data)%num_byte_per_trans
|
||||
if (test_residual != 0):
|
||||
print("Abnormal length")
|
||||
|
||||
side_info = np.frombuffer(data, dtype='int16')
|
||||
np.savetxt(side_info_fd, side_info)
|
||||
|
||||
timestamp, freq_offset, csi, equalizer = parse_side_info(side_info, num_eq, CSI_LEN, EQUALIZER_LEN, HEADER_LEN)
|
||||
print(timestamp)
|
||||
# print(freq_offset)
|
||||
# print(csi[0,0:10])
|
||||
# print(equalizer[0,0:10])
|
||||
display_side_info(freq_offset, csi, equalizer, CSI_LEN, EQUALIZER_LEN)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print('User quit')
|
||||
break
|
||||
|
||||
print('close()')
|
||||
side_info_fd.close()
|
||||
sock.close()
|
40
user_space/side_ch_ctl_src/test_side_info_file_display.m
Normal file
40
user_space/side_ch_ctl_src/test_side_info_file_display.m
Normal file
@ -0,0 +1,40 @@
|
||||
% Xianjun Jiao. xianjun.jiao@imec.be; putaoshu@msn.com
|
||||
|
||||
clear all;
|
||||
close all;
|
||||
|
||||
num_eq = 8;
|
||||
|
||||
a = load('side_info.txt');
|
||||
b = reshape(a, [4, length(a)/4])';
|
||||
num_data_in_each_side_info = 2+56+num_eq*52;
|
||||
num_side_info = size(b,1)/num_data_in_each_side_info;
|
||||
|
||||
side_info = zeros(num_data_in_each_side_info, num_side_info);
|
||||
timestamp = zeros(1, num_side_info);
|
||||
freq_offset = zeros(1, num_side_info);
|
||||
csi = zeros(56, num_side_info);
|
||||
equalizer = zeros(num_eq*52, num_side_info);
|
||||
for i=1:num_side_info
|
||||
sp = (i-1)*num_data_in_each_side_info + 1;
|
||||
ep = i*num_data_in_each_side_info;
|
||||
timestamp(i) = b(sp,1) + (2^16)*b(sp,2) + (2^32)*b(sp,3) + (2^48)*b(sp,4);
|
||||
freq_offset(i) = (20e6*b(sp+1,1)/512)/(2*pi);
|
||||
side_info(:,i) = b(sp:ep,1) + 1i.*b(sp:ep,2);
|
||||
csi(:,i) = side_info(3:58,i);
|
||||
equalizer(:,i) = side_info(59:end,i);
|
||||
end
|
||||
|
||||
csi = [csi(29:end,:); csi(1:28,:)];
|
||||
equalizer = equalizer(:);
|
||||
equalizer(equalizer == 32767+1i*32767) = NaN;
|
||||
|
||||
subplot(2,1,1); plot(abs(csi)); title('CSI'); ylabel('abs'); grid on;
|
||||
subplot(2,1,2); plot(angle(csi)); ylabel('phase'); xlabel('subcarrier'); grid on;
|
||||
|
||||
if ~isempty(equalizer)
|
||||
scatterplot(equalizer); grid on;
|
||||
end
|
||||
|
||||
figure; plot(timestamp); title('time stamp (TSF value)'); ylabel('us'); xlabel('packet'); grid on;
|
||||
figure; plot(freq_offset); title('freq offset (Hz)'); ylabel('Hz'); xlabel('packet'); grid on;
|
@ -120,12 +120,14 @@ sudo wget -P $SDCARD_DIR/rootfs/root/openwifi/webserver/ https://users.ugent.be/
|
||||
|
||||
# build openwifi driver
|
||||
$OPENWIFI_DIR/driver/make_all.sh $OPENWIFI_DIR $XILINX_DIR 32
|
||||
$OPENWIFI_DIR/driver/side_ch/make_driver.sh $OPENWIFI_DIR $XILINX_DIR 32
|
||||
# Copy files to SD card rootfs partition
|
||||
sudo mkdir $SDCARD_DIR/rootfs/root/openwifi/drv32
|
||||
sudo find $OPENWIFI_DIR/driver -name \*.ko -exec cp {} $SDCARD_DIR/rootfs/root/openwifi/drv32 \;
|
||||
|
||||
# build openwifi driver
|
||||
$OPENWIFI_DIR/driver/make_all.sh $OPENWIFI_DIR $XILINX_DIR 64
|
||||
$OPENWIFI_DIR/driver/side_ch/make_driver.sh $OPENWIFI_DIR $XILINX_DIR 64
|
||||
# Copy files to SD card rootfs partition
|
||||
sudo mkdir $SDCARD_DIR/rootfs/root/openwifi/drv64
|
||||
sudo find $OPENWIFI_DIR/driver -name \*.ko -exec cp {} $SDCARD_DIR/rootfs/root/openwifi/drv64 \;
|
||||
|
Loading…
Reference in New Issue
Block a user