From ca43e1515f42c9ab6efa485d561f5f85048807a7 Mon Sep 17 00:00:00 2001
From: Glenn Bradford <glenn.bradford@unimelb.edu.au>
Date: Fri, 1 Apr 2022 19:14:20 +1100
Subject: [PATCH] add cdc packet mac tx

---
 examples/cdc_packet_hw_loopback.grc   | 88 ++++++++++++++----------
 examples/cdc_packet_tx.grc            | 98 +++++++++++++++------------
 grc/CMakeLists.txt                    |  1 +
 grc/elen90089_packet_mac_tx.block.yml | 37 ++++++++++
 python/CMakeLists.txt                 |  1 +
 python/__init__.py                    |  1 +
 python/packet_mac_tx.py               | 90 ++++++++++++++++++++++++
 7 files changed, 237 insertions(+), 79 deletions(-)
 create mode 100644 grc/elen90089_packet_mac_tx.block.yml
 create mode 100644 python/packet_mac_tx.py

diff --git a/examples/cdc_packet_hw_loopback.grc b/examples/cdc_packet_hw_loopback.grc
index 4a76a62..44b6d6f 100644
--- a/examples/cdc_packet_hw_loopback.grc
+++ b/examples/cdc_packet_hw_loopback.grc
@@ -63,6 +63,30 @@ blocks:
     coordinate: [8, 108.0]
     rotation: 0
     state: true
+- name: default_freq
+  id: variable
+  parameters:
+    comment: ''
+    value: 920e6
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [456, 12.0]
+    rotation: 0
+    state: enabled
+- name: default_tx_gain
+  id: variable
+  parameters:
+    comment: ''
+    value: '20'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [440, 76.0]
+    rotation: 0
+    state: enabled
 - name: rf_freq
   id: variable_qtgui_range
   parameters:
@@ -75,13 +99,13 @@ blocks:
     start: 70e6
     step: 1e3
     stop: 6e9
-    value: 920e6
+    value: default_freq
     widget: counter
   states:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [456, 12.0]
+    coordinate: [560, 12.0]
     rotation: 0
     state: true
 - name: rx_gain
@@ -102,7 +126,7 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [704, 12.0]
+    coordinate: [808, 12.0]
     rotation: 0
     state: true
 - name: samp_rate
@@ -153,13 +177,13 @@ blocks:
     start: '-10'
     step: '1'
     stop: '50'
-    value: '20'
+    value: default_tx_gain
     widget: counter_slider
   states:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [584, 12.0]
+    coordinate: [688, 12.0]
     rotation: 0
     state: true
 - name: bladeRF_sink_0
@@ -176,8 +200,8 @@ blocks:
     device_id: '0'
     fpga_image: ''
     fpga_reload: 'False'
-    freq: rf_freq
-    gain0: tx_gain
+    freq: default_freq
+    gain0: default_tx_gain
     gain1: '10'
     if_gain0: '0'
     if_gain1: '20'
@@ -208,7 +232,7 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [608, 244.0]
+    coordinate: [880, 148.0]
     rotation: 0
     state: enabled
 - name: bladeRF_source_0
@@ -222,7 +246,7 @@ blocks:
     comment: ''
     dac: '10000'
     dc_calibration: LPF_TUNING
-    dc_offset_mode0: '0'
+    dc_offset_mode0: '2'
     dc_offset_mode1: '0'
     device_id: '0'
     fpga_image: ''
@@ -235,7 +259,7 @@ blocks:
     if_gain0: '0'
     if_gain1: '20'
     in_clk: ONBOARD
-    iq_balance_mode0: '0'
+    iq_balance_mode0: '2'
     iq_balance_mode1: '0'
     lpf_mode: disabled
     maxoutbuf: '0'
@@ -262,7 +286,7 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [888, 244.0]
+    coordinate: [304, 356.0]
     rotation: 0
     state: enabled
 - name: blocks_message_strobe_0
@@ -279,7 +303,7 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [784, 164.0]
+    coordinate: [592, 172.0]
     rotation: 180
     state: true
 - name: blocks_random_pdu_0
@@ -298,36 +322,26 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [488, 148.0]
+    coordinate: [280, 156.0]
     rotation: 180
     state: true
-- name: epy_block_0
-  id: epy_block
+- name: elen90089_packet_mac_tx_0
+  id: elen90089_packet_mac_tx
   parameters:
-    _source_code: "import numpy as np\nfrom gnuradio import gr\nimport pmt\n\n\nclass\
-      \ add_payload_bps(gr.sync_block):\n\n    def __init__(self, bps=1):\n      \
-      \  gr.sync_block.__init__(\n            self,\n            name='Add Payload\
-      \ BPS',   # will show up in GRC\n            in_sig=None,\n            out_sig=None\n\
-      \        )\n        self.bps = bps\n        self.message_port_register_in(pmt.intern('in'))\n\
-      \        self.message_port_register_out(pmt.intern('out'))\n        self.set_msg_handler(pmt.intern('in'),\
-      \ self.msg_handler)\n\n    def msg_handler(self, msg):\n        info = pmt.make_dict()\n\
-      \        info = pmt.dict_add(info, pmt.intern('bps'), pmt.from_long(self.bps))\n\
-      \        pdu = pmt.cons(info, pmt.cdr(msg))\n        self.message_port_pub(pmt.intern('out'),\
-      \ pdu)\n"
     affinity: ''
     alias: ''
     bps: bps_payload
     comment: ''
+    freq: rf_freq
+    gain: tx_gain
     maxoutbuf: '0'
     minoutbuf: '0'
   states:
-    _io_cache: ('Add Payload BPS', 'add_payload_bps', [('bps', '1')], [('in', 'message',
-      1)], [('out', 'message', 1)], '', ['bps'])
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [280, 172.0]
-    rotation: 180
+    coordinate: [312, 260.0]
+    rotation: 0
     state: true
 - name: packet_phy_tx_0
   id: packet_phy_tx
@@ -343,9 +357,9 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [280, 360.0]
+    coordinate: [584, 264.0]
     rotation: 0
-    state: true
+    state: enabled
 - name: qtgui_time_sink_x_0
   id: qtgui_time_sink_x
   parameters:
@@ -440,9 +454,9 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [608, 484.0]
+    coordinate: [880, 388.0]
     rotation: 0
-    state: true
+    state: enabled
 - name: qtgui_time_sink_x_0_0
   id: qtgui_time_sink_x
   parameters:
@@ -498,7 +512,7 @@ blocks:
     marker9: '-1'
     name: '"Received Waveform"'
     nconnections: '1'
-    size: '512'
+    size: '1024'
     srate: '1'
     stemplot: 'False'
     style1: '1'
@@ -537,15 +551,15 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [1120, 316.0]
+    coordinate: [544, 428.0]
     rotation: 0
     state: enabled
 
 connections:
 - [bladeRF_source_0, '0', qtgui_time_sink_x_0_0, '0']
 - [blocks_message_strobe_0, strobe, blocks_random_pdu_0, generate]
-- [blocks_random_pdu_0, pdus, epy_block_0, in]
-- [epy_block_0, out, packet_phy_tx_0, phy_sdu]
+- [blocks_random_pdu_0, pdus, elen90089_packet_mac_tx_0, mac_sdu]
+- [elen90089_packet_mac_tx_0, mac_pdu, packet_phy_tx_0, phy_sdu]
 - [packet_phy_tx_0, '0', bladeRF_sink_0, '0']
 - [packet_phy_tx_0, '0', qtgui_time_sink_x_0, '0']
 
diff --git a/examples/cdc_packet_tx.grc b/examples/cdc_packet_tx.grc
index 39fac7f..0e83b5e 100644
--- a/examples/cdc_packet_tx.grc
+++ b/examples/cdc_packet_tx.grc
@@ -63,27 +63,30 @@ blocks:
     coordinate: [8, 108.0]
     rotation: 0
     state: true
-- name: rf_freq
-  id: variable_qtgui_range
+- name: default_tx_freq
+  id: variable
   parameters:
     comment: ''
-    gui_hint: 0, 0, 1, 1
-    label: RF Frequency
-    min_len: '200'
-    orient: QtCore.Qt.Horizontal
-    rangeType: float
-    start: 70e6
-    step: 1e3
-    stop: 6e9
     value: 920e6
-    widget: counter_slider
   states:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [456, 12.0]
+    coordinate: [448, 12.0]
     rotation: 0
-    state: true
+    state: enabled
+- name: default_tx_gain
+  id: variable
+  parameters:
+    comment: ''
+    value: '0'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [448, 76.0]
+    rotation: 0
+    state: enabled
 - name: samp_rate
   id: variable
   parameters:
@@ -120,6 +123,27 @@ blocks:
     coordinate: [184, 12.0]
     rotation: 0
     state: enabled
+- name: tx_freq
+  id: variable_qtgui_range
+  parameters:
+    comment: ''
+    gui_hint: 0, 0, 1, 1
+    label: Tx Frequency
+    min_len: '200'
+    orient: QtCore.Qt.Horizontal
+    rangeType: float
+    start: 70e6
+    step: 1e3
+    stop: 6e9
+    value: default_tx_freq
+    widget: counter_slider
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [568, 12.0]
+    rotation: 0
+    state: true
 - name: tx_gain
   id: variable_qtgui_range
   parameters:
@@ -132,13 +156,13 @@ blocks:
     start: '-10'
     step: '1'
     stop: '50'
-    value: '0'
+    value: default_tx_gain
     widget: counter_slider
   states:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [584, 12.0]
+    coordinate: [696, 12.0]
     rotation: 0
     state: true
 - name: bladeRF_sink_0
@@ -155,8 +179,8 @@ blocks:
     device_id: '0'
     fpga_image: ''
     fpga_reload: 'False'
-    freq: rf_freq
-    gain0: tx_gain
+    freq: default_tx_freq
+    gain0: default_tx_gain
     gain1: '10'
     if_gain0: '0'
     if_gain1: '20'
@@ -187,7 +211,7 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [712, 340.0]
+    coordinate: [912, 332.0]
     rotation: 0
     state: disabled
 - name: blocks_message_strobe_0
@@ -204,7 +228,7 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [776, 164.0]
+    coordinate: [560, 164.0]
     rotation: 180
     state: true
 - name: blocks_random_pdu_0
@@ -223,7 +247,7 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [480, 148.0]
+    coordinate: [256, 148.0]
     rotation: 180
     state: true
 - name: blocks_throttle_0
@@ -242,36 +266,26 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [528, 268.0]
+    coordinate: [800, 260.0]
     rotation: 0
     state: true
-- name: epy_block_0
-  id: epy_block
+- name: elen90089_packet_mac_tx_0
+  id: elen90089_packet_mac_tx
   parameters:
-    _source_code: "import numpy as np\nfrom gnuradio import gr\nimport pmt\n\n\nclass\
-      \ add_payload_bps(gr.sync_block):\n\n    def __init__(self, bps=1):\n      \
-      \  gr.sync_block.__init__(\n            self,\n            name='Add Payload\
-      \ BPS',   # will show up in GRC\n            in_sig=None,\n            out_sig=None\n\
-      \        )\n        self.bps = bps\n        self.message_port_register_in(pmt.intern('in'))\n\
-      \        self.message_port_register_out(pmt.intern('out'))\n        self.set_msg_handler(pmt.intern('in'),\
-      \ self.msg_handler)\n\n    def msg_handler(self, msg):\n        info = pmt.make_dict()\n\
-      \        info = pmt.dict_add(info, pmt.intern('bps'), pmt.from_long(self.bps))\n\
-      \        pdu = pmt.cons(info, pmt.cdr(msg))\n        self.message_port_pub(pmt.intern('out'),\
-      \ pdu)\n"
     affinity: ''
     alias: ''
     bps: bps_payload
     comment: ''
+    freq: tx_freq
+    gain: tx_gain
     maxoutbuf: '0'
     minoutbuf: '0'
   states:
-    _io_cache: ('Add Payload BPS', 'add_payload_bps', [('bps', '1')], [('in', 'message',
-      1)], [('out', 'message', 1)], '', ['bps'])
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [280, 172.0]
-    rotation: 180
+    coordinate: [288, 260.0]
+    rotation: 0
     state: true
 - name: packet_phy_tx_0
   id: packet_phy_tx
@@ -287,7 +301,7 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [280, 272.0]
+    coordinate: [560, 264.0]
     rotation: 0
     state: true
 - name: qtgui_const_sink_x_0
@@ -379,7 +393,7 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [240, 356.0]
+    coordinate: [520, 340.0]
     rotation: 180
     state: enabled
 - name: qtgui_time_sink_x_0
@@ -476,15 +490,15 @@ blocks:
     bus_sink: false
     bus_source: false
     bus_structure: null
-    coordinate: [712, 244.0]
+    coordinate: [968, 236.0]
     rotation: 0
     state: true
 
 connections:
 - [blocks_message_strobe_0, strobe, blocks_random_pdu_0, generate]
-- [blocks_random_pdu_0, pdus, epy_block_0, in]
+- [blocks_random_pdu_0, pdus, elen90089_packet_mac_tx_0, mac_sdu]
 - [blocks_throttle_0, '0', qtgui_time_sink_x_0, '0']
-- [epy_block_0, out, packet_phy_tx_0, phy_sdu]
+- [elen90089_packet_mac_tx_0, mac_pdu, packet_phy_tx_0, phy_sdu]
 - [packet_phy_tx_0, '0', bladeRF_sink_0, '0']
 - [packet_phy_tx_0, '0', blocks_throttle_0, '0']
 - [packet_phy_tx_0, '1', qtgui_const_sink_x_0, '0']
diff --git a/grc/CMakeLists.txt b/grc/CMakeLists.txt
index 690c145..12c160e 100644
--- a/grc/CMakeLists.txt
+++ b/grc/CMakeLists.txt
@@ -11,5 +11,6 @@ install(FILES
     elen90089_moe_symbol_sync_cc.block.yml
     elen90089_symbol_mapper_c.block.yml
     elen90089_header_format_cdc.block.yml
+    elen90089_packet_mac_tx.block.yml
     DESTINATION share/gnuradio/grc/blocks
 )
diff --git a/grc/elen90089_packet_mac_tx.block.yml b/grc/elen90089_packet_mac_tx.block.yml
new file mode 100644
index 0000000..5526a79
--- /dev/null
+++ b/grc/elen90089_packet_mac_tx.block.yml
@@ -0,0 +1,37 @@
+id: elen90089_packet_mac_tx
+label: CDC Packet MAC Tx
+category: '[elen90089]'
+
+templates:
+  imports: import elen90089
+  make: elen90089.packet_mac_tx(${bps}, ${freq}, ${gain})
+  callbacks:
+    - set_bps(${bps})
+    - set_freq(${freq})
+    - set_gain(${gain})
+
+parameters:
+- id: bps
+  label: Payload BPS
+  dtype: int
+  default: 1
+- id: freq
+  label: Tx Frequency
+  dtype: raw
+  default: None
+- id: gain
+  label: Tx Gain
+  dtype: raw
+  default: None
+
+inputs:
+- label: mac_sdu
+  domain: message
+  optional: True
+
+outputs:
+- label: mac_pdu
+  domain: message
+  optional: True
+
+file_format: 1
diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
index a984ec1..3b89790 100644
--- a/python/CMakeLists.txt
+++ b/python/CMakeLists.txt
@@ -22,6 +22,7 @@ add_subdirectory(bindings)
 GR_PYTHON_INSTALL(
     FILES
     __init__.py
+    packet_mac_tx.py
     DESTINATION ${GR_PYTHON_DIR}/elen90089
 )
 
diff --git a/python/__init__.py b/python/__init__.py
index 76186ec..d997af0 100644
--- a/python/__init__.py
+++ b/python/__init__.py
@@ -20,4 +20,5 @@ except ModuleNotFoundError:
     pass
 
 # import any pure python here
+from .packet_mac_tx import packet_mac_tx
 #
diff --git a/python/packet_mac_tx.py b/python/packet_mac_tx.py
new file mode 100644
index 0000000..7f31aa0
--- /dev/null
+++ b/python/packet_mac_tx.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2022 University of Melbourne.
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+
+import numpy as np
+from gnuradio import gr
+import pmt
+
+
+class packet_mac_tx(gr.sync_block):
+    """CDC Packet MAC Transmitter."""
+    def __init__(self, bps=1, freq=None, gain=None):
+        gr.sync_block.__init__(
+            self,
+            name="CDC Packet MAC Tx",
+            in_sig=None,
+            out_sig=None)
+        
+        # PHY configuration parameters
+        self.bps = bps
+        self.freq = freq
+        self.gain = gain
+        
+        # create message ports
+        self.message_port_register_in(pmt.intern('mac_sdu'))
+        self.message_port_register_out(pmt.intern('mac_pdu'))
+        self.set_msg_handler(pmt.intern('mac_sdu'), self.handle_sdu)
+    
+    def set_bps(self, bps):
+        self.bps = int(bps)
+    
+    def set_freq(self, freq):
+        self.freq = float(freq)
+    
+    def set_gain(self, gain):
+        self.gain = float(gain)
+    
+    def handle_sdu(self, sdu):
+        """Handle SDU received from layer 3."""
+        
+        # add MAC header
+        data = pmt.to_python(pmt.cdr(sdu))
+        header = self.create_header()
+        payload = np.concatenate([header, data])
+        
+        # create phy configuration
+        phy_config = self.create_phy_config()
+        
+        # send PDU to PHY
+        pdu = pmt.cons(phy_config, pmt.to_pmt(payload))
+        self.message_port_pub(pmt.intern('mac_pdu'), pdu)
+    
+    def create_header(self):
+        """Create MAC header."""
+        header = np.array([], dtype=np.uint8)
+        return header
+    
+    def create_phy_config(self):
+        """Create PHY configuration dictionary."""
+        # Tx commands to bladeRF
+        tx_cmd = pmt.make_dict()
+        has_cmd = False
+        if self.freq is not None:
+            tx_cmd = pmt.dict_add(tx_cmd,
+                                  pmt.intern('freq'),
+                                  pmt.from_double(self.freq))
+            self.freq = None
+            has_cmd = True
+        if self.gain is not None:
+            tx_cmd = pmt.dict_add(tx_cmd,
+                                  pmt.intern('gain'),
+                                  pmt.from_double(self.gain))
+            self.gain = None
+            has_cmd = True
+        
+        # create config
+        config = pmt.make_dict()
+        config = pmt.dict_add(config,
+                              pmt.intern('bps'),
+                              pmt.from_long(self.bps))
+        if has_cmd:
+            config = pmt.dict_add(config,
+                                  pmt.intern('tx_command'),
+                                  tx_cmd)
+        
+        return config
-- 
GitLab