1 | /** @file wlan_phy_util.c |
---|
2 | * @brief Physical Layer Utility |
---|
3 | * |
---|
4 | * This contains code for configuring low-level parameters in the PHY and hardware. |
---|
5 | * |
---|
6 | * @copyright Copyright 2013-2019, Mango Communications. All rights reserved. |
---|
7 | * Distributed under the Mango Communications Reference Design License |
---|
8 | * See LICENSE.txt included in the design archive or |
---|
9 | * at http://mangocomm.com/802.11/license |
---|
10 | * |
---|
11 | * This file is part of the Mango 802.11 Reference Design (https://mangocomm.com/802.11) |
---|
12 | */ |
---|
13 | /***************************** Include Files *********************************/ |
---|
14 | |
---|
15 | // Xilinx SDK includes |
---|
16 | #include "stdio.h" |
---|
17 | #include "stdarg.h" |
---|
18 | #include "xio.h" |
---|
19 | #include "string.h" |
---|
20 | #include "xparameters.h" |
---|
21 | |
---|
22 | // WLAN includes |
---|
23 | #include "wlan_platform_low.h" |
---|
24 | #include "wlan_platform_common.h" |
---|
25 | #include "wlan_mac_mailbox_util.h" |
---|
26 | #include "wlan_phy_util.h" |
---|
27 | #include "wlan_mac_low.h" |
---|
28 | #include "wlan_mac_common.h" |
---|
29 | #include "wlan_mac_pkt_buf_util.h" |
---|
30 | |
---|
31 | // LUT of number of ones in each byte (used to calculate PARITY in SIGNAL) |
---|
32 | const u8 ones_in_chars[256] = { |
---|
33 | 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, // 0x00 - 0x0F |
---|
34 | 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, // 0x10 - 0x1F |
---|
35 | 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, // 0x20 - 0x2F |
---|
36 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, // 0x30 - 0x3F |
---|
37 | 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, // 0x40 - 0x4F |
---|
38 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, // 0x50 - 0x5F |
---|
39 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, // 0x60 - 0x6F |
---|
40 | 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, // 0x70 - 0x7F |
---|
41 | 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, // 0x80 - 0x8F |
---|
42 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, // 0x90 - 0x9F |
---|
43 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, // 0xA0 - 0xAF |
---|
44 | 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, // 0xB0 - 0xBF |
---|
45 | 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, // 0xC0 - 0xCF |
---|
46 | 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, // 0xD0 - 0xDF |
---|
47 | 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, // 0xE0 - 0xEF |
---|
48 | 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8}; // 0xF0 - 0xFF |
---|
49 | |
---|
50 | |
---|
51 | // Common Platform Device Info |
---|
52 | extern platform_common_dev_info_t platform_common_dev_info; |
---|
53 | |
---|
54 | |
---|
55 | /*****************************************************************************/ |
---|
56 | /** |
---|
57 | * Calculates the PHY preamble (SIGNAL for 11a, L-SIG/HT-SIG for 11n) and writes |
---|
58 | * the preamble bytes to the specified packet buffer. The PHY preamble must be |
---|
59 | * written to the packet buffer for each transmission. |
---|
60 | * |
---|
61 | * @param pkt_buf - Packet buffer number |
---|
62 | * @param phy_mode - Sets waveform format; must be PHY_MODE_NON_HT (11a) or PHY_MODE_HTMF (11n) |
---|
63 | * @param mcs - MCS (modulation/coding scheme) index |
---|
64 | * @param length - Length of the packet being transmitted |
---|
65 | * |
---|
66 | * @return None |
---|
67 | * |
---|
68 | *****************************************************************************/ |
---|
69 | const u8 sig_rate_vals[8] = {0xB, 0xF, 0xA, 0xE, 0x9, 0xD, 0x8, 0xC}; |
---|
70 | |
---|
71 | void write_phy_preamble(u8 pkt_buf, u8 phy_mode, u8 mcs, u16 length) { |
---|
72 | |
---|
73 | u8* htsig_ptr; |
---|
74 | u16 lsig_length; |
---|
75 | u8* phy_hdr_ptr; |
---|
76 | |
---|
77 | phy_hdr_ptr = (u8*)(CALC_PKT_BUF_ADDR(platform_common_dev_info.tx_pkt_buf_baseaddr, pkt_buf) + PHY_TX_PKT_BUF_PHY_HDR_OFFSET); |
---|
78 | |
---|
79 | // RATE field values for SIGNAL/L-SIG in PHY preamble (IEEE 802.11-2012 18.3.4.2) |
---|
80 | // RATE field in SIGNAL/L-SIG is one of 8 4-bit values indicating modulation scheme and coding rate |
---|
81 | // For 11a (NONHT) transmissions we map mcs index to SIGNAL.RATE directly |
---|
82 | // For 11n (HTMF) transmissions the L-SIG.RATE field is always the lowest (BSPK 1/2) |
---|
83 | |
---|
84 | if((phy_mode & PHY_MODE_NONHT) == PHY_MODE_NONHT) { |
---|
85 | //11a mode - write SIGNAL (3 bytes) |
---|
86 | |
---|
87 | //Zero-out any stale header, also properly sets SERVICE and reserved bytes to 0 |
---|
88 | //Old: takes longer than necessary. We only really need the SERVICE bits 0. |
---|
89 | //bzero((u32*)phy_hdr_ptr, PHY_TX_PKT_BUF_PHY_HDR_SIZE); |
---|
90 | |
---|
91 | // Set SERVICE to 0. |
---|
92 | // Unfortunately, SERVICE spans a 32-bit boundary so we need two write 2 words. |
---|
93 | Xil_Out32((u32)(phy_hdr_ptr + 0), 0); |
---|
94 | Xil_Out32((u32)(phy_hdr_ptr + 4), 0); |
---|
95 | |
---|
96 | //Set SIGNAL with actual rate/length |
---|
97 | Xil_Out32((u32)phy_hdr_ptr, WLAN_TX_SIGNAL_CALC(sig_rate_vals[mcs], length)); |
---|
98 | |
---|
99 | } else if((phy_mode & PHY_MODE_HTMF) == PHY_MODE_HTMF) { |
---|
100 | //11n mode - write L-SIG (3 bytes) and HT-SIG (6 bytes) |
---|
101 | |
---|
102 | //Zero-out any stale header, also properly sets SERVICE, reserved bytes, and auto-filled bytes of HT-SIG to 0 |
---|
103 | //Old: takes longer than necessary. We only really need the SERVICE bits 0. |
---|
104 | //bzero((u32*)(TX_PKT_BUF_TO_ADDR(pkt_buf) + PHY_TX_PKT_BUF_PHY_HDR_OFFSET), PHY_TX_PKT_BUF_PHY_HDR_SIZE); |
---|
105 | |
---|
106 | // Set SERVICE to 0. |
---|
107 | Xil_Out32((u32)(phy_hdr_ptr + 8), 0); |
---|
108 | |
---|
109 | |
---|
110 | // L-SIG is same format as 11a SIGNAL, but with RATE always 6Mb and LENGTH |
---|
111 | // set such that LENGTH/6Mb matches duration of HT transmission |
---|
112 | // Using equation from IEEE 802.11-2012 9.23.4 |
---|
113 | // L-SIG.LENGTH = (3*ceil( (TXTIME - 6 - 20) / 4) - 3) |
---|
114 | // where TXTIME is actual duration of the HT transmission |
---|
115 | // The ceil((TXTIME - 6 - 20)/4) term represents the number of OFDM symbols after the L-SIG symbol |
---|
116 | // (-6-20) are (T_EXT-T_NONHT_PREAMBLE); (-3) accounts for service/tail |
---|
117 | |
---|
118 | // Calc (3*(num_payload_syms+num_ht_preamble_syms) = (3*(num_payload_syms+4)) |
---|
119 | |
---|
120 | lsig_length = 3*wlan_ofdm_calc_num_payload_syms(length, mcs, phy_mode) + 12 - 3; |
---|
121 | |
---|
122 | |
---|
123 | |
---|
124 | Xil_Out32((u32)phy_hdr_ptr, WLAN_TX_SIGNAL_CALC(sig_rate_vals[0], lsig_length)); |
---|
125 | |
---|
126 | //Assign pointer to first byte of HTSIG (PHY header base + 3 for sizeof(L-SIG)) |
---|
127 | htsig_ptr = (u8*)(phy_hdr_ptr + 3); |
---|
128 | |
---|
129 | //Set HTSIG bytes |
---|
130 | // PHY logic fills in bytes 4 and 5; ok to ignore here |
---|
131 | // Going byte-by-byte for now - maybe optimize to (unaligned) 32-bit write later |
---|
132 | htsig_ptr[0] = mcs & 0x3F; //MSB is channel bandwidth; 0=20MHz |
---|
133 | htsig_ptr[1] = length & 0xFF; |
---|
134 | htsig_ptr[2] = (length >> 8) & 0xFF; |
---|
135 | htsig_ptr[3] = 0x7; //smoothing=1, not-sounding=1, reserved=1, aggregation=STBC=FEC=short_GI=0 |
---|
136 | htsig_ptr[4] = 0x00; //NESS=0, CRC bytes must be 0 in pkt buf, PHY replaces with CRC value |
---|
137 | htsig_ptr[5] = 0x00; |
---|
138 | } |
---|
139 | |
---|
140 | |
---|
141 | return; |
---|
142 | } |
---|
143 | |
---|
144 | /*****************************************************************************/ |
---|
145 | /** |
---|
146 | * Calculates duration of an OFDM waveform. |
---|
147 | * |
---|
148 | * This function assumes every OFDM symbol is the same duration. Duration |
---|
149 | * calculation for short guard interval (SHORT_GI) waveforms is not supported. |
---|
150 | * |
---|
151 | * @param length - Length of MAC payload in bytes |
---|
152 | * @param mcs - MCS index |
---|
153 | * @param phy_mode - PHY waveform mode - either PHY_MODE_NONHT (11a/g) or PHY_MODE_HTMF (11n) |
---|
154 | * @param phy_samp_rate - PHY sampling rate - one of (PHY_10M, PHY_20M, PHY_40M) |
---|
155 | * |
---|
156 | * @return u16 - Duration of transmission in microseconds |
---|
157 | * (See IEEE 802.11-2012 18.4.3 and 20.4.3) |
---|
158 | *****************************************************************************/ |
---|
159 | inline u16 wlan_ofdm_calc_txtime(u16 length, u8 mcs, u8 phy_mode, phy_samp_rate_t phy_samp_rate) { |
---|
160 | |
---|
161 | u16 num_ht_preamble_syms, num_payload_syms; |
---|
162 | |
---|
163 | u16 t_preamble; |
---|
164 | u16 t_sym; |
---|
165 | |
---|
166 | // Note: the t_ext signal extension represent the value used in the standard, which in turn |
---|
167 | // is the value expected by other commercial WLAN devices. By default, the signal extensions |
---|
168 | // programmed into the PHY match this value. |
---|
169 | u16 t_ext = 6; |
---|
170 | |
---|
171 | // Set OFDM symbol duration in microseconds; only depends on PHY sampling rate |
---|
172 | switch(phy_samp_rate) { |
---|
173 | case PHY_40M: |
---|
174 | t_sym = 2; |
---|
175 | break; |
---|
176 | |
---|
177 | default: |
---|
178 | case PHY_20M: |
---|
179 | t_sym = 4; |
---|
180 | break; |
---|
181 | |
---|
182 | case PHY_10M: |
---|
183 | t_sym = 8; |
---|
184 | break; |
---|
185 | } |
---|
186 | |
---|
187 | // PHY preamble common to NONHT and HTMF waveforms consists of 5 OFDM symbols |
---|
188 | // 4 symbols for STF/LTF |
---|
189 | // 1 symbol for SIGNAL/L-SIG |
---|
190 | t_preamble = 5*t_sym; |
---|
191 | |
---|
192 | // Only HTMF waveforms have HT-SIG, HT-STF and HT-LTF symbols |
---|
193 | if(phy_mode == PHY_MODE_HTMF) { |
---|
194 | num_ht_preamble_syms = 4; |
---|
195 | } else { |
---|
196 | num_ht_preamble_syms = 0; |
---|
197 | } |
---|
198 | |
---|
199 | num_payload_syms = wlan_ofdm_calc_num_payload_syms(length, mcs, phy_mode); |
---|
200 | |
---|
201 | // Sum each duration and return |
---|
202 | return (t_preamble + (t_sym * (num_ht_preamble_syms + num_payload_syms)) + t_ext); |
---|
203 | } |
---|
204 | |
---|
205 | |
---|
206 | /*****************************************************************************/ |
---|
207 | /** |
---|
208 | * Calculates number of payload OFDM symbols in a packet. Implements |
---|
209 | * ceil(payload_length_bits / num_bits_per_ofdm_sym) |
---|
210 | * where num_bits_per_ofdm_sym is a function of the MCS index and PHY mode |
---|
211 | * |
---|
212 | * @param length - Length of MAC payload in bytes |
---|
213 | * @param mcs - MCS index |
---|
214 | * @param phy_mode - PHY waveform mode - either PHY_MODE_NONHT (11a/g) or PHY_MODE_HTMF (11n) |
---|
215 | * |
---|
216 | * @return u16 - Number of OFDM symbols |
---|
217 | *****************************************************************************/ |
---|
218 | inline u16 wlan_ofdm_calc_num_payload_syms(u16 length, u8 mcs, u8 phy_mode) { |
---|
219 | u16 num_payload_syms; |
---|
220 | u32 num_payload_bits; |
---|
221 | u16 n_dbps; |
---|
222 | |
---|
223 | // Payload consists of: |
---|
224 | // 16-bit SERVICE field |
---|
225 | // 'length' byte MAC payload |
---|
226 | // 6-bit TAIL field |
---|
227 | num_payload_bits = 16 + (8 * length) + 6; |
---|
228 | |
---|
229 | // Num payload syms is ceil(num_payload_bits / N_DATA_BITS_PER_SYM). The ceil() |
---|
230 | // operation implicitly accounts for any PAD bits in the waveform. The PHY inserts |
---|
231 | // PAD bits to fill the final OFDM symbol. A waveform always consists of an integer |
---|
232 | // number of OFDM symbols, so the actual number of PAD bits is irrelevant here |
---|
233 | n_dbps = wlan_mac_low_mcs_to_n_dbps(mcs, phy_mode); |
---|
234 | num_payload_syms = num_payload_bits / n_dbps; |
---|
235 | |
---|
236 | // Apply ceil() |
---|
237 | // Integer div above implies floor(); increment result if floor() changed result |
---|
238 | if( (n_dbps * num_payload_syms) != num_payload_bits ) { |
---|
239 | num_payload_syms++; |
---|
240 | } |
---|
241 | |
---|
242 | return num_payload_syms; |
---|
243 | } |
---|
244 | |
---|