From 1ad9302fc35581712724efc8656da792edba64fc Mon Sep 17 00:00:00 2001 From: Jinghao Shi Date: Mon, 3 Apr 2017 14:31:25 -0400 Subject: [PATCH] readme --- Readme.rst | 28 ++++ scripts/policy.py | 267 ------------------------------------ scripts/policy_schema.json | 63 --------- verilog/common_params.v | 23 ---- verilog/dot11.v | 1 + verilog/xilinx_viterbi_tb.v | 125 ----------------- 6 files changed, 29 insertions(+), 478 deletions(-) create mode 100644 Readme.rst delete mode 100755 scripts/policy.py delete mode 100644 scripts/policy_schema.json delete mode 100644 verilog/xilinx_viterbi_tb.v diff --git a/Readme.rst b/Readme.rst new file mode 100644 index 0000000..1cd7dda --- /dev/null +++ b/Readme.rst @@ -0,0 +1,28 @@ +OpenOFDM +======== + +This project contains a Verilog implementation of 802.11 OFDM PHY decoder. +Features are: + + - Fully synthesizable (tested on Ettus Research USRP N210 platform) + - Full support for legacy 802.11a/g + - Support 802.11n for MCS 0 - 7 @ 20 MHz bandwidth + - Cross validation with included Python decoder + + +Environment Setup +----------------- + +This project has the following dependencies: + + - `Icarus Verilog `_: for compiling Verilog files and simulation. + - `GtkWave `_: for wave form visualization. + + +Input and Output +---------------- + +In a nutshell, the top level ``dot11`` Verilog module takes 32-bit I/Q samples +(16-bit each) as input, and output decoded bytes in 802.11 packet. The sampling +rate is 20 MSPS and the clock rate is 100 MHz. This means this module expects +one pair of I/Q sample every 5 clock ticks. diff --git a/scripts/policy.py b/scripts/policy.py deleted file mode 100755 index 094bcd5..0000000 --- a/scripts/policy.py +++ /dev/null @@ -1,267 +0,0 @@ -#!/usr/bin/env python - - -import os -import argparse -import jsonschema -import json -import itertools - -MCS_MAX = 7 -LENGTH_MAX = 4095 - -MAX_ACTION_LEN = 256 - -HEADER_LEN = 16 - -SR_RATE_FILTER = 7 -SR_LEN_FILTER = 8 -SR_HEADER_FILTER = 9 -SR_HEADER_LEN =10 -SR_JAM_POLICY = 11 - -POLICY_JSON_SCHEMA = """ -{ - "title": "Jamming Policy Format Specification", - "type": "array", - "items": { - "$ref": "#/definitions/policy" - }, - "minItems": 1, - "additionalProperties": false, - "definitions": { - "policy": { - "type": "object", - "properties": { - "length": { - "type": "integer", - "minimum": 0, - "maximum": 4095 - }, - "length_min": { - "type": "integer", - "minimum": 0, - "maximum": 4095 - }, - "length_max": { - "type": "integer", - "minimum": 0, - "maximum": 4095 - }, - - "mcs": { - "type": "integer", - "minimum": 0, - "maximum": 7 - }, - "mcs_min": { - "type": "integer", - "minimum": 0, - "maximum": 7 - }, - "mcs_max": { - "type": "integer", - "minimum": 0, - "maximum": 7 - }, - - "header": { - "type": "string", - "maxLength": 47 - }, - "actions": { - "type": "array", - "minItems": 1, - "maxItems": 256, - "items": { - "type": "string", - "enum": ["Jam", "Pass", "JamAck"] - } - } - }, - "additionalProperties": false - } - }, - "$schema": "http://json-schema.org/draft-04/schema#" -} -""" - - -def arg_parser(): - parser = argparse.ArgumentParser() - parser.add_argument('file', help="JSON file that contains the policy") - parser.add_argument('--out', help="Output file") - return parser - - -def check_policy(args): - for policy in args.policies: - if 'length' in policy and ('length_min' in policy or - 'length_max' in policy): - print "[ERROR] Policy can not contain both exact and range "\ - "quantifiers for length" - return False - - if 'mcs' in policy and ('mcs_min' in policy or 'mcs_max' in policy): - print "[ERROR] Policy can not contain both exact and range "\ - "quantifiers for mcs" - return False - - return True - - -def make_canonical(args): - for policy in args.policies: - has_mcs = any([k.startswith('mcs') for k in policy]) - has_length = any([k.startswith('length') for k in policy]) - has_header = 'header' in policy - - if has_mcs: - if 'mcs' in policy: - policy['mcs_min'] = policy['mcs'] - policy['mcs_max'] = policy['mcs'] - del policy['mcs'] - - if 'mcs_min' not in policy: - policy['mcs_min'] = 0 - - if 'mcs_max' not in policy: - policy['mcs_max'] = MCS_MAX - - policy['mcs_weight'] = 3 - if has_length: - policy['mcs_weight'] -= 1 - if has_header: - policy['mcs_weight'] -= 1 - else: - policy['mcs_min'] = MCS_MAX - policy['mcs_max'] = 0 - policy['mcs_weight'] = 0 - - if has_length: - if 'length' in policy: - policy['length_min'] = policy['length'] - policy['length_max'] = policy['length'] - del policy['length'] - - if 'length_min' not in policy: - policy['length_min'] = 0 - - if 'length_max' not in policy: - policy['length_max'] = LENGTH_MAX - - policy['length_weight'] = 3 - policy['mcs_weight'] - if has_header: - policy['mcs_weight'] -= 1 - else: - policy['length_min'] = LENGTH_MAX - policy['length_max'] = 0 - policy['length_weight'] = 0 - - if has_header: - bytes = [] - for s in policy['header'].split(): - if s == 'xx': - bytes.append(0x1ff) - else: - bytes.append(int(s, 16)) - policy['header'] = bytes - else: - policy['header'] = [] - - iter = itertools.cycle(policy['actions']) - for _ in range(MAX_ACTION_LEN-len(policy['actions'])): - policy['actions'].append(iter.next()) - - args.max_header_len = max([len(p['header']) for p in args.policies]) - for policy in args.policies: - for _ in range(args.max_header_len - len(policy['header'])): - policy['header'].append(0x1ff) - - cano_file = '_canonical'.join(os.path.splitext(args.file)) - with open(cano_file, 'w') as f: - f.write(json.dumps(args.policies, indent=2)) - - -def translate(args): - rate_data = [] - len_data = [] - header_data = [] - action_data = [] - - for id, policy in enumerate(args.policies): - val = (id<<28) + (policy['mcs_min']<<6) + (policy['mcs_max']<<2) +\ - (policy['mcs_weight']&0x3) - rate_data.append(val) - - val = (id<<28) + (policy['length_min']<<14) +\ - (policy['length_max']<<2) + (policy['length_weight']&0x3) - len_data.append(val) - - for addr, b in enumerate(policy['header']): - val = (id<<28) + (addr<<23) + (b&0x1ff) - header_data.append(val) - - for addr, a in enumerate(policy['actions']): - val = (id<<28) + (addr<<20) - if a == 'Jam': - val += 1 - elif a == 'Pass': - val += 0 - elif a == 'JamAck': - val += 2 - action_data.append(val) - - with open(args.out, 'w') as f: - f.write('0x%x\n' % (SR_RATE_FILTER)) - f.write('0x%x\n' % (len(rate_data))) - for d in rate_data: - f.write('0x%08x\n' % (d)) - - f.write('0x%x\n' % (SR_LEN_FILTER)) - f.write('0x%x\n' % (len(len_data))) - for d in len_data: - f.write('0x%08x\n' % (d)) - - f.write('0x%x\n' % (SR_HEADER_FILTER)) - f.write('0x%x\n' % (len(header_data))) - for d in header_data: - f.write('0x%08x\n' % (d)) - - f.write('0x%x\n' % (SR_HEADER_LEN)) - f.write('0x1\n') - f.write('0x%x\n' % (args.max_header_len)) - - f.write('0x%x\n' % (SR_JAM_POLICY)) - f.write('0x%x\n' % (len(action_data))) - for d in action_data: - f.write('0x%08x\n' % (d)) - - print "Jam file written to %s" % (args.out) - - -def main(): - args = arg_parser().parse_args() - - if args.out is None: - args.out = "%s.jam" % (os.path.splitext(args.file)[0]) - print "No output file specified, using %s" % (args.out) - - schema = json.loads(POLICY_JSON_SCHEMA) - - with open(args.file, 'r') as f: - args.policies = json.loads(f.read()) - - print "Validating policy ..." - jsonschema.validate(args.policies, schema) - - if not check_policy(args): - return - - print "Making canonical policy..." - make_canonical(args) - - translate(args) - -if __name__ == '__main__': - main() diff --git a/scripts/policy_schema.json b/scripts/policy_schema.json deleted file mode 100644 index 0995e50..0000000 --- a/scripts/policy_schema.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "title": "Jamming Policy Format Specification", - "type": "array", - "items": { - "$ref": "#/definitions/policy" - }, - "minItems": 1, - "additionalProperties": false, - "definitions": { - "policy": { - "type": "object", - "properties": { - "length": { - "type": "integer", - "minimum": 0, - "maximum": 4095 - }, - "length_min": { - "type": "integer", - "minimum": 0, - "maximum": 4095 - }, - "length_max": { - "type": "integer", - "minimum": 0, - "maximum": 4095 - }, - - "mcs": { - "type": "integer", - "minimum": 0, - "maximum": 7 - }, - "mcs_min": { - "type": "integer", - "minimum": 0, - "maximum": 7 - }, - "mcs_max": { - "type": "integer", - "minimum": 0, - "maximum": 7 - }, - - "header": { - "type": "string", - "maxLength": 47 - }, - "actions": { - "type": "array", - "minItems": 1, - "maxItems": 256, - "items": { - "type": "string", - "enum": ["Jam", "Pass", "JamAck"] - } - } - }, - "additionalProperties": false - } - }, - "$schema": "http://json-schema.org/draft-04/schema#" -} diff --git a/verilog/common_params.v b/verilog/common_params.v index 1392a70..6f7e82a 100644 --- a/verilog/common_params.v +++ b/verilog/common_params.v @@ -1,14 +1,3 @@ -////////////////////////////////////////////////////////////////////////// -// JAM FILTER STATUS -////////////////////////////////////////////////////////////////////////// -localparam FILTER_NO_MATCH = 0; -localparam FILTER_MATCH_PASS = 1; -localparam FILTER_MATCH_JAM = 2; -localparam FILTER_MATCH_JAM_ACK = 3; -localparam FILTER_RATIO_PASS = 4; -localparam FILTER_RATIO_JAM = 5; - - ////////////////////////////////////////////////////////////////////////// // PI DEFINITION ////////////////////////////////////////////////////////////////////////// @@ -24,9 +13,6 @@ localparam PI_3_4 = PI_2 + PI_4; ////////////////////////////////////////////////////////////////////////// // USER REG DEFINITION ////////////////////////////////////////////////////////////////////////// -localparam SR_JAMMER_ENABLE = 1; -localparam SR_JAMMER_RESET = 2; - // power trigger localparam SR_POWER_THRES = 3; localparam SR_POWER_WINDOW = 4; @@ -35,15 +21,6 @@ localparam SR_SKIP_SAMPLE = 5; // sync short localparam SR_MIN_PLATEAU = 6; -// filter -localparam SR_RATE_FILTER = 7; -localparam SR_LEN_FILTER = 8; -localparam SR_HEADER_FILTER = 9; -localparam SR_HEADER_LEN = 10; -localparam SR_JAM_POLICY = 11; - -localparam SR_JAM_SIGNAL = 12; - ////////////////////////////////////////////////////////////////////////// // DOT11 STATE MACHINE ////////////////////////////////////////////////////////////////////////// diff --git a/verilog/dot11.v b/verilog/dot11.v index 4ff1599..79b4c15 100644 --- a/verilog/dot11.v +++ b/verilog/dot11.v @@ -5,6 +5,7 @@ module dot11 ( input enable, input reset, + // setting registers input set_stb, input [7:0] set_addr, input [31:0] set_data, diff --git a/verilog/xilinx_viterbi_tb.v b/verilog/xilinx_viterbi_tb.v deleted file mode 100644 index deb4a4b..0000000 --- a/verilog/xilinx_viterbi_tb.v +++ /dev/null @@ -1,125 +0,0 @@ -module viterbi_tb; - -reg clock; -reg reset; -reg enable; - -localparam RAM_SIZE = 1<<25; -reg encoded_data [0:RAM_SIZE-1]; -reg [31:0] encoded_data_addr; - -reg decoded_data [0:RAM_SIZE-1]; -reg [31:0] decoded_data_addr; - -wire expected = decoded_data[decoded_data_addr]; - -reg [31:0] input_count; - - -localparam ENCODED_DATA_FILE = "./test_in/conv_encoded_data.txt"; -localparam DECODED_DATA_FILE = "./test_in/conv_decoded_data.txt"; - -reg clr; -reg sym0; -reg sym1; - -reg [31:0] error_count; - -wire [15:0] ber; -wire ber_done; -wire data_out; -wire rdy; - -viterbi_v7_0 viterbi_inst ( - .clk(clock), - .ce(1), - .sclr(clr), - .data_in0(sym0), - .data_in1(sym1), - .rdy(rdy), - .data_out(data_out) -); - -initial begin - $dumpfile("xilinx_viterbi_tb.vcd"); - $dumpvars; - - $display("Reading memory from %s ...", ENCODED_DATA_FILE); - $readmemb(ENCODED_DATA_FILE, encoded_data); - $readmemb(DECODED_DATA_FILE, decoded_data); - $display("Done."); - - clock = 0; - reset = 1; - enable = 0; - clr = 1; - - # 100 reset = 0; - # 100 enable = 1; - - # 20000 $finish; -end - - -always begin - #1 clock = !clock; -end - -localparam S_INPUT = 0; -localparam S_FLUSH = 1; - -reg [3:0] state; - -localparam BITS_TO_DECODE = 48*6+48; - - -always @(posedge clock) begin - if (reset) begin - sym0 <= 0; - sym1 <= 0; - input_count <= 0; - - error_count <= 0; - - encoded_data_addr <= 0; - decoded_data_addr <= 0; - state <= S_INPUT; - end else if (enable) begin - clr <= 0; - case(state) - S_INPUT: begin - if (input_count < BITS_TO_DECODE) begin - sym0 <= encoded_data[encoded_data_addr]; - sym1 <= encoded_data[encoded_data_addr+1]; - encoded_data_addr <= encoded_data_addr + 2; - input_count <= input_count + 2; - end else begin - sym0 <= 0; - sym1 <= 0; - state <= S_FLUSH; - end - end - - S_FLUSH: begin - end - endcase - - if (rdy) begin - $display("%d\t%d\t%d\t%d", decoded_data_addr, expected, data_out, error_count); - if (data_out != expected) begin - error_count <= error_count + 1; - if (error_count > 500) begin - $display("too many errors."); - $finish; - end - end - if (decoded_data_addr >= BITS_TO_DECODE/2) begin - $finish; - end else begin - decoded_data_addr <= decoded_data_addr + 1; - end - end - end -end - -endmodule