main - feat: Make some initial MCP server work
This commit is contained in:
parent
61309d9b57
commit
9f96402e02
20
README.md
20
README.md
@ -21,4 +21,22 @@ python -m grc
|
||||
```
|
||||
|
||||
## Current Status
|
||||
Currently, the project is only a port of GNURadio Companion (v3.10.12.0)
|
||||
Currently, the project is only a port of GNURadio Companion (v3.10.12.0)
|
||||
|
||||
|
||||
## Wanted API
|
||||
1. Resources
|
||||
- List available blocks
|
||||
- List block params
|
||||
|
||||
- List current blocks
|
||||
- List current connections
|
||||
|
||||
2. Tools
|
||||
- Add block
|
||||
- Remove block
|
||||
- Set block params
|
||||
- Add connection
|
||||
- Remove connection
|
||||
|
||||
-[ ] use pydantic
|
||||
|
||||
265
fm_radio_receiver.grc
Normal file
265
fm_radio_receiver.grc
Normal file
@ -0,0 +1,265 @@
|
||||
options:
|
||||
parameters:
|
||||
author: GNU Radio
|
||||
catch_exceptions: 'True'
|
||||
category: '[GRC Hier Blocks]'
|
||||
cmake_opt: ''
|
||||
comment: ''
|
||||
copyright: ''
|
||||
description: RTL-SDR FM Radio Receiver with frequency and volume controls
|
||||
gen_cmake: 'On'
|
||||
gen_linking: dynamic
|
||||
generate_options: qt_gui
|
||||
hier_block_src_path: '.:'
|
||||
id: default
|
||||
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: FM Radio Receiver
|
||||
window_size: 1280, 1024
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [8, 8]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
|
||||
blocks:
|
||||
- name: samp_rate
|
||||
id: variable
|
||||
parameters:
|
||||
comment: ''
|
||||
value: '2400000'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [200, 12]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
- name: variable_qtgui_range_0
|
||||
id: variable_qtgui_range
|
||||
parameters:
|
||||
comment: ''
|
||||
gui_hint: ''
|
||||
label: Frequency
|
||||
min_len: '200'
|
||||
orient: QtCore.Qt.Horizontal
|
||||
rangeType: float
|
||||
start: '87500000'
|
||||
step: '100000'
|
||||
stop: '108000000'
|
||||
value: '95500000'
|
||||
widget: counter_slider
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
state: enabled
|
||||
- name: variable_qtgui_range_1
|
||||
id: variable_qtgui_range
|
||||
parameters:
|
||||
comment: ''
|
||||
gui_hint: ''
|
||||
label: Volume
|
||||
min_len: '200'
|
||||
orient: QtCore.Qt.Horizontal
|
||||
rangeType: float
|
||||
start: '0'
|
||||
step: '0.1'
|
||||
stop: '2'
|
||||
value: '1'
|
||||
widget: slider
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
state: enabled
|
||||
- name: analog_wfm_rcv_0
|
||||
id: analog_wfm_rcv
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
audio_decimation: '10'
|
||||
comment: ''
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
quad_rate: '480000'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
state: enabled
|
||||
- name: audio_sink_0
|
||||
id: audio_sink
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
comment: ''
|
||||
device_name: ''
|
||||
num_inputs: '1'
|
||||
ok_to_block: 'True'
|
||||
samp_rate: '48000'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
state: enabled
|
||||
- name: blocks_multiply_const_vxx_0
|
||||
id: blocks_multiply_const_vxx
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
comment: ''
|
||||
const: variable_qtgui_range_1
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
type: float
|
||||
vlen: '1'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
state: enabled
|
||||
- name: low_pass_filter_0
|
||||
id: low_pass_filter
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
beta: '6.76'
|
||||
comment: ''
|
||||
cutoff_freq: '100000'
|
||||
decim: '5'
|
||||
gain: '1'
|
||||
interp: '1'
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
samp_rate: '2400000'
|
||||
type: fir_filter_ccf
|
||||
width: '30000'
|
||||
win: window.WIN_HAMMING
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
state: enabled
|
||||
- name: qtgui_freq_sink_x_0
|
||||
id: qtgui_freq_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'
|
||||
average: '1.0'
|
||||
axislabels: 'True'
|
||||
bw: '2400000'
|
||||
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'
|
||||
fc: variable_qtgui_range_0
|
||||
fftsize: '1024'
|
||||
freqhalf: 'True'
|
||||
grid: 'False'
|
||||
gui_hint: ''
|
||||
label: Relative Gain
|
||||
label1: ''
|
||||
label10: ''''''
|
||||
label2: ''''''
|
||||
label3: ''''''
|
||||
label4: ''''''
|
||||
label5: ''''''
|
||||
label6: ''''''
|
||||
label7: ''''''
|
||||
label8: ''''''
|
||||
label9: ''''''
|
||||
legend: 'True'
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
name: RF Spectrum
|
||||
nconnections: '1'
|
||||
norm_window: 'False'
|
||||
showports: 'False'
|
||||
tr_chan: '0'
|
||||
tr_level: '0.0'
|
||||
tr_mode: qtgui.TRIG_MODE_FREE
|
||||
tr_tag: '""'
|
||||
type: complex
|
||||
units: dB
|
||||
update_time: '0.10'
|
||||
width1: '1'
|
||||
width10: '1'
|
||||
width2: '1'
|
||||
width3: '1'
|
||||
width4: '1'
|
||||
width5: '1'
|
||||
width6: '1'
|
||||
width7: '1'
|
||||
width8: '1'
|
||||
width9: '1'
|
||||
wintype: window.WIN_BLACKMAN_hARRIS
|
||||
ymax: '10'
|
||||
ymin: '-140'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
state: enabled
|
||||
- name: soapy_rtlsdr_source_0
|
||||
id: soapy_rtlsdr_source
|
||||
parameters:
|
||||
affinity: ''
|
||||
agc: 'True'
|
||||
alias: ''
|
||||
bias: 'False'
|
||||
bufflen: '16384'
|
||||
center_freq: variable_qtgui_range_0
|
||||
comment: ''
|
||||
dev_args: ''
|
||||
freq_correction: '0'
|
||||
gain: '20'
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
samp_rate: '2400000'
|
||||
type: fc32
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
state: enabled
|
||||
|
||||
connections:
|
||||
- [analog_wfm_rcv_0, '0', blocks_multiply_const_vxx_0, '0']
|
||||
- [blocks_multiply_const_vxx_0, '0', audio_sink_0, '0']
|
||||
- [low_pass_filter_0, '0', analog_wfm_rcv_0, '0']
|
||||
- [soapy_rtlsdr_source_0, '0', low_pass_filter_0, '0']
|
||||
- [soapy_rtlsdr_source_0, '0', qtgui_freq_sink_x_0, '0']
|
||||
|
||||
metadata:
|
||||
file_format: 1
|
||||
grc_version: 3.10.12.0
|
||||
288
fm_radio_receiver_with_signal_meter.grc
Normal file
288
fm_radio_receiver_with_signal_meter.grc
Normal file
@ -0,0 +1,288 @@
|
||||
options:
|
||||
parameters:
|
||||
author: ''
|
||||
catch_exceptions: 'True'
|
||||
category: '[GRC Hier Blocks]'
|
||||
cmake_opt: ''
|
||||
comment: ''
|
||||
copyright: ''
|
||||
description: ''
|
||||
gen_cmake: 'On'
|
||||
gen_linking: dynamic
|
||||
generate_options: qt_gui
|
||||
hier_block_src_path: '.:'
|
||||
id: default
|
||||
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: Not titled yet
|
||||
window_size: (1000,1000)
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [296, 4.0]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
|
||||
blocks:
|
||||
- name: freq
|
||||
id: variable_qtgui_range
|
||||
parameters:
|
||||
comment: ''
|
||||
gui_hint: ''
|
||||
label: Frequency
|
||||
min_len: '200'
|
||||
orient: QtCore.Qt.Horizontal
|
||||
rangeType: float
|
||||
start: '88000000'
|
||||
step: '100000'
|
||||
stop: '108000000'
|
||||
value: '95700000'
|
||||
widget: counter_slider
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [48, 44.0]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
- name: rf_gain
|
||||
id: variable_qtgui_range
|
||||
parameters:
|
||||
comment: ''
|
||||
gui_hint: ''
|
||||
label: RF Gain
|
||||
min_len: '200'
|
||||
orient: QtCore.Qt.Horizontal
|
||||
rangeType: float
|
||||
start: '0'
|
||||
step: '1'
|
||||
stop: '47'
|
||||
value: '20'
|
||||
widget: counter_slider
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [568, 116.0]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
- name: samp_rate
|
||||
id: variable
|
||||
parameters:
|
||||
comment: ''
|
||||
value: '32000'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [200, 12]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
- name: variable_qtgui_range_0
|
||||
id: variable_qtgui_range
|
||||
parameters:
|
||||
comment: ''
|
||||
gui_hint: ''
|
||||
label: ''
|
||||
min_len: '200'
|
||||
orient: QtCore.Qt.Horizontal
|
||||
rangeType: float
|
||||
start: '0'
|
||||
step: '1'
|
||||
stop: '100'
|
||||
value: '50'
|
||||
widget: counter_slider
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [184, 104.0]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
- name: volume
|
||||
id: variable
|
||||
parameters:
|
||||
comment: ''
|
||||
value: '1'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [384, 128.0]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
- name: analog_wfm_rcv_1
|
||||
id: analog_wfm_rcv
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
audio_decimation: '8'
|
||||
comment: ''
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
quad_rate: '2048000'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [400, 240.0]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
- name: audio_sink_0
|
||||
id: audio_sink
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
comment: ''
|
||||
device_name: ''
|
||||
num_inputs: '1'
|
||||
ok_to_block: 'True'
|
||||
samp_rate: samp_rate
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [848, 204.0]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
- name: blocks_complex_to_mag_squared_0
|
||||
id: blocks_complex_to_mag_squared
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
comment: ''
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
vlen: '1'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [456, 484.0]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
- name: blocks_multiply_const_vxx_0
|
||||
id: blocks_multiply_const_vxx
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
comment: ''
|
||||
const: volume
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
type: float
|
||||
vlen: '1'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [696, 220.0]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
- name: qtgui_number_sink_0
|
||||
id: qtgui_number_sink
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
autoscale: 'False'
|
||||
avg: '0'
|
||||
color1: ("black", "black")
|
||||
color10: ("black", "black")
|
||||
color2: ("black", "black")
|
||||
color3: ("black", "black")
|
||||
color4: ("black", "black")
|
||||
color5: ("black", "black")
|
||||
color6: ("black", "black")
|
||||
color7: ("black", "black")
|
||||
color8: ("black", "black")
|
||||
color9: ("black", "black")
|
||||
comment: ''
|
||||
factor1: '1'
|
||||
factor10: '1'
|
||||
factor2: '1'
|
||||
factor3: '1'
|
||||
factor4: '1'
|
||||
factor5: '1'
|
||||
factor6: '1'
|
||||
factor7: '1'
|
||||
factor8: '1'
|
||||
factor9: '1'
|
||||
graph_type: qtgui.NUM_GRAPH_HORIZ
|
||||
gui_hint: ''
|
||||
label1: ''
|
||||
label10: ''
|
||||
label2: ''
|
||||
label3: ''
|
||||
label4: ''
|
||||
label5: ''
|
||||
label6: ''
|
||||
label7: ''
|
||||
label8: ''
|
||||
label9: ''
|
||||
max: '1'
|
||||
min: '-1'
|
||||
name: '""'
|
||||
nconnections: '1'
|
||||
type: float
|
||||
unit1: ''
|
||||
unit10: ''
|
||||
unit2: ''
|
||||
unit3: ''
|
||||
unit4: ''
|
||||
unit5: ''
|
||||
unit6: ''
|
||||
unit7: ''
|
||||
unit8: ''
|
||||
unit9: ''
|
||||
update_time: '0.10'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [856, 320.0]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
- name: soapy_rtlsdr_source_1
|
||||
id: soapy_rtlsdr_source
|
||||
parameters:
|
||||
affinity: ''
|
||||
agc: 'False'
|
||||
alias: ''
|
||||
bias: 'False'
|
||||
bufflen: '16384'
|
||||
center_freq: freq
|
||||
comment: ''
|
||||
dev_args: ''
|
||||
freq_correction: '0'
|
||||
gain: rf_gain
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
samp_rate: '2048000'
|
||||
type: fc32
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [88, 352.0]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
|
||||
connections:
|
||||
- [analog_wfm_rcv_1, '0', blocks_multiply_const_vxx_0, '0']
|
||||
- [blocks_complex_to_mag_squared_0, '0', qtgui_number_sink_0, '0']
|
||||
- [blocks_multiply_const_vxx_0, '0', audio_sink_0, '0']
|
||||
- [soapy_rtlsdr_source_1, '0', analog_wfm_rcv_1, '0']
|
||||
- [soapy_rtlsdr_source_1, '0', blocks_complex_to_mag_squared_0, '0']
|
||||
|
||||
metadata:
|
||||
file_format: 1
|
||||
grc_version: 3.10.12.0
|
||||
126
fm_receiver.grc
Normal file
126
fm_receiver.grc
Normal file
@ -0,0 +1,126 @@
|
||||
options:
|
||||
parameters:
|
||||
author: ''
|
||||
catch_exceptions: 'True'
|
||||
category: '[GRC Hier Blocks]'
|
||||
cmake_opt: ''
|
||||
comment: ''
|
||||
copyright: ''
|
||||
description: ''
|
||||
gen_cmake: 'On'
|
||||
gen_linking: dynamic
|
||||
generate_options: qt_gui
|
||||
hier_block_src_path: '.:'
|
||||
id: default
|
||||
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: Not titled yet
|
||||
window_size: (1000,1000)
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [8, 8]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
|
||||
blocks:
|
||||
- name: samp_rate
|
||||
id: variable
|
||||
parameters:
|
||||
comment: ''
|
||||
value: '32000'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
coordinate: [200, 12]
|
||||
rotation: 0
|
||||
state: enabled
|
||||
- name: analog_wfm_rcv_0
|
||||
id: analog_wfm_rcv
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
audio_decimation: '10'
|
||||
comment: ''
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
quad_rate: '480000'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
state: enabled
|
||||
- name: audio_sink_0
|
||||
id: audio_sink
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
comment: ''
|
||||
device_name: ''
|
||||
num_inputs: '1'
|
||||
ok_to_block: 'True'
|
||||
samp_rate: '44100'
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
state: enabled
|
||||
- name: rational_resampler_xxx_0
|
||||
id: rational_resampler_xxx
|
||||
parameters:
|
||||
affinity: ''
|
||||
alias: ''
|
||||
comment: ''
|
||||
decim: '480'
|
||||
fbw: '0'
|
||||
interp: '441'
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
taps: '[]'
|
||||
type: fff
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
state: enabled
|
||||
- name: soapy_rtlsdr_source_0
|
||||
id: soapy_rtlsdr_source
|
||||
parameters:
|
||||
affinity: ''
|
||||
agc: 'False'
|
||||
alias: ''
|
||||
bias: 'False'
|
||||
bufflen: '16384'
|
||||
center_freq: '95500000'
|
||||
comment: ''
|
||||
dev_args: ''
|
||||
freq_correction: '0'
|
||||
gain: '20'
|
||||
maxoutbuf: '0'
|
||||
minoutbuf: '0'
|
||||
samp_rate: '2457600'
|
||||
type: fc32
|
||||
states:
|
||||
bus_sink: false
|
||||
bus_source: false
|
||||
bus_structure: null
|
||||
state: enabled
|
||||
|
||||
connections:
|
||||
- [analog_wfm_rcv_0, '0', rational_resampler_xxx_0, '0']
|
||||
- [rational_resampler_xxx_0, '0', audio_sink_0, '0']
|
||||
- [soapy_rtlsdr_source_0, '0', analog_wfm_rcv_0, '0']
|
||||
|
||||
metadata:
|
||||
file_format: 1
|
||||
grc_version: 3.10.12.0
|
||||
70
grc/main.py
70
grc/main.py
@ -69,6 +69,71 @@ log = logging.getLogger('grc')
|
||||
# The default console logging should be WARNING
|
||||
log.setLevel(logging.DEBUG)
|
||||
|
||||
def run_api(args, log):
|
||||
|
||||
from .core.platform import Platform
|
||||
from .core.FlowGraph import FlowGraph
|
||||
|
||||
platform = Platform(
|
||||
version=gr.version(),
|
||||
version_parts=(gr.major_version(), gr.api_version(), gr.minor_version()),
|
||||
prefs=gr.prefs(),
|
||||
# install_prefix=gr.prefix()
|
||||
)
|
||||
platform.build_library()
|
||||
|
||||
|
||||
from .mcp.mcp import CoreMiddleware
|
||||
mcp = CoreMiddleware(platform, "")
|
||||
|
||||
from fastmcp import FastMCP
|
||||
|
||||
app = FastMCP("Demo 🚀")
|
||||
|
||||
app.tool()(mcp.list_all_blocks)
|
||||
app.tool()(mcp.list_block_input_data)
|
||||
app.tool()(mcp.list_block_output_data)
|
||||
app.tool()(mcp.list_block_parameters_data)
|
||||
|
||||
app.tool()(mcp.get_placed_blocks)
|
||||
app.tool()(mcp.get_placed_connections)
|
||||
app.tool()(mcp.get_placed_block_params)
|
||||
|
||||
app.tool()(mcp.validate_block)
|
||||
app.tool()(mcp.validate_connection)
|
||||
app.tool()(mcp.validate_flowgraph)
|
||||
app.tool()(mcp.get_all_errors)
|
||||
|
||||
app.tool()(mcp.add_block)
|
||||
app.tool()(mcp.remove_block)
|
||||
app.tool()(mcp.connect_blocks)
|
||||
app.tool()(mcp.update_block_params)
|
||||
|
||||
app.tool()(mcp.save_flowgraph)
|
||||
|
||||
|
||||
app.run(transport='sse')
|
||||
|
||||
|
||||
# print(mcp.flowgraph_blocks())
|
||||
# print(mcp.flowgraph_connections())
|
||||
# initial_state = platform.parse_flow_graph("")
|
||||
# fg = FlowGraph(platform)
|
||||
# fg.import_data(initial_state)
|
||||
# source = fg.new_block('analog_const_source_x')
|
||||
# source.params['id'].set_value('test1')
|
||||
# sink = fg.new_block('virtual_sink')
|
||||
# sink.params['id'].set_value('test2')
|
||||
# conn = fg.connect(source.sources[0], sink.sinks[0])
|
||||
# platform.save_flow_graph('test.grc', fg)
|
||||
|
||||
# mcp.add_block('analog_const_source_x')
|
||||
# mcp.add_block('virtual_sink')
|
||||
# mcp.connect_blocks('analog_const_source_x_0', 0, 'virtual_sink_0', 0)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def run_gtk(args, log):
|
||||
''' Runs the GTK version of GNU Radio Companion '''
|
||||
@ -182,7 +247,6 @@ def run_qt(args, log):
|
||||
install_prefix=gr.prefix()
|
||||
)
|
||||
model.build_library()
|
||||
|
||||
# Launch GRC
|
||||
app = grc.Application(settings, model, args.flow_graphs)
|
||||
sys.exit(app.run())
|
||||
@ -285,6 +349,8 @@ def main():
|
||||
help="GNU Radio Companion (QT)")
|
||||
gui_group_exclusive.add_argument("--gtk", dest='framework', action='store_const', const='gtk',
|
||||
help="GNU Radio Companion (GTK)")
|
||||
gui_group_exclusive.add_argument("--api", dest='framework', action='store_const', const='api',
|
||||
help="GNU Radio Companion (API)")
|
||||
|
||||
# Default options if not already set with add_argument()
|
||||
args = parser.parse_args()
|
||||
@ -316,6 +382,8 @@ def main():
|
||||
run_qt(args, log)
|
||||
elif args.framework == 'gtk':
|
||||
run_gtk(args, log)
|
||||
elif args.framework == 'api':
|
||||
run_api(args, log)
|
||||
else: # args.framework == None
|
||||
if grc_version_from_config == 'grc_qt':
|
||||
run_qt(args, log)
|
||||
|
||||
0
grc/mcp/__init__.py
Normal file
0
grc/mcp/__init__.py
Normal file
247
grc/mcp/mcp.py
Normal file
247
grc/mcp/mcp.py
Normal file
@ -0,0 +1,247 @@
|
||||
from itertools import count
|
||||
import re
|
||||
from typing import Any, Dict, List, Optional, Set
|
||||
|
||||
from grc.core.FlowGraph import FlowGraph
|
||||
from grc.core.blocks.block import Block
|
||||
from grc.core.params.param import Param
|
||||
from grc.core.Connection import Connection
|
||||
from grc.core.platform import Platform
|
||||
from grc.core.ports.port import Port
|
||||
|
||||
|
||||
class CoreMiddleware:
|
||||
def __init__(self, platform: Platform, filepath: Optional[str] = ""):
|
||||
|
||||
self._platform = platform
|
||||
|
||||
initial_state = platform.parse_flow_graph(filepath)
|
||||
self._flowgraph = FlowGraph(platform)
|
||||
self._flowgraph.import_data(initial_state)
|
||||
|
||||
##############################################
|
||||
# Static Data
|
||||
##############################################
|
||||
|
||||
def list_all_blocks(self) -> List[Dict[str, Any]]:
|
||||
blocks_data = []
|
||||
for block in self._platform.blocks.values():
|
||||
blocks_data.append(
|
||||
{
|
||||
"key": block.key,
|
||||
"label": block.label,
|
||||
}
|
||||
)
|
||||
return blocks_data
|
||||
|
||||
def list_block_parameters_data(self, block_key: str) -> List[str]:
|
||||
block = self._platform.blocks[block_key]
|
||||
return block.parameters_data
|
||||
|
||||
def list_block_output_data(self, block_key: str) -> List[Dict[str, Any]]:
|
||||
block = self._platform.blocks[block_key]
|
||||
return block.outputs_data
|
||||
|
||||
def list_block_input_data(self, block_key: str) -> List[Dict[str, Any]]:
|
||||
block = self._platform.blocks[block_key]
|
||||
return block.inputs_data
|
||||
|
||||
##############################################
|
||||
# Flowgraph Data
|
||||
##############################################
|
||||
|
||||
def get_placed_blocks(self) -> List[Dict[str, Any]]:
|
||||
blocks_data = []
|
||||
for block in self._flowgraph.blocks:
|
||||
blocks_data.append(
|
||||
{
|
||||
"key": block.key,
|
||||
"name": block.params["id"].get_value(),
|
||||
}
|
||||
)
|
||||
return blocks_data
|
||||
|
||||
def get_placed_block_params(self, block_name: str) -> Dict[str, Any]:
|
||||
block = self._flowgraph.get_block(block_name)
|
||||
return {param.key: param.get_value() for param in block.params.values()}
|
||||
|
||||
def get_placed_connections(self) -> Set[Dict[str, Any]]:
|
||||
connections_data = []
|
||||
for connection in self._flowgraph.connections:
|
||||
connection: Connection = connection
|
||||
source_port: Port = connection.source_port
|
||||
sink_port: Port = connection.sink_port
|
||||
connections_data.append(
|
||||
{
|
||||
"src_block": source_port.parent.key,
|
||||
"src_port": source_port.key,
|
||||
"dst_block": sink_port.parent.key,
|
||||
"dst_port": sink_port.key,
|
||||
}
|
||||
)
|
||||
return connections_data
|
||||
|
||||
##############################################
|
||||
# Flowgraph Operations
|
||||
##############################################
|
||||
|
||||
def add_block(self, block_key: str, name: Optional[str] = None) -> Block:
|
||||
name = name or self._get_unique_id(block_key)
|
||||
block = self._flowgraph.new_block(block_key)
|
||||
block.params["id"].set_value(name)
|
||||
return "success"
|
||||
|
||||
def remove_block(self, block_name: str) -> None:
|
||||
block = self._flowgraph.get_block(block_name)
|
||||
self._flowgraph.remove_element(block)
|
||||
return "success"
|
||||
|
||||
def connect_blocks(
|
||||
self,
|
||||
src_block_name: str,
|
||||
src_port_index: int,
|
||||
dst_block_name: str,
|
||||
dst_port_index: int,
|
||||
) -> Connection:
|
||||
src_block = self._flowgraph.get_block(src_block_name)
|
||||
dst_block = self._flowgraph.get_block(dst_block_name)
|
||||
self._flowgraph.connect(
|
||||
src_block.sources[src_port_index], dst_block.sinks[dst_port_index]
|
||||
)
|
||||
return "success"
|
||||
|
||||
def disconnect_blocks(
|
||||
self,
|
||||
src_block_name: str,
|
||||
src_port_index: int,
|
||||
dst_block_name: str,
|
||||
dst_port_index: int,
|
||||
) -> None:
|
||||
src_block = self._flowgraph.get_block(src_block_name)
|
||||
dst_block = self._flowgraph.get_block(dst_block_name)
|
||||
self._flowgraph.disconnect(
|
||||
src_block.sources[src_port_index], dst_block.sinks[dst_port_index]
|
||||
)
|
||||
return "success"
|
||||
|
||||
def update_block_params(self, block_name: str, params: Dict[str, Any]) -> None:
|
||||
block = self._flowgraph.get_block(block_name)
|
||||
for param_name, param_value in params.items():
|
||||
block.params[param_name].set_value(param_value)
|
||||
return "success"
|
||||
|
||||
##############################################
|
||||
# Flowgraph Validation
|
||||
##############################################
|
||||
|
||||
def validate_block(self, block_name: str) -> bool:
|
||||
self._flowgraph.rewrite()
|
||||
block = self._flowgraph.get_block(block_name)
|
||||
block.validate()
|
||||
return block.is_valid()
|
||||
|
||||
def validate_connection(
|
||||
self,
|
||||
src_block_name: str,
|
||||
src_port_index: int,
|
||||
dst_block_name: str,
|
||||
dst_port_index: int,
|
||||
) -> bool:
|
||||
self._flowgraph.rewrite()
|
||||
connections: Set[Connection] = self._flowgraph.connections
|
||||
for connection in connections:
|
||||
if (
|
||||
connection.source_port.parent.key == src_block_name
|
||||
and connection.sink_port.parent.key == dst_block_name
|
||||
and connection.source_port.key == src_port_index
|
||||
and connection.sink_port.key == dst_port_index
|
||||
):
|
||||
connection.validate()
|
||||
return connection.is_valid()
|
||||
raise ValueError("Connection not found")
|
||||
|
||||
def validate_flowgraph(self) -> bool:
|
||||
self._flowgraph.rewrite()
|
||||
self._flowgraph.validate()
|
||||
return self._flowgraph.is_valid()
|
||||
|
||||
def get_all_errors(self) -> List[Dict[str, Any]]:
|
||||
self._flowgraph.rewrite()
|
||||
self._flowgraph.validate()
|
||||
errors = []
|
||||
for elem, msg in self._flowgraph.iter_error_messages():
|
||||
msg = re.sub("[^A-Za-z0-9]+", " ", msg).strip()
|
||||
if isinstance(elem, Connection):
|
||||
connection: Connection = elem
|
||||
source_port: Port = elem.source_port
|
||||
sink_port: Port = elem.sink_port
|
||||
errors.append(
|
||||
{
|
||||
"type": "connection",
|
||||
"key": {
|
||||
"src_block": source_port.parent.key,
|
||||
"src_port": source_port.key,
|
||||
"dst_block": sink_port.parent.key,
|
||||
"dst_port": sink_port.key,
|
||||
},
|
||||
"message": msg,
|
||||
}
|
||||
)
|
||||
|
||||
if isinstance(elem, Param):
|
||||
errors.append(
|
||||
{
|
||||
"type": "param",
|
||||
"key": f"{elem.parent.params["id"].get_value()}:{elem.key}",
|
||||
"message": msg,
|
||||
}
|
||||
)
|
||||
|
||||
if isinstance(elem, Port):
|
||||
errors.append(
|
||||
{
|
||||
"type": "port",
|
||||
"key": f"{elem.parent.params["id"].get_value()}:{elem.key}",
|
||||
"message": msg,
|
||||
}
|
||||
)
|
||||
|
||||
if isinstance(elem, Block):
|
||||
errors.append(
|
||||
{
|
||||
"type": "block",
|
||||
"key": elem.params["id"].get_value(),
|
||||
"message": msg,
|
||||
}
|
||||
)
|
||||
|
||||
return errors
|
||||
|
||||
##############################################
|
||||
# Misc
|
||||
##############################################
|
||||
|
||||
def save_flowgraph(self, filepath: str) -> None:
|
||||
self._platform.save_flow_graph(filepath, self._flowgraph)
|
||||
return "success"
|
||||
|
||||
##############################################
|
||||
# Helper Functions
|
||||
##############################################
|
||||
|
||||
def _get_unique_id(self, base_id=""):
|
||||
"""
|
||||
Get a unique id starting with the base id.
|
||||
|
||||
Args:
|
||||
base_id: the id starts with this and appends a count
|
||||
|
||||
Returns:
|
||||
a unique id
|
||||
"""
|
||||
block_ids = set(b.name for b in self._flowgraph.blocks)
|
||||
for index in count():
|
||||
block_id = "{}_{}".format(base_id, index)
|
||||
if block_id not in block_ids:
|
||||
break
|
||||
return block_id
|
||||
Loading…
x
Reference in New Issue
Block a user