Eigene Blöcke
Erste Schritte zur Erstellung eigener , wiederverwertbarer GnuRadio Blöcke
In Gnuradio kann man eigene Blöcke erstellen, um die Funktionalität des Senders oder Empfängers zu erweitern.
Der embedded_python Block kann dazu genutz werden, Python Code in einen Flowgraph zu integrieren. Der grc ledgt diesen Block nach einer eigenen Namenskonvention ab. Möchte man einen Block in verschiedenen Projekten verwenden, ist es sinnvoller, einen eigenen Block zu erstellen. Dieser wird in den eigenen Libs unter den Projekten archiviert.
Der Baudot Decoder Block aus dem DDK9projekt ist ein Beispiel für einen solchen Block.
Dieser Artikel beschreibt die Vorgehensweise, wie man aus einem embeded Block eine wiederverwendbare Komponente macht.
gr-modtool
Bevor wir starten, ein kurzer Blick auf das wichtigste Werkzeug: gr-modtool. Da GNU Radio-Module eine strikte Ordnerstruktur und komplexe CMake-Verbindungen benötigen, automatisiert dieses CLI-Tool das Erstellen, Hinzufügen und Löschen von Blöcken.
Hier sind die drei Kernbefehle, die du für die Arbeit mit eigenen Bibliotheken brauchst:
gr_modtool newmod
Erstellt das äußere Entwicklungsverzeichnis (z. B. gr-meinelib). Es legt die grundlegende Verzeichnisstruktur an (python/, grc/, lib/, include/) und generiert die zentralen CMakeLists.txt-Dateien.
gr_modtool add [optionen]
Fügt einen neuen Block (Code + YAML-Schnittstelle) in ein bestehendes Modul ein. Es verknüpft die neue Datei automatisch in den CMake-Dateien, damit sie später mitkompiliert wird.
gr_modtool rm
Löscht einen Block sauber aus dem Modul und entfernt alle dazugehörigen Einträge aus den CMake-Konfigurationen (wichtig, da man sonst beim Kompilieren Fehler wegen "fehlender Dateien" bekommt).
Das Grundgerüst erstellen
Zuerst erstellen wir das Grundgerüst für deine persönliche Library. Öffne ein Terminal in deinem gewünschten Entwicklungsordner:
# 1. Neues Modul mit dem Namen "meinelib" anlegen
gr_modtool newmod meinelib
# 2. In das neu entstandene Verzeichnis wechseln
cd gr-meinelib
# 1. Neues Modul mit dem Namen "meinelib" anlegen
gr_modtool newmod meinelib
# 2. In das neu entstandene Verzeichnis wechseln
cd gr-meinelib
Den Python Block hinzufügen
gr_modtool add -t python -l python ita2_decoder
gr_modtool add -t python -l python ita2_decoder
Bei diesem Schritt werden die In- und Output Parameter für den Block über eine YAML Datei festgelegt, dies können spätere Nutzer des Blocks ändern, ohne den Quellcode zu öffnen. Es ist deshalb wichtig, dass du dir im Vorfeld Gedanken über die nötigen Parameter und deren sinnvollen Standardwerte machst.
Als Blocktyp währen wir für den Baudot Decoder den sync Block.
Der Code
import numpy as np
from gnuradio import gr
class ita2_decoder(gr.sync_block):
"""
ITA2 (Baudot) Decoder Block
"""
def __init__(self, samples_per_symbol=1):
gr.sync_block.__init__(
self,
name='ITA2 Decoder',
in_sig=[np.uint8], # Eingang: z.B. Serialisierte Bits/Bytes
out_sig=[np.uint8] # Ausgang: Dekodierte ASCII/UTF-8 Zeichen
)
self.sps = samples_per_symbol
def work(self, input_items, output_items):
in0 = input_items[0]
out = output_items[0]
# ----------------------------------------------------
# DEINE ITA2-DEKODIERUNGSLOGIK HIER EINFÜGEN
# ----------------------------------------------------
# Beispiel: Kopiert Daten nur durch
out[:len(in0)] = in0
return len(out)
import numpy as np
from gnuradio import gr
class ita2_decoder(gr.sync_block):
"""
ITA2 (Baudot) Decoder Block
"""
def __init__(self, samples_per_symbol=1):
gr.sync_block.__init__(
self,
name='ITA2 Decoder',
in_sig=[np.uint8], # Eingang: z.B. Serialisierte Bits/Bytes
out_sig=[np.uint8] # Ausgang: Dekodierte ASCII/UTF-8 Zeichen
)
self.sps = samples_per_symbol
def work(self, input_items, output_items):
in0 = input_items[0]
out = output_items[0]
# ----------------------------------------------------
# DEINE ITA2-DEKODIERUNGSLOGIK HIER EINFÜGEN
# ----------------------------------------------------
# Beispiel: Kopiert Daten nur durch
out[:len(in0)] = in0
return len(out)
Einbindung in die GRC Oberfläche
id: meinelib_ita2_decoder
label: ITA2 Decoder
category: '[meinelib]'
templates:
imports: import meinelib
make: meinelib.ita2_decoder(samples_per_symbol=${samples_per_symbol})
parameters:
- id: samples_per_symbol
label: Samples per Symbol
dtype: int
default: '1'
inputs:
- label: in
dtype: byte
outputs:
- label: out
dtype: byte
id: meinelib_ita2_decoder
label: ITA2 Decoder
category: '[meinelib]'
templates:
imports: import meinelib
make: meinelib.ita2_decoder(samples_per_symbol=${samples_per_symbol})
parameters:
- id: samples_per_symbol
label: Samples per Symbol
dtype: int
default: '1'
inputs:
- label: in
dtype: byte
outputs:
- label: out
dtype: byte
Kompilieren und Einbinden
Zuerst müssen wir die Library bauen und für GRC verfügbar machen. Da das Projekt jetzt die Struktur einer echten Library hat, müssen wir es im Entwicklungsmodus ausführen:
# 1. Im Hauptordner meinelib/ das modul bauen und installieren (User-Scope)
cd meinelib
mkdir build
cd build
cmake .. -DCMAKE_INSTALL_PREFIX=$HOME/.local
make
make install
# 2. Gruradio-Bibliotheken im Homeverzeichnis neu generieren lassen
grunano --rebuild-grc-library
# 1. Im Hauptordner meinelib/ das modul bauen und installieren (User-Scope)
cd meinelib
mkdir build
cd build
cmake .. -DCMAKE_INSTALL_PREFIX=$HOME/.local
make
make install
# 2. Gruradio-Bibliotheken im Homeverzeichnis neu generieren lassen
grunano --rebuild-grc-library
Nach diesem Schritt sollte der ITA2 Decoder im GRC-Bibliotheksfenster unter der Kategorie [meinelib] erscheinen und kann wie jeder Standardblock verwendet werden.