diff --git a/examples/cdc_phy_loopback.grc b/examples/cdc_phy_loopback.grc
new file mode 100644
index 0000000000000000000000000000000000000000..756e3324b0bf2a7ec0f8e51c1039f6c220c02ec1
--- /dev/null
+++ b/examples/cdc_phy_loopback.grc
@@ -0,0 +1,612 @@
+options:
+  parameters:
+    author: ''
+    catch_exceptions: 'True'
+    category: '[GRC Hier Blocks]'
+    cmake_opt: ''
+    comment: ''
+    copyright: University of Melbourne
+    description: ''
+    gen_cmake: 'On'
+    gen_linking: dynamic
+    generate_options: qt_gui
+    hier_block_src_path: '.:'
+    id: cdc_phy_loopback
+    max_nouts: '0'
+    output_language: python
+    placement: (0,0)
+    qt_qss_theme: ''
+    realtime_scheduling: ''
+    run: 'True'
+    run_command: '{python} -u {filename}'
+    run_options: prompt
+    sizing_mode: fixed
+    thread_safe_setters: ''
+    title: CDC PHY Loopback
+    window_size: (1000,1000)
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [8, 8]
+    rotation: 0
+    state: enabled
+
+blocks:
+- name: amp_gain
+  id: variable_qtgui_range
+  parameters:
+    comment: ''
+    gui_hint: ''
+    label: Amp Gain
+    min_len: '200'
+    orient: QtCore.Qt.Horizontal
+    rangeType: float
+    start: '-3'
+    step: '0.1'
+    stop: '3'
+    value: '0.0'
+    widget: counter_slider
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [288, 316.0]
+    rotation: 0
+    state: true
+- name: excess_bw
+  id: variable
+  parameters:
+    comment: ''
+    value: '0.35'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [256, 12.0]
+    rotation: 0
+    state: enabled
+- name: phase_rot
+  id: variable_qtgui_range
+  parameters:
+    comment: ''
+    gui_hint: ''
+    label: Phase Rot
+    min_len: '200'
+    orient: QtCore.Qt.Horizontal
+    rangeType: float
+    start: -np.pi
+    step: 2*np.pi/200
+    stop: np.pi
+    value: np.pi/4
+    widget: counter_slider
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [400, 316.0]
+    rotation: 0
+    state: true
+- name: sps
+  id: variable
+  parameters:
+    comment: ''
+    value: '2'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [184, 12.0]
+    rotation: 0
+    state: enabled
+- name: blocks_message_debug_0
+  id: blocks_message_debug
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    en_uvec: 'True'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [856, 8.0]
+    rotation: 0
+    state: true
+- name: blocks_message_strobe_1
+  id: blocks_message_strobe
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    msg: pmt.intern("TEST")
+    period: '500'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [352, 116.0]
+    rotation: 180
+    state: true
+- name: channels_channel_model_0
+  id: channels_channel_model
+  parameters:
+    affinity: ''
+    alias: ''
+    block_tags: 'False'
+    comment: ''
+    epsilon: '1.001'
+    freq_offset: '0.0'
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    noise_voltage: '0.0'
+    seed: '0'
+    taps: np.exp(1j*phase_rot)*10**(amp_gain)
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [304, 188.0]
+    rotation: 0
+    state: true
+- name: import_0
+  id: import
+  parameters:
+    alias: ''
+    comment: ''
+    imports: import numpy as np
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [288, 444.0]
+    rotation: 0
+    state: true
+- name: pdu_random_pdu_0
+  id: pdu_random_pdu
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    length_modulo: '2'
+    mask: '0xFF'
+    maxoutbuf: '0'
+    maxsize: '64'
+    minoutbuf: '0'
+    minsize: '64'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [80, 100.0]
+    rotation: 180
+    state: true
+- name: phy_rx_0
+  id: phy_rx
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    excess_bw: '0.350'
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    sps: '2'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [552, 152.0]
+    rotation: 0
+    state: true
+- name: phy_tx_0
+  id: phy_tx
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    excess_bw: '0.350'
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    phasing: '20'
+    sps: '2'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [80, 232.0]
+    rotation: 0
+    state: true
+- name: qtgui_const_sink_x_0
+  id: qtgui_const_sink_x
+  parameters:
+    affinity: ''
+    alias: ''
+    alpha1: '1.0'
+    alpha10: '1.0'
+    alpha2: '1.0'
+    alpha3: '1.0'
+    alpha4: '1.0'
+    alpha5: '1.0'
+    alpha6: '1.0'
+    alpha7: '1.0'
+    alpha8: '1.0'
+    alpha9: '1.0'
+    autoscale: 'False'
+    axislabels: 'True'
+    color1: '"blue"'
+    color10: '"red"'
+    color2: '"red"'
+    color3: '"red"'
+    color4: '"red"'
+    color5: '"red"'
+    color6: '"red"'
+    color7: '"red"'
+    color8: '"red"'
+    color9: '"red"'
+    comment: ''
+    grid: 'False'
+    gui_hint: ''
+    label1: ''
+    label10: ''
+    label2: ''
+    label3: ''
+    label4: ''
+    label5: ''
+    label6: ''
+    label7: ''
+    label8: ''
+    label9: ''
+    legend: 'True'
+    marker1: '0'
+    marker10: '0'
+    marker2: '0'
+    marker3: '0'
+    marker4: '0'
+    marker5: '0'
+    marker6: '0'
+    marker7: '0'
+    marker8: '0'
+    marker9: '0'
+    name: '"Symbol Sync"'
+    nconnections: '1'
+    size: '256'
+    style1: '0'
+    style10: '0'
+    style2: '0'
+    style3: '0'
+    style4: '0'
+    style5: '0'
+    style6: '0'
+    style7: '0'
+    style8: '0'
+    style9: '0'
+    tr_chan: '0'
+    tr_level: '0.0'
+    tr_mode: qtgui.TRIG_MODE_TAG
+    tr_slope: qtgui.TRIG_SLOPE_POS
+    tr_tag: '"corr_est"'
+    type: complex
+    update_time: '0.10'
+    width1: '1'
+    width10: '1'
+    width2: '1'
+    width3: '1'
+    width4: '1'
+    width5: '1'
+    width6: '1'
+    width7: '1'
+    width8: '1'
+    width9: '1'
+    xmax: '2'
+    xmin: '-2'
+    ymax: '2'
+    ymin: '-2'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [800, 116.0]
+    rotation: 0
+    state: enabled
+- name: qtgui_const_sink_x_0_0
+  id: qtgui_const_sink_x
+  parameters:
+    affinity: ''
+    alias: ''
+    alpha1: '1.0'
+    alpha10: '1.0'
+    alpha2: '1.0'
+    alpha3: '1.0'
+    alpha4: '1.0'
+    alpha5: '1.0'
+    alpha6: '1.0'
+    alpha7: '1.0'
+    alpha8: '1.0'
+    alpha9: '1.0'
+    autoscale: 'False'
+    axislabels: 'True'
+    color1: '"blue"'
+    color10: '"red"'
+    color2: '"red"'
+    color3: '"red"'
+    color4: '"red"'
+    color5: '"red"'
+    color6: '"red"'
+    color7: '"red"'
+    color8: '"red"'
+    color9: '"red"'
+    comment: ''
+    grid: 'False'
+    gui_hint: ''
+    label1: ''
+    label10: ''
+    label2: ''
+    label3: ''
+    label4: ''
+    label5: ''
+    label6: ''
+    label7: ''
+    label8: ''
+    label9: ''
+    legend: 'True'
+    marker1: '0'
+    marker10: '0'
+    marker2: '0'
+    marker3: '0'
+    marker4: '0'
+    marker5: '0'
+    marker6: '0'
+    marker7: '0'
+    marker8: '0'
+    marker9: '0'
+    name: '"Costas Loop"'
+    nconnections: '1'
+    size: '256'
+    style1: '0'
+    style10: '0'
+    style2: '0'
+    style3: '0'
+    style4: '0'
+    style5: '0'
+    style6: '0'
+    style7: '0'
+    style8: '0'
+    style9: '0'
+    tr_chan: '0'
+    tr_level: '0.0'
+    tr_mode: qtgui.TRIG_MODE_TAG
+    tr_slope: qtgui.TRIG_SLOPE_POS
+    tr_tag: '"corr_est"'
+    type: complex
+    update_time: '0.10'
+    width1: '1'
+    width10: '1'
+    width2: '1'
+    width3: '1'
+    width4: '1'
+    width5: '1'
+    width6: '1'
+    width7: '1'
+    width8: '1'
+    width9: '1'
+    xmax: '2'
+    xmin: '-2'
+    ymax: '2'
+    ymin: '-2'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [800, 196.0]
+    rotation: 0
+    state: enabled
+- name: qtgui_time_sink_x_0
+  id: qtgui_time_sink_x
+  parameters:
+    affinity: ''
+    alias: ''
+    alpha1: '1.0'
+    alpha10: '1.0'
+    alpha2: '1.0'
+    alpha3: '1.0'
+    alpha4: '1.0'
+    alpha5: '1.0'
+    alpha6: '1.0'
+    alpha7: '1.0'
+    alpha8: '1.0'
+    alpha9: '1.0'
+    autoscale: 'False'
+    axislabels: 'True'
+    color1: blue
+    color10: dark blue
+    color2: red
+    color3: green
+    color4: black
+    color5: cyan
+    color6: magenta
+    color7: yellow
+    color8: dark red
+    color9: dark green
+    comment: ''
+    ctrlpanel: 'False'
+    entags: 'True'
+    grid: 'False'
+    gui_hint: ''
+    label1: Signal 1
+    label10: Signal 10
+    label2: Signal 2
+    label3: Signal 3
+    label4: Signal 4
+    label5: Signal 5
+    label6: Signal 6
+    label7: Signal 7
+    label8: Signal 8
+    label9: Signal 9
+    legend: 'True'
+    marker1: '-1'
+    marker10: '-1'
+    marker2: '-1'
+    marker3: '-1'
+    marker4: '-1'
+    marker5: '-1'
+    marker6: '-1'
+    marker7: '-1'
+    marker8: '-1'
+    marker9: '-1'
+    name: '"Preamble"'
+    nconnections: '1'
+    size: '256'
+    srate: '1'
+    stemplot: 'False'
+    style1: '1'
+    style10: '1'
+    style2: '1'
+    style3: '1'
+    style4: '1'
+    style5: '1'
+    style6: '1'
+    style7: '1'
+    style8: '1'
+    style9: '1'
+    tr_chan: '0'
+    tr_delay: '0'
+    tr_level: '0.0'
+    tr_mode: qtgui.TRIG_MODE_TAG
+    tr_slope: qtgui.TRIG_SLOPE_POS
+    tr_tag: '"corr_est"'
+    type: float
+    update_time: '0.10'
+    width1: '1'
+    width10: '1'
+    width2: '1'
+    width3: '1'
+    width4: '1'
+    width5: '1'
+    width6: '1'
+    width7: '1'
+    width8: '1'
+    width9: '1'
+    ylabel: Amplitude
+    ymax: '1.5'
+    ymin: '0'
+    yunit: '""'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [832, 276.0]
+    rotation: 0
+    state: enabled
+- name: qtgui_time_sink_x_1
+  id: qtgui_time_sink_x
+  parameters:
+    affinity: ''
+    alias: ''
+    alpha1: '1.0'
+    alpha10: '1.0'
+    alpha2: '1.0'
+    alpha3: '1.0'
+    alpha4: '1.0'
+    alpha5: '1.0'
+    alpha6: '1.0'
+    alpha7: '1.0'
+    alpha8: '1.0'
+    alpha9: '1.0'
+    autoscale: 'False'
+    axislabels: 'True'
+    color1: blue
+    color10: dark blue
+    color2: red
+    color3: green
+    color4: black
+    color5: cyan
+    color6: magenta
+    color7: yellow
+    color8: dark red
+    color9: dark green
+    comment: ''
+    ctrlpanel: 'False'
+    entags: 'True'
+    grid: 'False'
+    gui_hint: ''
+    label1: Signal 1
+    label10: Signal 10
+    label2: Signal 2
+    label3: Signal 3
+    label4: Signal 4
+    label5: Signal 5
+    label6: Signal 6
+    label7: Signal 7
+    label8: Signal 8
+    label9: Signal 9
+    legend: 'True'
+    marker1: '-1'
+    marker10: '-1'
+    marker2: '-1'
+    marker3: '-1'
+    marker4: '-1'
+    marker5: '-1'
+    marker6: '-1'
+    marker7: '-1'
+    marker8: '-1'
+    marker9: '-1'
+    name: '"AGC"'
+    nconnections: '1'
+    size: '1024'
+    srate: '1'
+    stemplot: 'False'
+    style1: '1'
+    style10: '1'
+    style2: '1'
+    style3: '1'
+    style4: '1'
+    style5: '1'
+    style6: '1'
+    style7: '1'
+    style8: '1'
+    style9: '1'
+    tr_chan: '0'
+    tr_delay: '0'
+    tr_level: '0.0'
+    tr_mode: qtgui.TRIG_MODE_TAG
+    tr_slope: qtgui.TRIG_SLOPE_POS
+    tr_tag: '"corr_est"'
+    type: complex
+    update_time: '0.10'
+    width1: '1'
+    width10: '1'
+    width2: '1'
+    width3: '1'
+    width4: '1'
+    width5: '1'
+    width6: '1'
+    width7: '1'
+    width8: '1'
+    width9: '1'
+    ylabel: Amplitude
+    ymax: '2'
+    ymin: '-2'
+    yunit: '""'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [816, 372.0]
+    rotation: 0
+    state: true
+
+connections:
+- [blocks_message_strobe_1, strobe, pdu_random_pdu_0, generate]
+- [channels_channel_model_0, '0', phy_rx_0, '0']
+- [pdu_random_pdu_0, pdus, phy_tx_0, sdu]
+- [phy_rx_0, '0', qtgui_const_sink_x_0, '0']
+- [phy_rx_0, '1', qtgui_const_sink_x_0_0, '0']
+- [phy_rx_0, '3', qtgui_time_sink_x_0, '0']
+- [phy_rx_0, '4', qtgui_time_sink_x_1, '0']
+- [phy_rx_0, pdu, blocks_message_debug_0, print]
+- [phy_tx_0, '0', channels_channel_model_0, '0']
+
+metadata:
+  file_format: 1
diff --git a/examples/cdc_phy_rx.grc b/examples/cdc_phy_rx.grc
new file mode 100644
index 0000000000000000000000000000000000000000..65862b8ca694db4f7575b34c0e0c7b245ba6fba9
--- /dev/null
+++ b/examples/cdc_phy_rx.grc
@@ -0,0 +1,561 @@
+options:
+  parameters:
+    author: ''
+    catch_exceptions: 'True'
+    category: '[CDC]'
+    cmake_opt: ''
+    comment: ''
+    copyright: University of Melbourne
+    description: ''
+    gen_cmake: 'On'
+    gen_linking: dynamic
+    generate_options: hb
+    hier_block_src_path: '.:'
+    id: cdc_phy_rx_mod
+    max_nouts: '0'
+    output_language: python
+    placement: (0,0)
+    qt_qss_theme: ''
+    realtime_scheduling: ''
+    run: 'True'
+    run_command: '{python} -u {filename}'
+    run_options: prompt
+    sizing_mode: fixed
+    thread_safe_setters: ''
+    title: CDC PHY Rx (Mod)
+    window_size: (1000,1000)
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [8, 8]
+    rotation: 0
+    state: enabled
+
+blocks:
+- name: constel
+  id: variable_constellation
+  parameters:
+    comment: ''
+    const_points: '[-1-1j, -1+1j, 1+1j, 1-1j]'
+    dims: '1'
+    normalization: digital.constellation.AMPLITUDE_NORMALIZATION
+    precision: '8'
+    rot_sym: '4'
+    soft_dec_lut: None
+    sym_map: '[0, 1, 3, 2]'
+    type: bpsk
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [200, 420.0]
+    rotation: 0
+    state: true
+- name: modulated_sync_word
+  id: variable
+  parameters:
+    comment: ''
+    value: np.array([ 6.3415498e-01+0.j, -8.2522854e-02+0.j, -6.7432624e-01+0.j, 2.1960361e-02+0.j,  6.6994393e-01+0.j,  2.7926212e-02+0.j,
+      -6.2773204e-01+0.j, -1.6468078e-01+0.j,  5.7718420e-01+0.j, 7.2756535e-01+0.j,  4.6373290e-01+0.j,  2.3871353e-02+0.j,
+      -4.8910391e-01+0.j, -7.3612314e-01+0.j, -4.8162562e-01+0.j, 1.2282493e-02+0.j,  4.6576929e-01+0.j,  7.3573601e-01+0.j,
+      5.4807413e-01+0.j, -1.3198391e-01+0.j, -5.6807721e-01+0.j, -1.1599341e-01+0.j,  6.0297143e-01+0.j,  6.1259979e-01+0.j,
+      3.7387580e-01+0.j,  6.1534089e-01+0.j,  6.1044985e-01+0.j, -1.3032347e-01+0.j,
+      -5.7351917e-01+0.j, -1.1359498e-01+0.j, 5.1318854e-01+0.j,  7.6605660e-01+0.j,  5.5351597e-01+0.j,
+      -1.7184576e-01+0.j, -6.0304552e-01+0.j, -5.2386895e-09+0.j, 6.0304564e-01+0.j,  1.7458701e-01+0.j,
+      -5.4603779e-01+0.j, -7.7764541e-01+0.j, -5.1115209e-01+0.j,  1.2587748e-01+0.j,
+      5.5562639e-01+0.j,  1.4426640e-01+0.j, -5.5147964e-01+0.j, -7.4326605e-01+0.j,
+      -4.9114031e-01+0.j,  2.7579335e-02+0.j, 5.3652304e-01+0.j,  5.9185678e-01+0.j,  4.3005973e-01+0.j,
+      5.5639654e-01+0.j,  5.7140875e-01+0.j,  1.4330061e-02+0.j, -5.7344508e-01+0.j,
+      -5.8026785e-01+0.j, -4.0265229e-01+0.j, -6.0784715e-01+0.j, -6.1882788e-01+0.j,  1.3541880e-01+0.j,
+      6.3996756e-01+0.j, -1.1588858e-02+0.j, -6.3045293e-01+0.j, -1.2313626e-01+0.j,  5.9345692e-01+0.j,  6.3337904e-01+0.j,
+      4.5958614e-01+0.j,  4.4280154e-01+0.j,  4.8155165e-01+0.j, 6.0579962e-01+0.j,  5.2610868e-01+0.j,  2.5531810e-02+0.j,
+      -4.9454585e-01+0.j, -7.3372471e-01+0.j, -5.7140863e-01+0.j, 1.6025695e-01+0.j,  6.3045293e-01+0.j,
+      -2.2790564e-02+0.j, -6.5453744e-01+0.j, -4.3920707e-02+0.j,  6.6330218e-01+0.j,
+      1.3472509e-01+0.j, -6.3582081e-01+0.j, -5.8741081e-01+0.j, -4.1216698e-01+0.j,
+      -5.9255040e-01+0.j, -5.4807413e-01+0.j, -1.3942933e-02+0.j,  5.0699669e-01+0.j,  7.0545167e-01+0.j,
+      5.1991683e-01+0.j, -3.5073120e-02+0.j, -5.2814502e-01+0.j, -5.9695208e-01+0.j,
+      -4.9650821e-01+0.j, -4.3669510e-01+0.j, -4.6910083e-01+0.j, -6.3407266e-01+0.j,
+      -5.7760048e-01+0.j, 9.9652052e-02+0.j,  5.9685379e-01+0.j,  1.1398210e-01+0.j,
+      -5.7963693e-01+0.j, -6.4087272e-01+0.j, -4.3625149e-01+0.j, -4.7107458e-01+0.j,
+      -5.4392737e-01+0.j, -4.6153325e-01+0.j, -4.5958611e-01+0.j, -6.1738855e-01+0.j,
+      -5.3855950e-01+0.j, 2.7412227e-03+0.j,  5.4603767e-01+0.j,  6.0305846e-01+0.j,
+      4.5414424e-01+0.j,  4.7992218e-01+0.j,  5.0904173e-01+0.j, 4.9728334e-01+0.j,  5.1278079e-01+0.j,  4.7549835e-01+0.j,
+      4.5890158e-01+0.j,  6.0340530e-01+0.j,  5.3810960e-01+0.j, 1.3112724e-02+0.j,
+      -5.2549899e-01+0.j, -6.6004950e-01+0.j, -4.8329139e-01+0.j, -2.2242454e-01+0.j],
+      dtype=np.complex64)
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [160, 156.0]
+    rotation: 0
+    state: true
+- name: nfilts
+  id: variable
+  parameters:
+    comment: ''
+    value: '32'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [672, 20.0]
+    rotation: 0
+    state: true
+- name: rrc_taps
+  id: variable_rrc_filter_taps
+  parameters:
+    alpha: excess_bw
+    comment: ''
+    gain: nfilts
+    ntaps: 11*sps*nfilts
+    samp_rate: sps*nfilts
+    sym_rate: '1.0'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [744, 20.0]
+    rotation: 0
+    state: true
+- name: blocks_multiply_by_tag_value_cc_0
+  id: blocks_multiply_by_tag_value_cc
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    tagname: amp_est
+    vlen: '1'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [392, 212.0]
+    rotation: 0
+    state: true
+- name: blocks_repack_bits_bb_0
+  id: blocks_repack_bits_bb
+  parameters:
+    affinity: ''
+    alias: ''
+    align_output: 'True'
+    comment: ''
+    endianness: gr.GR_MSB_FIRST
+    k: constel.bits_per_symbol()
+    l: '8'
+    len_tag_key: '"packet_len"'
+    maxoutbuf: '0'
+    minoutbuf: '0'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [720, 364.0]
+    rotation: 0
+    state: true
+- name: cdc_preamble_detect_cc_0
+  id: cdc_preamble_detect_cc
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    mark_delay: '0'
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    sequence: modulated_sync_word
+    threshold: '0.5'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [152, 220.0]
+    rotation: 0
+    state: true
+- name: digital_additive_scrambler_bb_0
+  id: digital_additive_scrambler_bb
+  parameters:
+    affinity: ''
+    alias: ''
+    bits_per_byte: '8'
+    comment: ''
+    count: '0'
+    len: '7'
+    mask: '0x8A'
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    reset_tag_key: '"packet_len"'
+    seed: '0x7F'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [192, 492.0]
+    rotation: 0
+    state: true
+- name: digital_constellation_decoder_cb_0
+  id: digital_constellation_decoder_cb
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    constellation: constel
+    maxoutbuf: '0'
+    minoutbuf: '0'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [200, 372.0]
+    rotation: 0
+    state: true
+- name: digital_correlate_access_code_xx_ts_0
+  id: digital_correlate_access_code_xx_ts
+  parameters:
+    access_code: digital.packet_utils.default_access_code
+    affinity: ''
+    alias: ''
+    comment: ''
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    tagname: packet_len
+    threshold: '3'
+    type: byte
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [432, 356.0]
+    rotation: 0
+    state: true
+- name: digital_costas_loop_cc_0
+  id: digital_costas_loop_cc
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    order: constel.arity()
+    use_snr: 'False'
+    w: '0.035'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [1024, 144.0]
+    rotation: 0
+    state: true
+- name: digital_crc32_async_bb_0
+  id: digital_crc32_async_bb
+  parameters:
+    affinity: ''
+    alias: ''
+    check: 'True'
+    comment: ''
+    maxoutbuf: '0'
+    minoutbuf: '0'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [632, 532.0]
+    rotation: 0
+    state: true
+- name: digital_symbol_sync_xx_0
+  id: digital_symbol_sync_xx
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    constellation: digital.constellation_bpsk().base()
+    damping: '1.0'
+    loop_bw: 0.045/2
+    max_dev: '1.5'
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    nfilters: nfilts
+    osps: '1'
+    pfb_mf_taps: rrc_taps
+    resamp_type: digital.IR_PFB_MF
+    sps: sps
+    ted_gain: '1.0'
+    ted_type: digital.TED_EARLY_LATE
+    type: cc
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [624, 148.0]
+    rotation: 0
+    state: true
+- name: excess_bw
+  id: parameter
+  parameters:
+    alias: ''
+    comment: ''
+    hide: none
+    label: Excess Bw
+    short_id: ''
+    type: eng_float
+    value: '0.350'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [336, 12.0]
+    rotation: 0
+    state: true
+- name: import_0
+  id: import
+  parameters:
+    alias: ''
+    comment: ''
+    imports: import numpy as np
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [80, 156.0]
+    rotation: 0
+    state: true
+- name: pad_sink_0
+  id: pad_sink
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    label: pdu
+    num_streams: '1'
+    optional: 'True'
+    type: message
+    vlen: '1'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [792, 532.0]
+    rotation: 0
+    state: true
+- name: pad_sink_1
+  id: pad_sink
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    label: timing
+    num_streams: '1'
+    optional: 'True'
+    type: complex
+    vlen: '1'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [1024, 276.0]
+    rotation: 0
+    state: true
+- name: pad_sink_1_0
+  id: pad_sink
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    label: symbols
+    num_streams: '1'
+    optional: 'True'
+    type: complex
+    vlen: '1'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [1280, 188.0]
+    rotation: 0
+    state: true
+- name: pad_sink_1_1
+  id: pad_sink
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    label: packet
+    num_streams: '1'
+    optional: 'True'
+    type: byte
+    vlen: '1'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [400, 580.0]
+    rotation: 0
+    state: true
+- name: pad_sink_1_2
+  id: pad_sink
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    label: corr
+    num_streams: '1'
+    optional: 'True'
+    type: float
+    vlen: '1'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [264, 300.0]
+    rotation: 180
+    state: true
+- name: pad_sink_1_3
+  id: pad_sink
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    label: agc
+    num_streams: '1'
+    optional: 'True'
+    type: complex
+    vlen: '1'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [472, 276.0]
+    rotation: 180
+    state: true
+- name: pad_source_0
+  id: pad_source
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    label: iq
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    num_streams: '1'
+    optional: 'False'
+    type: complex
+    vlen: '1'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [16, 236.0]
+    rotation: 0
+    state: true
+- name: pdu_tagged_stream_to_pdu_0
+  id: pdu_tagged_stream_to_pdu
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    tag: packet_len
+    type: byte
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [400, 532.0]
+    rotation: 0
+    state: true
+- name: sps
+  id: parameter
+  parameters:
+    alias: ''
+    comment: ''
+    hide: none
+    label: Samps per Symb
+    short_id: ''
+    type: intx
+    value: '2'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [192, 12.0]
+    rotation: 0
+    state: true
+- name: virtual_sink_0
+  id: virtual_sink
+  parameters:
+    alias: ''
+    comment: ''
+    stream_id: symbols
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [1280, 140.0]
+    rotation: 0
+    state: true
+- name: virtual_sink_0_0
+  id: virtual_sink
+  parameters:
+    alias: ''
+    comment: ''
+    stream_id: bytes
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [928, 372.0]
+    rotation: 0
+    state: true
+- name: virtual_source_0
+  id: virtual_source
+  parameters:
+    alias: ''
+    comment: ''
+    stream_id: symbols
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [16, 372.0]
+    rotation: 0
+    state: true
+- name: virtual_source_0_0
+  id: virtual_source
+  parameters:
+    alias: ''
+    comment: ''
+    stream_id: bytes
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [16, 532.0]
+    rotation: 0
+    state: true
+
+connections:
+- [blocks_multiply_by_tag_value_cc_0, '0', digital_symbol_sync_xx_0, '0']
+- [blocks_multiply_by_tag_value_cc_0, '0', pad_sink_1_3, '0']
+- [blocks_repack_bits_bb_0, '0', virtual_sink_0_0, '0']
+- [cdc_preamble_detect_cc_0, '0', blocks_multiply_by_tag_value_cc_0, '0']
+- [cdc_preamble_detect_cc_0, '1', pad_sink_1_2, '0']
+- [digital_additive_scrambler_bb_0, '0', pad_sink_1_1, '0']
+- [digital_additive_scrambler_bb_0, '0', pdu_tagged_stream_to_pdu_0, '0']
+- [digital_constellation_decoder_cb_0, '0', digital_correlate_access_code_xx_ts_0,
+  '0']
+- [digital_correlate_access_code_xx_ts_0, '0', blocks_repack_bits_bb_0, '0']
+- [digital_costas_loop_cc_0, '0', pad_sink_1_0, '0']
+- [digital_costas_loop_cc_0, '0', virtual_sink_0, '0']
+- [digital_crc32_async_bb_0, out, pad_sink_0, in]
+- [digital_symbol_sync_xx_0, '0', digital_costas_loop_cc_0, '0']
+- [digital_symbol_sync_xx_0, '0', pad_sink_1, '0']
+- [pad_source_0, '0', cdc_preamble_detect_cc_0, '0']
+- [pdu_tagged_stream_to_pdu_0, pdus, digital_crc32_async_bb_0, in]
+- [virtual_source_0, '0', digital_constellation_decoder_cb_0, '0']
+- [virtual_source_0_0, '0', digital_additive_scrambler_bb_0, '0']
+
+metadata:
+  file_format: 1
diff --git a/examples/cdc_phy_tx.grc b/examples/cdc_phy_tx.grc
new file mode 100644
index 0000000000000000000000000000000000000000..bd2e60bb1a514d3014cc0feec19def028e15bbbd
--- /dev/null
+++ b/examples/cdc_phy_tx.grc
@@ -0,0 +1,453 @@
+options:
+  parameters:
+    author: ''
+    catch_exceptions: 'True'
+    category: '[CDC]'
+    cmake_opt: ''
+    comment: ''
+    copyright: University of Melbourne
+    description: ''
+    gen_cmake: 'On'
+    gen_linking: dynamic
+    generate_options: hb
+    hier_block_src_path: '.:'
+    id: cdc_phy_tx_mod
+    max_nouts: '0'
+    output_language: python
+    placement: (0,0)
+    qt_qss_theme: ''
+    realtime_scheduling: ''
+    run: 'True'
+    run_command: '{python} -u {filename}'
+    run_options: prompt
+    sizing_mode: fixed
+    thread_safe_setters: ''
+    title: CDC PHY Tx (Mod)
+    window_size: (1000,1000)
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [8, 8]
+    rotation: 0
+    state: enabled
+
+blocks:
+- name: access_code
+  id: variable
+  parameters:
+    comment: ''
+    value: digital.packet_utils.default_access_code
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [768, 12.0]
+    rotation: 0
+    state: true
+- name: constel
+  id: variable_constellation
+  parameters:
+    comment: ''
+    const_points: '[-1-1j, -1+1j, 1+1j, 1-1j]'
+    dims: '1'
+    normalization: digital.constellation.AMPLITUDE_NORMALIZATION
+    precision: '8'
+    rot_sym: '4'
+    soft_dec_lut: None
+    sym_map: '[0, 1, 3, 2]'
+    type: bpsk
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [192, 388.0]
+    rotation: 0
+    state: true
+- name: header_format
+  id: variable
+  parameters:
+    comment: ''
+    value: digital.header_format_default(access_code, 0, constel.bits_per_symbol())
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [952, 12.0]
+    rotation: 0
+    state: true
+- name: num_taps
+  id: variable
+  parameters:
+    comment: ''
+    value: 11*sps
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [1024, 404.0]
+    rotation: 0
+    state: true
+- name: blocks_repack_bits_bb_0
+  id: blocks_repack_bits_bb
+  parameters:
+    affinity: ''
+    alias: ''
+    align_output: 'False'
+    comment: ''
+    endianness: gr.GR_MSB_FIRST
+    k: '8'
+    l: constel.bits_per_symbol()
+    len_tag_key: '"packet_len"'
+    maxoutbuf: '0'
+    minoutbuf: '0'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [192, 316.0]
+    rotation: 0
+    state: true
+- name: blocks_tagged_stream_mux_0
+  id: blocks_tagged_stream_mux
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    lengthtagname: packet_len
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    ninputs: '2'
+    tag_preserve_head_pos: '0'
+    type: byte
+    vlen: '1'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [1016, 128.0]
+    rotation: 0
+    state: true
+- name: cdc_tag_tx_burst_cc_0
+  id: cdc_tag_tx_burst_cc
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    lengthtagname: packet_len
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    scalar: sps
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [1168, 308.0]
+    rotation: 0
+    state: true
+- name: digital_additive_scrambler_bb_0
+  id: digital_additive_scrambler_bb
+  parameters:
+    affinity: ''
+    alias: ''
+    bits_per_byte: '8'
+    comment: ''
+    count: '0'
+    len: '7'
+    mask: '0x8A'
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    reset_tag_key: '"packet_len"'
+    seed: '0x7F'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [568, 124.0]
+    rotation: 0
+    state: true
+- name: digital_burst_shaper_xx_0
+  id: digital_burst_shaper_xx
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    insert_phasing: 'True'
+    length_tag_name: '"packet_len"'
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    post_padding: num_taps//2
+    pre_padding: '0'
+    type: complex
+    window: firdes.window(window.WIN_HANN, phasing, 0)
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [696, 284.0]
+    rotation: 0
+    state: true
+- name: digital_chunks_to_symbols_xx_0
+  id: digital_chunks_to_symbols_xx
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    dimension: '1'
+    in_type: byte
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    num_ports: '1'
+    out_type: complex
+    symbol_table: constel.points()
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [496, 304.0]
+    rotation: 0
+    state: true
+- name: digital_crc32_async_bb_0
+  id: digital_crc32_async_bb
+  parameters:
+    affinity: ''
+    alias: ''
+    check: 'False'
+    comment: ''
+    maxoutbuf: '0'
+    minoutbuf: '0'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [152, 164.0]
+    rotation: 0
+    state: true
+- name: digital_protocol_formatter_bb_0
+  id: digital_protocol_formatter_bb
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    format: header_format
+    len_tag_key: '"packet_len"'
+    maxoutbuf: '0'
+    minoutbuf: '0'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [768, 116.0]
+    rotation: 0
+    state: true
+- name: excess_bw
+  id: parameter
+  parameters:
+    alias: ''
+    comment: ''
+    hide: none
+    label: Excess Bw
+    short_id: ''
+    type: eng_float
+    value: '0.350'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [336, 12.0]
+    rotation: 0
+    state: true
+- name: pad_sink_0
+  id: pad_sink
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    label: iq
+    num_streams: '1'
+    optional: 'False'
+    type: complex
+    vlen: '1'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [1400, 316.0]
+    rotation: 0
+    state: true
+- name: pad_sink_1
+  id: pad_sink
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    label: burst
+    num_streams: '1'
+    optional: 'True'
+    type: complex
+    vlen: '1'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [936, 404.0]
+    rotation: 0
+    state: true
+- name: pad_sink_1_0
+  id: pad_sink
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    label: symbols
+    num_streams: '1'
+    optional: 'True'
+    type: complex
+    vlen: '1'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [696, 396.0]
+    rotation: 0
+    state: true
+- name: pad_source_0
+  id: pad_source
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    label: sdu
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    num_streams: '1'
+    optional: 'True'
+    type: message
+    vlen: '1'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [16, 164.0]
+    rotation: 0
+    state: true
+- name: pdu_pdu_to_tagged_stream_0
+  id: pdu_pdu_to_tagged_stream
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    tag: packet_len
+    type: byte
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [344, 164.0]
+    rotation: 0
+    state: true
+- name: phasing
+  id: parameter
+  parameters:
+    alias: ''
+    comment: ''
+    hide: none
+    label: Phasing Symbols
+    short_id: ''
+    type: intx
+    value: '20'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [448, 12.0]
+    rotation: 0
+    state: true
+- name: root_raised_cosine_filter_0
+  id: root_raised_cosine_filter
+  parameters:
+    affinity: ''
+    alias: ''
+    alpha: excess_bw
+    comment: ''
+    decim: '1'
+    gain: '1.0'
+    interp: sps
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    ntaps: num_taps
+    samp_rate: sps
+    sym_rate: '1.0'
+    type: interp_fir_filter_ccf
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [936, 276.0]
+    rotation: 0
+    state: true
+- name: sps
+  id: parameter
+  parameters:
+    alias: ''
+    comment: ''
+    hide: none
+    label: Samps per Symb
+    short_id: ''
+    type: intx
+    value: '2'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [192, 12.0]
+    rotation: 0
+    state: true
+- name: virtual_sink_0
+  id: virtual_sink
+  parameters:
+    alias: ''
+    comment: ''
+    stream_id: tx_bytes
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [1248, 140.0]
+    rotation: 0
+    state: true
+- name: virtual_source_0
+  id: virtual_source
+  parameters:
+    alias: ''
+    comment: ''
+    stream_id: tx_bytes
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [16, 324.0]
+    rotation: 0
+    state: true
+
+connections:
+- [blocks_repack_bits_bb_0, '0', digital_chunks_to_symbols_xx_0, '0']
+- [blocks_tagged_stream_mux_0, '0', virtual_sink_0, '0']
+- [cdc_tag_tx_burst_cc_0, '0', pad_sink_0, '0']
+- [digital_additive_scrambler_bb_0, '0', blocks_tagged_stream_mux_0, '1']
+- [digital_additive_scrambler_bb_0, '0', digital_protocol_formatter_bb_0, '0']
+- [digital_burst_shaper_xx_0, '0', pad_sink_1, '0']
+- [digital_burst_shaper_xx_0, '0', root_raised_cosine_filter_0, '0']
+- [digital_chunks_to_symbols_xx_0, '0', digital_burst_shaper_xx_0, '0']
+- [digital_chunks_to_symbols_xx_0, '0', pad_sink_1_0, '0']
+- [digital_crc32_async_bb_0, out, pdu_pdu_to_tagged_stream_0, pdus]
+- [digital_protocol_formatter_bb_0, '0', blocks_tagged_stream_mux_0, '0']
+- [pad_source_0, out, digital_crc32_async_bb_0, in]
+- [pdu_pdu_to_tagged_stream_0, '0', digital_additive_scrambler_bb_0, '0']
+- [root_raised_cosine_filter_0, '0', cdc_tag_tx_burst_cc_0, '0']
+- [virtual_source_0, '0', blocks_repack_bits_bb_0, '0']
+
+metadata:
+  file_format: 1
diff --git a/grc/CMakeLists.txt b/grc/CMakeLists.txt
index 49a597df0d6617ad013021f3f8579a993c6aa5bf..31c18d1e357264535f1c633bdfce9b43ef1b4b9d 100644
--- a/grc/CMakeLists.txt
+++ b/grc/CMakeLists.txt
@@ -5,7 +5,9 @@
 #
 # SPDX-License-Identifier: GPL-3.0-or-later
 #
-
 install(FILES
-    DESTINATION share/gnuradio/grc/blocks
+    cdc_tag_tx_burst_cc.block.yml
+    cdc_preamble_detect_cc.block.yml
+    cdc_phy_tx.block.yml
+    cdc_phy_rx.block.yml DESTINATION share/gnuradio/grc/blocks
 )
diff --git a/grc/cdc_phy_rx.block.yml b/grc/cdc_phy_rx.block.yml
new file mode 100644
index 0000000000000000000000000000000000000000..6a806a2eae53e1a6f9c207f6660fbdc4b650541b
--- /dev/null
+++ b/grc/cdc_phy_rx.block.yml
@@ -0,0 +1,58 @@
+id: phy_rx
+label: CDC PHY Rx
+category: '[CDC]'
+
+parameters:
+-   id: excess_bw
+    label: Excess Bw
+    dtype: real
+    default: '0.350'
+    hide: none
+-   id: sps
+    label: Samps per Symb
+    dtype: int
+    default: '2'
+    hide: none
+
+inputs:
+-   label: iq
+    dtype: complex
+    vlen: 1
+
+outputs:
+-   label: pdu
+    domain: message
+    dtype: message
+    optional: true
+-   label: timing
+    dtype: complex
+    vlen: 1
+    optional: true
+-   label: symbols
+    dtype: complex
+    vlen: 1
+    optional: true
+-   label: packet
+    dtype: byte
+    vlen: 1
+    optional: true
+-   label: corr
+    dtype: float
+    vlen: 1
+    optional: true
+-   label: agc
+    dtype: complex
+    vlen: 1
+    optional: true
+
+templates:
+    imports: 'from phy_rx import phy_rx  # grc-generated hier_block'
+    make: "phy_rx(\n    excess_bw=${ excess_bw },\n    sps=${ sps },\n)"
+    callbacks:
+    - set_excess_bw(${ excess_bw })
+    - set_sps(${ sps })
+
+documentation: /home/gjbradford/code/gnuradio/gr/gr-cdc/examples/phy_rx.py
+grc_source: /home/gjbradford/code/gnuradio/gr/gr-cdc/examples/cdc_phy_rx.grc
+
+file_format: 1
diff --git a/grc/cdc_phy_tx.block.yml b/grc/cdc_phy_tx.block.yml
new file mode 100644
index 0000000000000000000000000000000000000000..8f58df9553bab0f5a5fe52ba329ef5577c55e5e6
--- /dev/null
+++ b/grc/cdc_phy_tx.block.yml
@@ -0,0 +1,53 @@
+id: phy_tx
+label: CDC PHY Tx
+category: '[CDC]'
+
+parameters:
+-   id: excess_bw
+    label: Excess Bw
+    dtype: real
+    default: '0.350'
+    hide: none
+-   id: phasing
+    label: Phasing Symbols
+    dtype: int
+    default: '20'
+    hide: none
+-   id: sps
+    label: Samps per Symb
+    dtype: int
+    default: '2'
+    hide: none
+
+inputs:
+-   label: sdu
+    domain: message
+    dtype: message
+    optional: true
+
+outputs:
+-   label: iq
+    dtype: complex
+    vlen: 1
+-   label: burst
+    dtype: complex
+    vlen: 1
+    optional: true
+-   label: symbols
+    dtype: complex
+    vlen: 1
+    optional: true
+
+templates:
+    imports: 'from phy_tx import phy_tx  # grc-generated hier_block'
+    make: "phy_tx(\n    excess_bw=${ excess_bw },\n    phasing=${ phasing },\n   \
+        \ sps=${ sps },\n)"
+    callbacks:
+    - set_excess_bw(${ excess_bw })
+    - set_phasing(${ phasing })
+    - set_sps(${ sps })
+
+documentation: /home/gjbradford/code/gnuradio/gr/gr-cdc/examples/phy_tx.py
+grc_source: /home/gjbradford/code/gnuradio/gr/gr-cdc/examples/cdc_phy_tx.grc
+
+file_format: 1
diff --git a/grc/cdc_preamble_detect_cc.block.yml b/grc/cdc_preamble_detect_cc.block.yml
new file mode 100644
index 0000000000000000000000000000000000000000..b56910479e0b5d38dc0aa63e40d799b71aa8254c
--- /dev/null
+++ b/grc/cdc_preamble_detect_cc.block.yml
@@ -0,0 +1,35 @@
+id: cdc_preamble_detect_cc
+label: Preamble Detect
+category: '[CDC]'
+
+templates:
+  imports: from gnuradio import cdc
+  make: cdc.preamble_detect_cc(${sequence}, ${threshold}, ${mark_delay})
+
+parameters:
+- id: sequence
+  label: Sequence
+  dtype: complex_vector
+- id: threshold
+  label: Threshold
+  default: '0.5'
+  dtype: float
+- id: mark_delay
+  label: Mark delay
+  default: '0'
+  dtype: int
+
+inputs:
+- label: in
+  domain: stream
+  dtype: complex
+
+outputs:
+- label: out
+  domain: stream
+  dtype: complex
+- label: out
+  domain: stream
+  dtype: float
+
+file_format: 1
diff --git a/grc/cdc_tag_tx_burst_cc.block.yml b/grc/cdc_tag_tx_burst_cc.block.yml
new file mode 100644
index 0000000000000000000000000000000000000000..9e48dbe21bbf19477d7705a036b597b37a4936d3
--- /dev/null
+++ b/grc/cdc_tag_tx_burst_cc.block.yml
@@ -0,0 +1,29 @@
+id: cdc_tag_tx_burst_cc
+label: Tag Tx Burst
+category: '[CDC]'
+
+templates:
+  imports: from gnuradio import cdc
+  make: cdc.tag_tx_burst_cc(${lengthtagname}, ${scalar})
+
+parameters:
+- id: lengthtagname
+  label: Length tag name
+  dtype: string
+  default: 'packet_len'
+- id: scalar
+  label: Scalar
+  dtype: int
+  default: 
+
+inputs:
+- label: in
+  domain: stream
+  dtype: complex
+
+outputs:
+- label: out
+  domain: stream
+  dtype: complex
+
+file_format: 1
diff --git a/include/gnuradio/cdc/CMakeLists.txt b/include/gnuradio/cdc/CMakeLists.txt
index 864df4f841a39a4a1ef6051922c69d8a9a967f94..75345f8917ac7f03559dc9a6e7902775d0c975de 100644
--- a/include/gnuradio/cdc/CMakeLists.txt
+++ b/include/gnuradio/cdc/CMakeLists.txt
@@ -11,5 +11,6 @@
 ########################################################################
 install(FILES
     api.h
-    DESTINATION include/gnuradio/cdc
+    tag_tx_burst_cc.h
+    preamble_detect_cc.h DESTINATION include/gnuradio/cdc
 )
diff --git a/include/gnuradio/cdc/preamble_detect_cc.h b/include/gnuradio/cdc/preamble_detect_cc.h
new file mode 100644
index 0000000000000000000000000000000000000000..6e9cda4b6831d59d8c839ffe15c06f18731b0c76
--- /dev/null
+++ b/include/gnuradio/cdc/preamble_detect_cc.h
@@ -0,0 +1,43 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2023 University of Melbourne.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#ifndef INCLUDED_CDC_PREAMBLE_DETECT_CC_H
+#define INCLUDED_CDC_PREAMBLE_DETECT_CC_H
+
+#include <gnuradio/cdc/api.h>
+#include <gnuradio/sync_block.h>
+
+namespace gr {
+namespace cdc {
+
+/*!
+ * \brief <+description of block+>
+ * \ingroup cdc
+ *
+ */
+class CDC_API preamble_detect_cc : virtual public gr::sync_block {
+public:
+    typedef std::shared_ptr<preamble_detect_cc> sptr;
+
+    static sptr make(const std::vector<gr_complex>& sequence,
+                     float threshold = 0.5,
+                     unsigned int mark_delay = 0);
+
+    virtual std::vector<gr_complex> sequence() const = 0;
+    virtual void set_sequence(const std::vector<gr_complex>& sequence) = 0;
+
+    virtual float threshold() const = 0;
+    virtual void set_threshold(float threshold) = 0;
+
+    virtual unsigned int mark_delay(void) const = 0;
+    virtual void set_mark_delay(unsigned int mark_delay) = 0;
+};
+
+} // namespace cdc
+} // namespace gr
+
+#endif /* INCLUDED_CDC_PREAMBLE_DETECT_CC_H */
diff --git a/include/gnuradio/cdc/tag_tx_burst_cc.h b/include/gnuradio/cdc/tag_tx_burst_cc.h
new file mode 100644
index 0000000000000000000000000000000000000000..c5499f382491984435d5d21c43e6f61d1a18dd97
--- /dev/null
+++ b/include/gnuradio/cdc/tag_tx_burst_cc.h
@@ -0,0 +1,34 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2023 University of Melbourne.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#ifndef INCLUDED_CDC_TAG_TX_BURST_CC_H
+#define INCLUDED_CDC_TAG_TX_BURST_CC_H
+
+#include <gnuradio/cdc/api.h>
+#include <gnuradio/sync_block.h>
+
+namespace gr {
+namespace cdc {
+
+/*!
+ * \brief <+description of block+>
+ * \ingroup cdc
+ *
+ */
+class CDC_API tag_tx_burst_cc : virtual public gr::sync_block
+{
+public:
+    typedef std::shared_ptr<tag_tx_burst_cc> sptr;
+
+    static sptr make(const std::string &lengthtagname,
+                     int scalar);
+};
+
+} // namespace cdc
+} // namespace gr
+
+#endif /* INCLUDED_CDC_TAG_TX_BURST_CC_H */
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 77cfc1ecf2430bb3ca79afb3ed5d82d6609beba3..3028ecff7ded67488521408cb7b003b4d0f90a33 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -12,6 +12,8 @@
 include(GrPlatform) #define LIB_SUFFIX
 
 list(APPEND cdc_sources
+    tag_tx_burst_cc_impl.cc
+    preamble_detect_cc_impl.cc
 )
 
 set(cdc_sources "${cdc_sources}" PARENT_SCOPE)
@@ -21,7 +23,7 @@ if(NOT cdc_sources)
 endif(NOT cdc_sources)
 
 add_library(gnuradio-cdc SHARED ${cdc_sources})
-target_link_libraries(gnuradio-cdc gnuradio::gnuradio-runtime)
+target_link_libraries(gnuradio-cdc gnuradio::gnuradio-runtime gnuradio-filter)
 target_include_directories(gnuradio-cdc
     PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>
     PUBLIC $<INSTALL_INTERFACE:include>
diff --git a/lib/preamble_detect_cc_impl.cc b/lib/preamble_detect_cc_impl.cc
new file mode 100644
index 0000000000000000000000000000000000000000..d00f47e63cc83e8966ae1128c8868748016bf536
--- /dev/null
+++ b/lib/preamble_detect_cc_impl.cc
@@ -0,0 +1,207 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2023 University of Melbourne.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#include "preamble_detect_cc_impl.h"
+#include <gnuradio/io_signature.h>
+#include <gnuradio/math.h>
+
+
+namespace gr {
+namespace cdc {
+
+preamble_detect_cc::sptr preamble_detect_cc::make(const std::vector<gr_complex>& sequence,
+                                                  float threshold,
+                                                  unsigned int mark_delay)
+{
+    return gnuradio::make_block_sptr<preamble_detect_cc_impl>(
+        sequence, threshold, mark_delay);
+}
+
+preamble_detect_cc_impl::preamble_detect_cc_impl(const std::vector<gr_complex>& sequence,
+                                                 float threshold,
+                                                 unsigned int mark_delay)
+    : gr::sync_block("preamble_detect_cc",
+                     gr::io_signature::make(1, 1, sizeof(gr_complex)),
+                     gr::io_signature::make2(1, 2, sizeof(gr_complex), sizeof(float))),
+      d_src_id(pmt::intern(alias())),
+      d_sequence(sequence.size()),
+      d_threshold(threshold),
+      d_mark_delay(mark_delay),
+      d_filter(1, sequence),
+      d_corr(s_nitems),
+      d_corr_mag(s_nitems),
+      d_y_mag(s_nitems + sequence.size()),
+      d_y_accum(0.0),
+      d_skip(0)
+{
+    set_max_noutput_items(s_nitems);
+    set_sequence(sequence);
+}
+
+preamble_detect_cc_impl::~preamble_detect_cc_impl() {}
+
+std::vector<gr_complex> preamble_detect_cc_impl::sequence() const
+{
+    return d_sequence;
+}
+
+void preamble_detect_cc_impl::set_sequence(const std::vector<gr_complex>& sequence)
+{
+    gr::thread::scoped_lock lock(d_setlock);
+
+    d_sequence = sequence;
+
+    // create time-reversed conjugate of training sequence for filtering
+    std::vector<gr_complex> taps(sequence.size());
+    std::reverse_copy(sequence.begin(), sequence.end(), taps.begin()); 
+    d_scale = 0.0;
+    for (size_t i = 0; i < taps.size(); i++) {
+        taps[i] = std::conj(taps[i]);
+        d_scale += std::norm(taps[i]);
+    }
+    d_scale = 1.0 / sqrt(d_scale);
+    for (size_t i = 0; i < taps.size(); i++) {
+        taps[i] *= d_scale;
+    }
+
+    // set taps and block output multiple to FFT kernel's internal nsamples
+    const int nsamples = d_filter.set_taps(taps);
+    set_output_multiple(nsamples);
+
+    // keep a history of the length of the sync word to delay for tagging
+    set_history(d_sequence.size());
+    declare_sample_delay(0, sequence.size());
+    declare_sample_delay(1, 0);
+}
+
+float preamble_detect_cc_impl::threshold() const
+{
+    return d_threshold;
+}
+
+void preamble_detect_cc_impl::set_threshold(float threshold)
+{
+    gr::thread::scoped_lock lock(d_setlock);
+    d_threshold = threshold;
+}
+
+unsigned int preamble_detect_cc_impl::mark_delay() const
+{
+    return d_mark_delay;
+}
+
+void preamble_detect_cc_impl::set_mark_delay(unsigned int mark_delay)
+{
+    gr::thread::scoped_lock lock(d_setlock);
+    d_mark_delay = mark_delay;
+}
+
+int preamble_detect_cc_impl::work(int noutput_items,
+                                  gr_vector_const_void_star& input_items,
+                                  gr_vector_void_star& output_items)
+{
+    auto in = static_cast<const gr_complex*>(input_items[0]);
+    auto out = static_cast<gr_complex*>(output_items[0]);
+
+    float* corr_mag;
+    if (output_items.size() > 1) {
+        corr_mag = static_cast<float*>(output_items[1]);
+    } else {
+        corr_mag = d_corr_mag.data();
+    }
+
+    unsigned int hist_len = history() - 1;
+
+    float threshold;
+    {
+        gr::thread::scoped_lock lock(d_setlock);
+        threshold = d_threshold;
+    }
+
+    // correlate input samples with training sequence
+    d_filter.filter(noutput_items, &in[hist_len], d_corr.data());
+
+    // calculate squared magnitude of correlation result
+    volk_32fc_magnitude_squared_32f(corr_mag, d_corr.data(), noutput_items);
+
+    // calculate squared magnitued of input samples for normalization
+    volk_32fc_magnitude_squared_32f(d_y_mag.data(), in, noutput_items + hist_len);
+    
+    // initialize moving average filter
+    d_y_accum = 0;
+    for (int i = 0; i < hist_len; i++) {
+        d_y_accum += d_y_mag[i]; 
+    }
+
+    // search for correlation peaks above threshold
+    for (int i = 0; i < noutput_items; i++) {
+        // add sample to moving average
+        d_y_accum += d_y_mag[hist_len + i];
+
+        // normalize cross-correlation
+        corr_mag[i] /= d_y_accum;
+
+        // drop oldest sample from moving average
+        d_y_accum -= d_y_mag[i]; 
+
+        if (d_skip > 0) {
+            d_skip--;
+            continue;
+        }
+
+        if (corr_mag[i] > threshold) {
+            // single-tap (inverse) channel estimate
+            gr_complex chan_est = d_corr[i] * d_scale;
+            double amp_est = 1.0 / std::abs(chan_est);
+            double phase_est = std::arg(chan_est);
+            
+            // time phase estimate - center-of-mass (3 samples)
+            float m1 = corr_mag[i-1];
+            float m2 = corr_mag[i+0];
+            float m3 = corr_mag[i+1] / (d_y_accum + d_y_mag[hist_len+i+1]);
+            double nom = m1 + 2*m2 + 3*m3;
+            double den = m1 + m2 + m3;
+            double time_est = (nom/den) - 2.0;
+
+            // tag output
+            int offset = nitems_written(0) + i;
+            for (unsigned int ch = 0; ch < output_items.size(); ch++) {
+                add_item_tag(ch, offset,
+                             pmt::intern("corr_start"),
+                             pmt::from_double(corr_mag[i]),
+                             d_src_id);
+                add_item_tag(ch, offset + d_mark_delay,
+                             pmt::intern("corr_est"),
+                             pmt::from_double(corr_mag[i]),
+                             d_src_id);
+                add_item_tag(ch, offset + d_mark_delay,
+                             pmt::intern("amp_est"),
+                             pmt::from_complex(amp_est),
+                             d_src_id);
+                add_item_tag(ch, offset + d_mark_delay,
+                             pmt::intern("phase_est"), // reset Costas Loop to zero phase
+                             pmt::from_double(phase_est),
+                             d_src_id);
+                add_item_tag(ch, offset + d_mark_delay,
+                             pmt::intern("time_est"),
+                             pmt::from_double(time_est),
+                             d_src_id);
+            }
+
+            // skip remaining symbols in sequence
+            d_skip = d_sequence.size() - 1;
+        }
+    }
+
+    // pass through input samples but with delay of history()
+    memcpy(out, &in[0], sizeof(gr_complex)*noutput_items);
+
+    return noutput_items;
+}
+
+} /* namespace cdc */
+} /* namespace gr */
diff --git a/lib/preamble_detect_cc_impl.h b/lib/preamble_detect_cc_impl.h
new file mode 100644
index 0000000000000000000000000000000000000000..9177a346802d20d8409cbc78287a6034b6c4727e
--- /dev/null
+++ b/lib/preamble_detect_cc_impl.h
@@ -0,0 +1,60 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2023 University of Melbourne.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#ifndef INCLUDED_CDC_PREAMBLE_DETECT_CC_IMPL_H
+#define INCLUDED_CDC_PREAMBLE_DETECT_CC_IMPL_H
+
+#include <gnuradio/cdc/preamble_detect_cc.h>
+#include <gnuradio/filter/fft_filter.h>
+
+using namespace gr::filter;
+
+namespace gr {
+namespace cdc {
+
+class preamble_detect_cc_impl : public preamble_detect_cc {
+private:
+    pmt::pmt_t d_src_id;
+
+    std::vector<gr_complex> d_sequence;
+    float d_threshold;
+    unsigned int d_mark_delay;
+
+    kernel::fft_filter_ccc d_filter;
+    volk::vector<gr_complex> d_corr;
+    volk::vector<float> d_corr_mag;
+    volk::vector<float> d_y_mag;
+    float d_scale;
+    float d_y_accum;
+    int d_skip;
+
+    static constexpr int s_nitems = 24*1024;
+
+public:
+    preamble_detect_cc_impl(const std::vector<gr_complex> &sequence,
+                            float threshold,
+                            unsigned int mark_delay);
+    ~preamble_detect_cc_impl() override;
+
+    std::vector<gr_complex> sequence() const override;
+    void set_sequence(const std::vector<gr_complex>& sequence) override;
+
+    float threshold() const override;
+    void set_threshold(float threshold) override;
+
+    unsigned int mark_delay() const override;
+    void set_mark_delay(unsigned int mark_delay) override;
+
+    int work(int noutput_items,
+             gr_vector_const_void_star &input_items,
+             gr_vector_void_star &output_items);
+};
+
+} // namespace cdc
+} // namespace gr
+
+#endif /* INCLUDED_CDC_PREAMBLE_DETECT_CC_IMPL_H */
diff --git a/lib/tag_tx_burst_cc_impl.cc b/lib/tag_tx_burst_cc_impl.cc
new file mode 100644
index 0000000000000000000000000000000000000000..d1f36abf32e2b06d691389ffc4d7359a89be3f84
--- /dev/null
+++ b/lib/tag_tx_burst_cc_impl.cc
@@ -0,0 +1,88 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2023 University of Melbourne.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#include "tag_tx_burst_cc_impl.h"
+#include <gnuradio/io_signature.h>
+
+namespace gr {
+namespace cdc {
+
+tag_tx_burst_cc::sptr tag_tx_burst_cc::make(const std::string &lengthtagname,
+                                            int scalar)
+{
+    return gnuradio::make_block_sptr<tag_tx_burst_cc_impl>(
+        lengthtagname, scalar);
+}
+
+tag_tx_burst_cc_impl::tag_tx_burst_cc_impl(const std::string &lengthtagname,
+                                           int scalar)
+    : gr::sync_block(
+          "tag_tx_burst_cc",
+          gr::io_signature::make(1, 1, sizeof(gr_complex)),
+          gr::io_signature::make(1, 1, sizeof(gr_complex))),
+      d_lengthtag(pmt::mp(lengthtagname)),
+      d_scalar(scalar),
+      d_eob_offset(0)
+{
+    set_tag_propagation_policy(TPP_DONT);
+}
+
+tag_tx_burst_cc_impl::~tag_tx_burst_cc_impl() {}
+
+int tag_tx_burst_cc_impl::work(int noutput_items,
+                               gr_vector_const_void_star &input_items,
+                               gr_vector_void_star &output_items) {
+    auto in = static_cast<const gr_complex *>(input_items[0]);
+    auto out = static_cast<gr_complex *>(output_items[0]);
+
+    // copy input samples to output port
+    memcpy(out, in, noutput_items*sizeof(gr_complex));
+
+    // update length tag and add SOB and EOB tags
+    uint64_t offset = nitems_read(0);
+    uint64_t nend = nitems_read(0) + noutput_items;
+    while (offset < nend) {
+        if (d_eob_offset > 0) {
+            if (d_eob_offset < nend) {
+                offset = d_eob_offset;
+                d_eob_offset = 0;
+                
+                add_item_tag(0,
+                             offset,
+                             pmt::mp("tx_eob"),
+                             pmt::PMT_NIL);
+            } else {
+                offset = nend;
+            }
+        } else {
+            // get tags in remaining window
+            std::vector<tag_t> tags;
+            get_tags_in_range(tags, 0, offset, nend, d_lengthtag);
+
+            if (!tags.empty()) {
+                long value = d_scalar * pmt::to_long(tags[0].value);
+                add_item_tag(0,
+                             tags[0].offset,
+                             d_lengthtag,
+                             pmt::from_long(value),
+                             tags[0].srcid);
+                add_item_tag(0,
+                             tags[0].offset,
+                             pmt::mp("tx_sob"),
+                             pmt::PMT_NIL);
+                d_eob_offset = tags[0].offset + value - 1;
+            } else {
+                offset = nend;
+            }
+        }
+    }
+
+    return noutput_items;
+}
+
+} /* namespace cdc */
+} /* namespace gr */
diff --git a/lib/tag_tx_burst_cc_impl.h b/lib/tag_tx_burst_cc_impl.h
new file mode 100644
index 0000000000000000000000000000000000000000..f732351e8f78a54227febffb6675bf49c25e8b9b
--- /dev/null
+++ b/lib/tag_tx_burst_cc_impl.h
@@ -0,0 +1,35 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2023 University of Melbourne.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#ifndef INCLUDED_CDC_TAG_TX_BURST_CC_IMPL_H
+#define INCLUDED_CDC_TAG_TX_BURST_CC_IMPL_H
+
+#include <gnuradio/cdc/tag_tx_burst_cc.h>
+
+namespace gr {
+namespace cdc {
+
+class tag_tx_burst_cc_impl : public tag_tx_burst_cc {
+private:
+    const pmt::pmt_t d_lengthtag;
+    int d_scalar;
+    uint64_t d_eob_offset;
+
+public:
+    tag_tx_burst_cc_impl(const std::string& lengthtagname,
+                         int scalar);
+    ~tag_tx_burst_cc_impl();
+
+    int work(int noutput_items,
+             gr_vector_const_void_star &input_items,
+             gr_vector_void_star &output_items) override;
+};
+
+} // namespace cdc
+} // namespace gr
+
+#endif /* INCLUDED_CDC_TAG_TX_BURST_CC_IMPL_H */
diff --git a/python/cdc/CMakeLists.txt b/python/cdc/CMakeLists.txt
index b7f3145e17e21d04627ac2200752fde58dcede40..858f625febe43e72d51576319034926b81a96f17 100644
--- a/python/cdc/CMakeLists.txt
+++ b/python/cdc/CMakeLists.txt
@@ -22,7 +22,8 @@ add_subdirectory(bindings)
 GR_PYTHON_INSTALL(
     FILES
     __init__.py
-    DESTINATION ${GR_PYTHON_DIR}/gnuradio/cdc
+    phy_tx.py
+    phy_rx.py DESTINATION ${GR_PYTHON_DIR}/gnuradio/cdc
 )
 
 ########################################################################
diff --git a/python/cdc/__init__.py b/python/cdc/__init__.py
index 8271f599c3eb6962efb61429f50b6ec2d303a42b..e08c076c382109aba61b8d1778862ae8fddf1397 100644
--- a/python/cdc/__init__.py
+++ b/python/cdc/__init__.py
@@ -20,4 +20,7 @@ except ModuleNotFoundError:
     pass
 
 # import any pure python here
+from .phy_tx import phy_tx
+from .phy_rx import phy_rx
+
 #
diff --git a/python/cdc/bindings/CMakeLists.txt b/python/cdc/bindings/CMakeLists.txt
index 607a20f93ea348f644015e0dacb7dad7ae5ad34a..e223334924bf41f77e13caff1689de334c9f6e38 100644
--- a/python/cdc/bindings/CMakeLists.txt
+++ b/python/cdc/bindings/CMakeLists.txt
@@ -29,7 +29,8 @@ include(GrPybind)
 ########################################################################
 
 list(APPEND cdc_python_files
-    python_bindings.cc)
+    tag_tx_burst_cc_python.cc
+    preamble_detect_cc_python.cc python_bindings.cc)
 
 GR_PYBIND_MAKE_OOT(cdc
    ../../..
diff --git a/python/cdc/bindings/docstrings/preamble_detect_cc_pydoc_template.h b/python/cdc/bindings/docstrings/preamble_detect_cc_pydoc_template.h
new file mode 100644
index 0000000000000000000000000000000000000000..3043d288b645334e239dce566ede68c6a7bad199
--- /dev/null
+++ b/python/cdc/bindings/docstrings/preamble_detect_cc_pydoc_template.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2023 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+#include "pydoc_macros.h"
+#define D(...) DOC(gr,cdc, __VA_ARGS__ )
+/*
+  This file contains placeholders for docstrings for the Python bindings.
+  Do not edit! These were automatically extracted during the binding process
+  and will be overwritten during the build process
+ */
+
+
+ 
+ static const char *__doc_gr_cdc_preamble_detect_cc = R"doc()doc";
+
+
+ static const char *__doc_gr_cdc_preamble_detect_cc_preamble_detect_cc_0 = R"doc()doc";
+
+
+ static const char *__doc_gr_cdc_preamble_detect_cc_preamble_detect_cc_1 = R"doc()doc";
+
+
+ static const char *__doc_gr_cdc_preamble_detect_cc_make = R"doc()doc";
+
+
+ static const char *__doc_gr_cdc_preamble_detect_cc_sequence = R"doc()doc";
+
+
+ static const char *__doc_gr_cdc_preamble_detect_cc_set_sequence = R"doc()doc";
+
+
+ static const char *__doc_gr_cdc_preamble_detect_cc_threshold = R"doc()doc";
+
+
+ static const char *__doc_gr_cdc_preamble_detect_cc_set_threshold = R"doc()doc";
+
+
+ static const char *__doc_gr_cdc_preamble_detect_cc_mark_delay = R"doc()doc";
+
+
+ static const char *__doc_gr_cdc_preamble_detect_cc_set_mark_delay = R"doc()doc";
+
+  
diff --git a/python/cdc/bindings/docstrings/tag_tx_burst_cc_pydoc_template.h b/python/cdc/bindings/docstrings/tag_tx_burst_cc_pydoc_template.h
new file mode 100644
index 0000000000000000000000000000000000000000..3da5e6f317dac9b85af6bf9fce052b7fc28ffe3b
--- /dev/null
+++ b/python/cdc/bindings/docstrings/tag_tx_burst_cc_pydoc_template.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2023 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+#include "pydoc_macros.h"
+#define D(...) DOC(gr,cdc, __VA_ARGS__ )
+/*
+  This file contains placeholders for docstrings for the Python bindings.
+  Do not edit! These were automatically extracted during the binding process
+  and will be overwritten during the build process
+ */
+
+
+ 
+ static const char *__doc_gr_cdc_tag_tx_burst_cc = R"doc()doc";
+
+
+ static const char *__doc_gr_cdc_tag_tx_burst_cc_tag_tx_burst_cc = R"doc()doc";
+
+
+ static const char *__doc_gr_cdc_tag_tx_burst_cc_make = R"doc()doc";
+
+  
diff --git a/python/cdc/bindings/preamble_detect_cc_python.cc b/python/cdc/bindings/preamble_detect_cc_python.cc
new file mode 100644
index 0000000000000000000000000000000000000000..d468c2cec8d00d56dde29a2b18d495a90082e614
--- /dev/null
+++ b/python/cdc/bindings/preamble_detect_cc_python.cc
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2023 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+
+/***********************************************************************************/
+/* This file is automatically generated using bindtool and can be manually edited  */
+/* The following lines can be configured to regenerate this file during cmake      */
+/* If manual edits are made, the following tags should be modified accordingly.    */
+/* BINDTOOL_GEN_AUTOMATIC(0)                                                       */
+/* BINDTOOL_USE_PYGCCXML(0)                                                        */
+/* BINDTOOL_HEADER_FILE(preamble_detect_cc.h)                                        */
+/* BINDTOOL_HEADER_FILE_HASH(a9266ae8920e7062dd71159aa9a81dbd)                     */
+/***********************************************************************************/
+
+#include <pybind11/complex.h>
+#include <pybind11/pybind11.h>
+#include <pybind11/stl.h>
+
+namespace py = pybind11;
+
+#include <gnuradio/cdc/preamble_detect_cc.h>
+// pydoc.h is automatically generated in the build directory
+#include <preamble_detect_cc_pydoc.h>
+
+void bind_preamble_detect_cc(py::module& m)
+{
+
+    using preamble_detect_cc    = ::gr::cdc::preamble_detect_cc;
+
+
+    py::class_<preamble_detect_cc, gr::sync_block, gr::block, gr::basic_block,
+        std::shared_ptr<preamble_detect_cc>>(m, "preamble_detect_cc", D(preamble_detect_cc))
+
+        .def(py::init(&preamble_detect_cc::make),
+           py::arg("sequence"),
+           py::arg("threshold") = 0.5,
+           py::arg("mark_delay") = 0,
+           D(preamble_detect_cc,make)
+        )
+        
+
+
+
+
+        
+        .def("sequence",&preamble_detect_cc::sequence,       
+            D(preamble_detect_cc,sequence)
+        )
+
+
+        
+        .def("set_sequence",&preamble_detect_cc::set_sequence,       
+            py::arg("sequence"),
+            D(preamble_detect_cc,set_sequence)
+        )
+
+
+        
+        .def("threshold",&preamble_detect_cc::threshold,       
+            D(preamble_detect_cc,threshold)
+        )
+
+
+        
+        .def("set_threshold",&preamble_detect_cc::set_threshold,       
+            py::arg("threshold"),
+            D(preamble_detect_cc,set_threshold)
+        )
+
+
+        
+        .def("mark_delay",&preamble_detect_cc::mark_delay,       
+            D(preamble_detect_cc,mark_delay)
+        )
+
+
+        
+        .def("set_mark_delay",&preamble_detect_cc::set_mark_delay,       
+            py::arg("mark_delay"),
+            D(preamble_detect_cc,set_mark_delay)
+        )
+
+        ;
+
+
+
+
+}
+
+
+
+
+
+
+
+
diff --git a/python/cdc/bindings/python_bindings.cc b/python/cdc/bindings/python_bindings.cc
index 3e8d87ca128146499ffa16fa9eedd83766ee7579..914900bfbe15652e06bbcb6ee32c960f36b652c6 100644
--- a/python/cdc/bindings/python_bindings.cc
+++ b/python/cdc/bindings/python_bindings.cc
@@ -21,6 +21,8 @@ namespace py = pybind11;
 // Please do not delete
 /**************************************/
 // BINDING_FUNCTION_PROTOTYPES(
+    void bind_tag_tx_burst_cc(py::module& m);
+    void bind_preamble_detect_cc(py::module& m);
 // ) END BINDING_FUNCTION_PROTOTYPES
 
 
@@ -49,5 +51,7 @@ PYBIND11_MODULE(cdc_python, m)
     // Please do not delete
     /**************************************/
     // BINDING_FUNCTION_CALLS(
+    bind_tag_tx_burst_cc(m);
+    bind_preamble_detect_cc(m);
     // ) END BINDING_FUNCTION_CALLS
-}
+}
\ No newline at end of file
diff --git a/python/cdc/bindings/tag_tx_burst_cc_python.cc b/python/cdc/bindings/tag_tx_burst_cc_python.cc
new file mode 100644
index 0000000000000000000000000000000000000000..cef6787f14026ab93cb336ad14b36a3dfddc778c
--- /dev/null
+++ b/python/cdc/bindings/tag_tx_burst_cc_python.cc
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2023 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+
+/***********************************************************************************/
+/* This file is automatically generated using bindtool and can be manually edited  */
+/* The following lines can be configured to regenerate this file during cmake      */
+/* If manual edits are made, the following tags should be modified accordingly.    */
+/* BINDTOOL_GEN_AUTOMATIC(0)                                                       */
+/* BINDTOOL_USE_PYGCCXML(0)                                                        */
+/* BINDTOOL_HEADER_FILE(tag_tx_burst_cc.h)                                        */
+/* BINDTOOL_HEADER_FILE_HASH(82ed4da9bc2a218e814737e1f7643ca7)                     */
+/***********************************************************************************/
+
+#include <pybind11/complex.h>
+#include <pybind11/pybind11.h>
+#include <pybind11/stl.h>
+
+namespace py = pybind11;
+
+#include <gnuradio/cdc/tag_tx_burst_cc.h>
+// pydoc.h is automatically generated in the build directory
+#include <tag_tx_burst_cc_pydoc.h>
+
+void bind_tag_tx_burst_cc(py::module& m)
+{
+
+    using tag_tx_burst_cc    = ::gr::cdc::tag_tx_burst_cc;
+
+
+    py::class_<tag_tx_burst_cc, gr::sync_block, gr::block, gr::basic_block,
+        std::shared_ptr<tag_tx_burst_cc>>(m, "tag_tx_burst_cc", D(tag_tx_burst_cc))
+
+        .def(py::init(&tag_tx_burst_cc::make),
+           py::arg("lengthtagname"),
+           py::arg("scalar"),
+           D(tag_tx_burst_cc,make)
+        )
+        
+
+
+
+        ;
+
+
+
+
+}
+
+
+
+
+
+
+
+
diff --git a/python/cdc/phy_rx.py b/python/cdc/phy_rx.py
new file mode 100644
index 0000000000000000000000000000000000000000..7d08049e426b4d01fc6baf058e7734b0b39d93c6
--- /dev/null
+++ b/python/cdc/phy_rx.py
@@ -0,0 +1,138 @@
+# -*- coding: utf-8 -*-
+
+#
+# SPDX-License-Identifier: GPL-3.0
+#
+# GNU Radio Python Flow Graph
+# Title: CDC PHY Rx
+# Copyright: University of Melbourne
+# GNU Radio version: 3.10.1.1
+
+from gnuradio import blocks
+from gnuradio import cdc
+from gnuradio import digital
+from gnuradio import filter
+from gnuradio import gr
+from gnuradio.filter import firdes
+from gnuradio.fft import window
+import sys
+import signal
+from gnuradio import gr, pdu
+import numpy as np
+
+
+
+
+
+
+
+class phy_rx(gr.hier_block2):
+    def __init__(self, excess_bw=0.350, sps=2):
+        gr.hier_block2.__init__(
+            self, "CDC PHY Rx",
+                gr.io_signature(1, 1, gr.sizeof_gr_complex*1),
+                gr.io_signature.makev(5, 5, [gr.sizeof_gr_complex*1, gr.sizeof_gr_complex*1, gr.sizeof_char*1, gr.sizeof_float*1, gr.sizeof_gr_complex*1]),
+        )
+        self.message_port_register_hier_out("pdu")
+
+        ##################################################
+        # Parameters
+        ##################################################
+        self.excess_bw = excess_bw
+        self.sps = sps
+
+        ##################################################
+        # Variables
+        ##################################################
+        self.nfilts = nfilts = 32
+        self.rrc_taps = rrc_taps = firdes.root_raised_cosine(nfilts, sps*nfilts,1.0, excess_bw, 11*sps*nfilts)
+        self.modulated_sync_word = modulated_sync_word = np.array([ 6.3415498e-01+0.j, -8.2522854e-02+0.j, -6.7432624e-01+0.j, 2.1960361e-02+0.j,  6.6994393e-01+0.j,  2.7926212e-02+0.j, -6.2773204e-01+0.j, -1.6468078e-01+0.j,  5.7718420e-01+0.j, 7.2756535e-01+0.j,  4.6373290e-01+0.j,  2.3871353e-02+0.j, -4.8910391e-01+0.j, -7.3612314e-01+0.j, -4.8162562e-01+0.j, 1.2282493e-02+0.j,  4.6576929e-01+0.j,  7.3573601e-01+0.j, 5.4807413e-01+0.j, -1.3198391e-01+0.j, -5.6807721e-01+0.j, -1.1599341e-01+0.j,  6.0297143e-01+0.j,  6.1259979e-01+0.j, 3.7387580e-01+0.j,  6.1534089e-01+0.j,  6.1044985e-01+0.j, -1.3032347e-01+0.j, -5.7351917e-01+0.j, -1.1359498e-01+0.j, 5.1318854e-01+0.j,  7.6605660e-01+0.j,  5.5351597e-01+0.j, -1.7184576e-01+0.j, -6.0304552e-01+0.j, -5.2386895e-09+0.j, 6.0304564e-01+0.j,  1.7458701e-01+0.j, -5.4603779e-01+0.j, -7.7764541e-01+0.j, -5.1115209e-01+0.j,  1.2587748e-01+0.j, 5.5562639e-01+0.j,  1.4426640e-01+0.j, -5.5147964e-01+0.j, -7.4326605e-01+0.j, -4.9114031e-01+0.j,  2.7579335e-02+0.j, 5.3652304e-01+0.j,  5.9185678e-01+0.j,  4.3005973e-01+0.j, 5.5639654e-01+0.j,  5.7140875e-01+0.j,  1.4330061e-02+0.j, -5.7344508e-01+0.j, -5.8026785e-01+0.j, -4.0265229e-01+0.j, -6.0784715e-01+0.j, -6.1882788e-01+0.j,  1.3541880e-01+0.j, 6.3996756e-01+0.j, -1.1588858e-02+0.j, -6.3045293e-01+0.j, -1.2313626e-01+0.j,  5.9345692e-01+0.j,  6.3337904e-01+0.j, 4.5958614e-01+0.j,  4.4280154e-01+0.j,  4.8155165e-01+0.j, 6.0579962e-01+0.j,  5.2610868e-01+0.j,  2.5531810e-02+0.j, -4.9454585e-01+0.j, -7.3372471e-01+0.j, -5.7140863e-01+0.j, 1.6025695e-01+0.j,  6.3045293e-01+0.j, -2.2790564e-02+0.j, -6.5453744e-01+0.j, -4.3920707e-02+0.j,  6.6330218e-01+0.j, 1.3472509e-01+0.j, -6.3582081e-01+0.j, -5.8741081e-01+0.j, -4.1216698e-01+0.j, -5.9255040e-01+0.j, -5.4807413e-01+0.j, -1.3942933e-02+0.j,  5.0699669e-01+0.j,  7.0545167e-01+0.j, 5.1991683e-01+0.j, -3.5073120e-02+0.j, -5.2814502e-01+0.j, -5.9695208e-01+0.j, -4.9650821e-01+0.j, -4.3669510e-01+0.j, -4.6910083e-01+0.j, -6.3407266e-01+0.j, -5.7760048e-01+0.j, 9.9652052e-02+0.j,  5.9685379e-01+0.j,  1.1398210e-01+0.j, -5.7963693e-01+0.j, -6.4087272e-01+0.j, -4.3625149e-01+0.j, -4.7107458e-01+0.j, -5.4392737e-01+0.j, -4.6153325e-01+0.j, -4.5958611e-01+0.j, -6.1738855e-01+0.j, -5.3855950e-01+0.j, 2.7412227e-03+0.j,  5.4603767e-01+0.j,  6.0305846e-01+0.j, 4.5414424e-01+0.j,  4.7992218e-01+0.j,  5.0904173e-01+0.j, 4.9728334e-01+0.j,  5.1278079e-01+0.j,  4.7549835e-01+0.j, 4.5890158e-01+0.j,  6.0340530e-01+0.j,  5.3810960e-01+0.j, 1.3112724e-02+0.j, -5.2549899e-01+0.j, -6.6004950e-01+0.j, -4.8329139e-01+0.j, -2.2242454e-01+0.j], dtype=np.complex64)
+        self.constel = constel = digital.constellation_bpsk().base()
+
+        ##################################################
+        # Blocks
+        ##################################################
+        self.pdu_tagged_stream_to_pdu_0 = pdu.tagged_stream_to_pdu(gr.types.byte_t, 'packet_len')
+        self.digital_symbol_sync_xx_0 = digital.symbol_sync_cc(
+            digital.TED_EARLY_LATE,
+            sps,
+            0.045/2,
+            1.0,
+            1.0,
+            1.5,
+            1,
+            digital.constellation_bpsk().base(),
+            digital.IR_PFB_MF,
+            nfilts,
+            rrc_taps)
+        self.digital_crc32_async_bb_0 = digital.crc32_async_bb(True)
+        self.digital_costas_loop_cc_0 = digital.costas_loop_cc(0.035, constel.arity(), False)
+        self.digital_correlate_access_code_xx_ts_0 = digital.correlate_access_code_bb_ts(digital.packet_utils.default_access_code,
+          3, 'packet_len')
+        self.digital_constellation_decoder_cb_0 = digital.constellation_decoder_cb(constel)
+        self.digital_additive_scrambler_bb_0 = digital.additive_scrambler_bb(0x8A, 0x7F, 7, count=0, bits_per_byte=8, reset_tag_key="packet_len")
+        self.cdc_preamble_detect_cc_0 = cdc.preamble_detect_cc(modulated_sync_word, 0.5, 0)
+        self.blocks_repack_bits_bb_0 = blocks.repack_bits_bb(constel.bits_per_symbol(), 8, "packet_len", True, gr.GR_MSB_FIRST)
+        self.blocks_multiply_by_tag_value_cc_0 = blocks.multiply_by_tag_value_cc('amp_est', 1)
+
+
+        ##################################################
+        # Connections
+        ##################################################
+        self.msg_connect((self.digital_crc32_async_bb_0, 'out'), (self, 'pdu'))
+        self.msg_connect((self.pdu_tagged_stream_to_pdu_0, 'pdus'), (self.digital_crc32_async_bb_0, 'in'))
+        self.connect((self.blocks_multiply_by_tag_value_cc_0, 0), (self.digital_symbol_sync_xx_0, 0))
+        self.connect((self.blocks_multiply_by_tag_value_cc_0, 0), (self, 4))
+        self.connect((self.blocks_repack_bits_bb_0, 0), (self.digital_additive_scrambler_bb_0, 0))
+        self.connect((self.cdc_preamble_detect_cc_0, 0), (self.blocks_multiply_by_tag_value_cc_0, 0))
+        self.connect((self.cdc_preamble_detect_cc_0, 1), (self, 3))
+        self.connect((self.digital_additive_scrambler_bb_0, 0), (self, 2))
+        self.connect((self.digital_additive_scrambler_bb_0, 0), (self.pdu_tagged_stream_to_pdu_0, 0))
+        self.connect((self.digital_constellation_decoder_cb_0, 0), (self.digital_correlate_access_code_xx_ts_0, 0))
+        self.connect((self.digital_correlate_access_code_xx_ts_0, 0), (self.blocks_repack_bits_bb_0, 0))
+        self.connect((self.digital_costas_loop_cc_0, 0), (self.digital_constellation_decoder_cb_0, 0))
+        self.connect((self.digital_costas_loop_cc_0, 0), (self, 1))
+        self.connect((self.digital_symbol_sync_xx_0, 0), (self.digital_costas_loop_cc_0, 0))
+        self.connect((self.digital_symbol_sync_xx_0, 0), (self, 0))
+        self.connect((self, 0), (self.cdc_preamble_detect_cc_0, 0))
+
+
+    def get_excess_bw(self):
+        return self.excess_bw
+
+    def set_excess_bw(self, excess_bw):
+        self.excess_bw = excess_bw
+        self.set_rrc_taps(firdes.root_raised_cosine(self.nfilts, self.sps*self.nfilts, 1.0, self.excess_bw, 11*self.sps*self.nfilts))
+
+    def get_sps(self):
+        return self.sps
+
+    def set_sps(self, sps):
+        self.sps = sps
+        self.set_rrc_taps(firdes.root_raised_cosine(self.nfilts, self.sps*self.nfilts, 1.0, self.excess_bw, 11*self.sps*self.nfilts))
+
+    def get_nfilts(self):
+        return self.nfilts
+
+    def set_nfilts(self, nfilts):
+        self.nfilts = nfilts
+        self.set_rrc_taps(firdes.root_raised_cosine(self.nfilts, self.sps*self.nfilts, 1.0, self.excess_bw, 11*self.sps*self.nfilts))
+
+    def get_rrc_taps(self):
+        return self.rrc_taps
+
+    def set_rrc_taps(self, rrc_taps):
+        self.rrc_taps = rrc_taps
+
+    def get_modulated_sync_word(self):
+        return self.modulated_sync_word
+
+    def set_modulated_sync_word(self, modulated_sync_word):
+        self.modulated_sync_word = modulated_sync_word
+
+    def get_constel(self):
+        return self.constel
+
+    def set_constel(self, constel):
+        self.constel = constel
+
diff --git a/python/cdc/phy_tx.py b/python/cdc/phy_tx.py
new file mode 100644
index 0000000000000000000000000000000000000000..dbcbb99fc82cfc9158aa65267c855406482aea36
--- /dev/null
+++ b/python/cdc/phy_tx.py
@@ -0,0 +1,139 @@
+# -*- coding: utf-8 -*-
+
+#
+# SPDX-License-Identifier: GPL-3.0
+#
+# GNU Radio Python Flow Graph
+# Title: CDC PHY Tx
+# Copyright: University of Melbourne
+# GNU Radio version: 3.10.1.1
+
+from gnuradio import blocks
+from gnuradio import cdc
+from gnuradio import digital
+from gnuradio import filter
+from gnuradio.filter import firdes
+from gnuradio import gr
+from gnuradio.fft import window
+import sys
+import signal
+from gnuradio import gr, pdu
+
+
+
+
+
+
+
+class phy_tx(gr.hier_block2):
+    def __init__(self, excess_bw=0.350, phasing=20, sps=2):
+        gr.hier_block2.__init__(
+            self, "CDC PHY Tx",
+                gr.io_signature(0, 0, 0),
+                gr.io_signature.makev(3, 3, [gr.sizeof_gr_complex*1, gr.sizeof_gr_complex*1, gr.sizeof_gr_complex*1]),
+        )
+        self.message_port_register_hier_in("sdu")
+
+        ##################################################
+        # Parameters
+        ##################################################
+        self.excess_bw = excess_bw
+        self.phasing = phasing
+        self.sps = sps
+
+        ##################################################
+        # Variables
+        ##################################################
+        self.constel = constel = digital.constellation_bpsk().base()
+        self.access_code = access_code = digital.packet_utils.default_access_code
+        self.num_taps = num_taps = 11*sps
+        self.header_format = header_format = digital.header_format_default(access_code, 0, constel.bits_per_symbol())
+
+        ##################################################
+        # Blocks
+        ##################################################
+        self.root_raised_cosine_filter_0 = filter.interp_fir_filter_ccf(
+            sps,
+            firdes.root_raised_cosine(
+                1.0,
+                sps,
+                1.0,
+                excess_bw,
+                num_taps))
+        self.pdu_pdu_to_tagged_stream_0 = pdu.pdu_to_tagged_stream(gr.types.byte_t, 'packet_len')
+        self.digital_protocol_formatter_bb_0 = digital.protocol_formatter_bb(header_format, "packet_len")
+        self.digital_crc32_async_bb_0 = digital.crc32_async_bb(False)
+        self.digital_chunks_to_symbols_xx_0 = digital.chunks_to_symbols_bc(constel.points(), 1)
+        self.digital_burst_shaper_xx_0 = digital.burst_shaper_cc(firdes.window(window.WIN_HANN, phasing, 0), 0, num_taps//2, True, "packet_len")
+        self.digital_additive_scrambler_bb_0 = digital.additive_scrambler_bb(0x8A, 0x7F, 7, count=0, bits_per_byte=8, reset_tag_key="packet_len")
+        self.cdc_tag_tx_burst_cc_0 = cdc.tag_tx_burst_cc('packet_len', sps)
+        self.blocks_tagged_stream_mux_0 = blocks.tagged_stream_mux(gr.sizeof_char*1, 'packet_len', 0)
+        self.blocks_repack_bits_bb_0 = blocks.repack_bits_bb(8, constel.bits_per_symbol(), "packet_len", False, gr.GR_MSB_FIRST)
+
+
+        ##################################################
+        # Connections
+        ##################################################
+        self.msg_connect((self.digital_crc32_async_bb_0, 'out'), (self.pdu_pdu_to_tagged_stream_0, 'pdus'))
+        self.msg_connect((self, 'sdu'), (self.digital_crc32_async_bb_0, 'in'))
+        self.connect((self.blocks_repack_bits_bb_0, 0), (self.digital_chunks_to_symbols_xx_0, 0))
+        self.connect((self.blocks_tagged_stream_mux_0, 0), (self.blocks_repack_bits_bb_0, 0))
+        self.connect((self.cdc_tag_tx_burst_cc_0, 0), (self, 0))
+        self.connect((self.digital_additive_scrambler_bb_0, 0), (self.blocks_tagged_stream_mux_0, 1))
+        self.connect((self.digital_additive_scrambler_bb_0, 0), (self.digital_protocol_formatter_bb_0, 0))
+        self.connect((self.digital_burst_shaper_xx_0, 0), (self, 1))
+        self.connect((self.digital_burst_shaper_xx_0, 0), (self.root_raised_cosine_filter_0, 0))
+        self.connect((self.digital_chunks_to_symbols_xx_0, 0), (self.digital_burst_shaper_xx_0, 0))
+        self.connect((self.digital_chunks_to_symbols_xx_0, 0), (self, 2))
+        self.connect((self.digital_protocol_formatter_bb_0, 0), (self.blocks_tagged_stream_mux_0, 0))
+        self.connect((self.pdu_pdu_to_tagged_stream_0, 0), (self.digital_additive_scrambler_bb_0, 0))
+        self.connect((self.root_raised_cosine_filter_0, 0), (self.cdc_tag_tx_burst_cc_0, 0))
+
+
+    def get_excess_bw(self):
+        return self.excess_bw
+
+    def set_excess_bw(self, excess_bw):
+        self.excess_bw = excess_bw
+        self.root_raised_cosine_filter_0.set_taps(firdes.root_raised_cosine(1.0, self.sps, 1.0, self.excess_bw, self.num_taps))
+
+    def get_phasing(self):
+        return self.phasing
+
+    def set_phasing(self, phasing):
+        self.phasing = phasing
+
+    def get_sps(self):
+        return self.sps
+
+    def set_sps(self, sps):
+        self.sps = sps
+        self.set_num_taps(11*self.sps)
+        self.root_raised_cosine_filter_0.set_taps(firdes.root_raised_cosine(1.0, self.sps, 1.0, self.excess_bw, self.num_taps))
+
+    def get_constel(self):
+        return self.constel
+
+    def set_constel(self, constel):
+        self.constel = constel
+
+    def get_access_code(self):
+        return self.access_code
+
+    def set_access_code(self, access_code):
+        self.access_code = access_code
+        self.set_header_format(digital.header_format_default(self.access_code, 0, constel.bits_per_symbol()))
+
+    def get_num_taps(self):
+        return self.num_taps
+
+    def set_num_taps(self, num_taps):
+        self.num_taps = num_taps
+        self.root_raised_cosine_filter_0.set_taps(firdes.root_raised_cosine(1.0, self.sps, 1.0, self.excess_bw, self.num_taps))
+
+    def get_header_format(self):
+        return self.header_format
+
+    def set_header_format(self, header_format):
+        self.header_format = header_format
+