122dd0cc4SXianjun Jiao# 222dd0cc4SXianjun Jiao# openwifi side info receive and display program 322dd0cc4SXianjun Jiao# Xianjun jiao. [email protected]; [email protected] 422dd0cc4SXianjun Jiao# 522dd0cc4SXianjun Jiaoimport os 622dd0cc4SXianjun Jiaoimport sys 722dd0cc4SXianjun Jiaoimport socket 822dd0cc4SXianjun Jiaoimport numpy as np 922dd0cc4SXianjun Jiaoimport matplotlib.pyplot as plt 1022dd0cc4SXianjun Jiao 118cfbbc8eSXianjun Jiaodef display_side_info(freq_offset, csi, equalizer, waterfall_flag, CSI_LEN, EQUALIZER_LEN): 1222dd0cc4SXianjun Jiao if not hasattr(display_side_info, 'freq_offset_store'): 1322dd0cc4SXianjun Jiao display_side_info.freq_offset_store = np.zeros((256,)) 1422dd0cc4SXianjun Jiao 1522dd0cc4SXianjun Jiao len_freq_offset = len(freq_offset) 1622dd0cc4SXianjun Jiao display_side_info.freq_offset_store[:(256-len_freq_offset)] = display_side_info.freq_offset_store[len_freq_offset:] 1722dd0cc4SXianjun Jiao display_side_info.freq_offset_store[(256-len_freq_offset):] = freq_offset 1822dd0cc4SXianjun Jiao 1922dd0cc4SXianjun Jiao fig_freq_offset = plt.figure(0) 2022dd0cc4SXianjun Jiao fig_freq_offset.clf() 2122dd0cc4SXianjun Jiao plt.xlabel("packet idx") 2222dd0cc4SXianjun Jiao plt.ylabel("Hz") 2322dd0cc4SXianjun Jiao plt.title("freq offset") 2422dd0cc4SXianjun Jiao plt.plot(display_side_info.freq_offset_store) 259fde3bffSthavinga fig_freq_offset.canvas.flush_events() 2622dd0cc4SXianjun Jiao 2722dd0cc4SXianjun Jiao good_row_idx = 0 2822dd0cc4SXianjun Jiao if ( len(equalizer)==0 ): 2922dd0cc4SXianjun Jiao csi_for_plot = csi.T 3022dd0cc4SXianjun Jiao else: 3122dd0cc4SXianjun Jiao equalizer[equalizer == 32767+32767*1j] = 0 3222dd0cc4SXianjun Jiao num_row_equalizer, num_col_equalizer = equalizer.shape 3322dd0cc4SXianjun Jiao equalizer_for_plot = np.zeros((num_row_equalizer, num_col_equalizer)) + 1j*np.zeros((num_row_equalizer, num_col_equalizer)) 3422dd0cc4SXianjun Jiao 3522dd0cc4SXianjun Jiao num_row_csi, num_col_csi = csi.shape 3622dd0cc4SXianjun Jiao csi_for_plot = np.zeros((num_row_csi, num_col_csi)) + 1j*np.zeros((num_row_csi, num_col_csi)) 3722dd0cc4SXianjun Jiao 3822dd0cc4SXianjun Jiao # only take out the good equalizer result, when output > 2000, it is not good 3922dd0cc4SXianjun Jiao for i in range(num_row_equalizer): 4022dd0cc4SXianjun Jiao if (not (np.any(abs(equalizer[i,:].real)>2000) or np.any(abs(equalizer[i,:].imag)>2000)) ): 4122dd0cc4SXianjun Jiao equalizer_for_plot[good_row_idx,:] = equalizer[i,:] 4222dd0cc4SXianjun Jiao csi_for_plot[good_row_idx,:] = csi[i,:] 4322dd0cc4SXianjun Jiao good_row_idx = good_row_idx + 1 4422dd0cc4SXianjun Jiao 4522dd0cc4SXianjun Jiao csi_for_plot = csi_for_plot[0:good_row_idx,:] 4622dd0cc4SXianjun Jiao equalizer_for_plot = equalizer_for_plot[0:good_row_idx,:] 4722dd0cc4SXianjun Jiao csi_for_plot = csi_for_plot.T 4822dd0cc4SXianjun Jiao equalizer_for_plot = equalizer_for_plot.T 4922dd0cc4SXianjun Jiao 5022dd0cc4SXianjun Jiao if ( (len(equalizer)==0) or ((len(equalizer)>0)and(good_row_idx>0)) ): 5122dd0cc4SXianjun Jiao fig_csi = plt.figure(1) 5222dd0cc4SXianjun Jiao fig_csi.clf() 538cfbbc8eSXianjun Jiao # if waterfall_flag == 0: 5422dd0cc4SXianjun Jiao ax_abs_csi = fig_csi.add_subplot(211) 5522dd0cc4SXianjun Jiao ax_abs_csi.set_xlabel("subcarrier idx") 5622dd0cc4SXianjun Jiao ax_abs_csi.set_ylabel("abs") 5722dd0cc4SXianjun Jiao ax_abs_csi.set_title("CSI") 5822dd0cc4SXianjun Jiao plt.plot(np.abs(csi_for_plot)) 5922dd0cc4SXianjun Jiao ax_phase_csi = fig_csi.add_subplot(212) 6022dd0cc4SXianjun Jiao ax_phase_csi.set_xlabel("subcarrier idx") 6122dd0cc4SXianjun Jiao ax_phase_csi.set_ylabel("phase") 6222dd0cc4SXianjun Jiao plt.plot(np.angle(csi_for_plot)) 639fde3bffSthavinga fig_csi.canvas.flush_events() 6422dd0cc4SXianjun Jiao 658cfbbc8eSXianjun Jiao # else: 668cfbbc8eSXianjun Jiao 678cfbbc8eSXianjun Jiao if waterfall_flag == 1: 688cfbbc8eSXianjun Jiao # print(np.abs(display_side_info.csi_mat_for_waterfall)) 698cfbbc8eSXianjun Jiao display_side_info.csi_mat_for_waterfall = np.roll(display_side_info.csi_mat_for_waterfall, 1, axis=0) 708cfbbc8eSXianjun Jiao # print(np.abs(display_side_info.csi_mat_for_waterfall)) 718cfbbc8eSXianjun Jiao 728cfbbc8eSXianjun Jiao display_side_info.csi_mat_for_waterfall[0,:] = csi[0,:] 738cfbbc8eSXianjun Jiao 748cfbbc8eSXianjun Jiao fig_waterfall = plt.figure(3) 758cfbbc8eSXianjun Jiao fig_waterfall.clf() 768cfbbc8eSXianjun Jiao 778cfbbc8eSXianjun Jiao ax_abs_csi_waterfall = fig_waterfall.add_subplot(121) 788cfbbc8eSXianjun Jiao ax_abs_csi_waterfall.set_title('CSI amplitude') 798cfbbc8eSXianjun Jiao ax_abs_csi_waterfall.set_xlabel("subcarrier idx") 808cfbbc8eSXianjun Jiao ax_abs_csi_waterfall.set_ylabel("time") 818cfbbc8eSXianjun Jiao # ax_abs_csi_waterfall_shw = ax_abs_csi_waterfall.imshow(np.abs(display_side_info.csi_mat_for_waterfall), vmin=200, vmax=500) 828cfbbc8eSXianjun Jiao ax_abs_csi_waterfall_shw = ax_abs_csi_waterfall.imshow(np.abs(display_side_info.csi_mat_for_waterfall)) 838cfbbc8eSXianjun Jiao plt.colorbar(ax_abs_csi_waterfall_shw) 848cfbbc8eSXianjun Jiao 858cfbbc8eSXianjun Jiao ax_phase_csi_waterfall = fig_waterfall.add_subplot(122) 868cfbbc8eSXianjun Jiao ax_phase_csi_waterfall.set_title('CSI phase') 878cfbbc8eSXianjun Jiao ax_phase_csi_waterfall.set_xlabel("subcarrier idx") 888cfbbc8eSXianjun Jiao ax_phase_csi_waterfall.set_ylabel("time") 898cfbbc8eSXianjun Jiao # ax_phase_csi_waterfall_shw = ax_phase_csi_waterfall.imshow(np.angle(display_side_info.csi_mat_for_waterfall), vmin=-3.14, vmax=3.14) 908cfbbc8eSXianjun Jiao ax_phase_csi_waterfall_shw = ax_phase_csi_waterfall.imshow(np.angle(display_side_info.csi_mat_for_waterfall)) 918cfbbc8eSXianjun Jiao plt.colorbar(ax_phase_csi_waterfall_shw) 928cfbbc8eSXianjun Jiao 938cfbbc8eSXianjun Jiao fig_waterfall.canvas.flush_events() 948cfbbc8eSXianjun Jiao 9522dd0cc4SXianjun Jiao if ( (len(equalizer)>0) and (good_row_idx>0) ): 9622dd0cc4SXianjun Jiao fig_equalizer = plt.figure(2) 9722dd0cc4SXianjun Jiao fig_equalizer.clf() 9822dd0cc4SXianjun Jiao plt.xlabel("I") 9922dd0cc4SXianjun Jiao plt.ylabel("Q") 10022dd0cc4SXianjun Jiao plt.title("equalizer") 10122dd0cc4SXianjun Jiao plt.scatter(equalizer_for_plot.real, equalizer_for_plot.imag) 1029fde3bffSthavinga fig_freq_offset.canvas.flush_events() 10322dd0cc4SXianjun Jiao 10422dd0cc4SXianjun Jiaodef parse_side_info(side_info, num_eq, CSI_LEN, EQUALIZER_LEN, HEADER_LEN): 10522dd0cc4SXianjun Jiao # print(len(side_info), num_eq, CSI_LEN, EQUALIZER_LEN, HEADER_LEN) 10622dd0cc4SXianjun Jiao CSI_LEN_HALF = round(CSI_LEN/2) 10722dd0cc4SXianjun Jiao num_dma_symbol_per_trans = HEADER_LEN + CSI_LEN + num_eq*EQUALIZER_LEN 10822dd0cc4SXianjun Jiao num_int16_per_trans = num_dma_symbol_per_trans*4 # 64bit per dma symbol 10922dd0cc4SXianjun Jiao num_trans = round(len(side_info)/num_int16_per_trans) 11022dd0cc4SXianjun Jiao # print(len(side_info), side_info.dtype, num_trans) 11122dd0cc4SXianjun Jiao side_info = side_info.reshape([num_trans, num_int16_per_trans]) 11222dd0cc4SXianjun Jiao 11322dd0cc4SXianjun Jiao timestamp = side_info[:,0] + pow(2,16)*side_info[:,1] + pow(2,32)*side_info[:,2] + pow(2,48)*side_info[:,3] 11422dd0cc4SXianjun Jiao 115*e556af35SXianjun Jiao freq_offset = (20e6*np.int16(side_info[:,4])/512)/(2*3.14159265358979323846) 11622dd0cc4SXianjun Jiao 11722dd0cc4SXianjun Jiao csi = np.zeros((num_trans, CSI_LEN), dtype='int16') 11822dd0cc4SXianjun Jiao csi = csi + csi*1j 11922dd0cc4SXianjun Jiao 12022dd0cc4SXianjun Jiao equalizer = np.zeros((0,0), dtype='int16') 12122dd0cc4SXianjun Jiao if num_eq>0: 12222dd0cc4SXianjun Jiao equalizer = np.zeros((num_trans, num_eq*EQUALIZER_LEN), dtype='int16') 12322dd0cc4SXianjun Jiao equalizer = equalizer + equalizer*1j 12422dd0cc4SXianjun Jiao 12522dd0cc4SXianjun Jiao for i in range(num_trans): 126*e556af35SXianjun Jiao tmp_vec_i = np.int16(side_info[i,8:(num_int16_per_trans-1):4]) 127*e556af35SXianjun Jiao tmp_vec_q = np.int16(side_info[i,9:(num_int16_per_trans-1):4]) 12822dd0cc4SXianjun Jiao tmp_vec = tmp_vec_i + tmp_vec_q*1j 12922dd0cc4SXianjun Jiao # csi[i,:] = tmp_vec[0:CSI_LEN] 13022dd0cc4SXianjun Jiao csi[i,:CSI_LEN_HALF] = tmp_vec[CSI_LEN_HALF:CSI_LEN] 13122dd0cc4SXianjun Jiao csi[i,CSI_LEN_HALF:] = tmp_vec[0:CSI_LEN_HALF] 13222dd0cc4SXianjun Jiao if num_eq>0: 13322dd0cc4SXianjun Jiao equalizer[i,:] = tmp_vec[CSI_LEN:(CSI_LEN+num_eq*EQUALIZER_LEN)] 13422dd0cc4SXianjun Jiao # print(i, len(tmp_vec), len(tmp_vec[0:CSI_LEN]), len(tmp_vec[CSI_LEN:(CSI_LEN+num_eq*EQUALIZER_LEN)])) 13522dd0cc4SXianjun Jiao 13622dd0cc4SXianjun Jiao return timestamp, freq_offset, csi, equalizer 13722dd0cc4SXianjun Jiao 13822dd0cc4SXianjun JiaoUDP_IP = "192.168.10.1" #Local IP to listen 13922dd0cc4SXianjun JiaoUDP_PORT = 4000 #Local port to listen 14022dd0cc4SXianjun Jiao 14122dd0cc4SXianjun Jiaosock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP 14222dd0cc4SXianjun Jiaosock.bind((UDP_IP, UDP_PORT)) 143a4eb2001SXianjun Jiaosock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 464) # for low latency. 464 is the minimum udp length in our case (CSI only) 14422dd0cc4SXianjun Jiao 14522dd0cc4SXianjun Jiao# align with side_ch_control.v and all related user space, remote files 146f71252c5SXianjun JiaoMAX_NUM_DMA_SYMBOL = 8192 14722dd0cc4SXianjun JiaoCSI_LEN = 56 # length of single CSI 14822dd0cc4SXianjun JiaoEQUALIZER_LEN = (56-4) # for non HT, four {32767,32767} will be padded to achieve 52 (non HT should have 48) 14922dd0cc4SXianjun JiaoHEADER_LEN = 2 # timestamp and frequency offset 15022dd0cc4SXianjun Jiao 15122dd0cc4SXianjun Jiaoif len(sys.argv)<2: 15222dd0cc4SXianjun Jiao print("Assume num_eq = 8!") 15322dd0cc4SXianjun Jiao num_eq = 8 15422dd0cc4SXianjun Jiaoelse: 15522dd0cc4SXianjun Jiao num_eq = int(sys.argv[1]) 15622dd0cc4SXianjun Jiao print(num_eq) 15722dd0cc4SXianjun Jiao # print(type(num_eq)) 15822dd0cc4SXianjun Jiao 1598cfbbc8eSXianjun Jiaowaterfall_flag = 0 1608cfbbc8eSXianjun Jiaoif len(sys.argv)>2: 1618cfbbc8eSXianjun Jiao print("Will plot CSI in waterfall!") 1628cfbbc8eSXianjun Jiao display_side_info.csi_mat_for_waterfall = np.zeros((64, CSI_LEN)) + 1j*np.zeros((64, CSI_LEN)) 1638cfbbc8eSXianjun Jiao waterfall_flag = 1 1648cfbbc8eSXianjun Jiao 16522dd0cc4SXianjun Jiaonum_dma_symbol_per_trans = HEADER_LEN + CSI_LEN + num_eq*EQUALIZER_LEN 16622dd0cc4SXianjun Jiaonum_byte_per_trans = 8*num_dma_symbol_per_trans 16722dd0cc4SXianjun Jiao 16822dd0cc4SXianjun Jiaoif os.path.exists("side_info.txt"): 16922dd0cc4SXianjun Jiao os.remove("side_info.txt") 17022dd0cc4SXianjun Jiaoside_info_fd=open('side_info.txt','a') 17122dd0cc4SXianjun Jiao 1729fde3bffSthavingaplt.ion() 1739fde3bffSthavinga 17422dd0cc4SXianjun Jiaowhile True: 17522dd0cc4SXianjun Jiao try: 176f71252c5SXianjun Jiao data, addr = sock.recvfrom(MAX_NUM_DMA_SYMBOL*8) # buffer size 17722dd0cc4SXianjun Jiao # print(addr) 1788cfbbc8eSXianjun Jiao # print(len(data), num_byte_per_trans) 17922dd0cc4SXianjun Jiao test_residual = len(data)%num_byte_per_trans 18022dd0cc4SXianjun Jiao if (test_residual != 0): 18122dd0cc4SXianjun Jiao print("Abnormal length") 18222dd0cc4SXianjun Jiao 183*e556af35SXianjun Jiao side_info = np.frombuffer(data, dtype='uint16') 18422dd0cc4SXianjun Jiao np.savetxt(side_info_fd, side_info) 18522dd0cc4SXianjun Jiao 18622dd0cc4SXianjun Jiao timestamp, freq_offset, csi, equalizer = parse_side_info(side_info, num_eq, CSI_LEN, EQUALIZER_LEN, HEADER_LEN) 1878cfbbc8eSXianjun Jiao # print(timestamp) 18822dd0cc4SXianjun Jiao # print(freq_offset) 18922dd0cc4SXianjun Jiao # print(csi[0,0:10]) 19022dd0cc4SXianjun Jiao # print(equalizer[0,0:10]) 1918cfbbc8eSXianjun Jiao display_side_info(freq_offset, csi, equalizer, waterfall_flag, CSI_LEN, EQUALIZER_LEN) 19222dd0cc4SXianjun Jiao 19322dd0cc4SXianjun Jiao except KeyboardInterrupt: 19422dd0cc4SXianjun Jiao print('User quit') 19522dd0cc4SXianjun Jiao break 19622dd0cc4SXianjun Jiao 19722dd0cc4SXianjun Jiaoprint('close()') 19822dd0cc4SXianjun Jiaoside_info_fd.close() 19922dd0cc4SXianjun Jiaosock.close() 200