Browse Source

added gnuradio flowchart sending continuous 5Hz signal for testing

Fabian Peter Hammerle 3 years ago
parent
commit
253a524d1d
4 changed files with 325 additions and 0 deletions
  1. 1 0
      .gitignore
  2. 4 0
      Makefile
  3. 75 0
      serial_sink_block.py
  4. 245 0
      transmit.grc

+ 1 - 0
.gitignore

@@ -1 +1,2 @@
 /build-*/
+/transmit.py

+ 4 - 0
Makefile

@@ -1,2 +1,6 @@
 BOARD_TAG = uno
 include /usr/share/arduino/Arduino.mk
+
+# https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html
+run: transmit.grc
+	grcc --run $^

+ 75 - 0
serial_sink_block.py

@@ -0,0 +1,75 @@
+import ctypes
+import ctypes.util
+import time
+
+import gnuradio.gr
+import numpy
+import serial
+
+_LIBC_NAME = ctypes.util.find_library("c")
+if not _LIBC_NAME:
+    raise Exception("couldn't find libc")
+_LIBC = ctypes.CDLL(_LIBC_NAME)
+
+
+class _Timespec(ctypes.Structure):
+    # pylint: disable=too-few-public-methods
+    """
+    > struct timespec {
+    >     time_t tv_sec;        /* seconds */
+    >     long   tv_nsec;       /* nanoseconds */
+    > };
+
+    > The value of the nanoseconds field must be in the range 0 to 999999999.
+    """
+    _fields_ = [("tv_sec", ctypes.c_uint32), ("tv_nsec", ctypes.c_long)]
+
+
+_NANOSLEEP = _LIBC.nanosleep
+_NANOSLEEP.argtypes = [ctypes.POINTER(_Timespec), ctypes.POINTER(_Timespec)]
+_NANOSLEEP.restype = ctypes.c_int
+
+
+class SerialSinkBlock(gnuradio.gr.basic_block):
+    _SLEEP_THRESHOLD_NS = 10000
+
+    def __init__(self, port="/dev/ttyUSB0", baud_rate=115200, sample_rate_hz=1000):
+        gnuradio.gr.basic_block.__init__(
+            self, name="Serial Sink Block", in_sig=[numpy.uint8], out_sig=None
+        )
+        self._serial_port = serial.Serial(
+            port=port, baudrate=baud_rate, bytesize=serial.EIGHTBITS
+        )
+        self._tick_interval_ns = int(1e9 / sample_rate_hz)
+        # periodically return from .general_work() to handle signals
+        self._work_max_samples = max(int(sample_rate_hz * 2), 1)
+        self._next_tick_time_ns = None
+        self._libc = ctypes.CDLL(ctypes.util.find_library("c"))
+
+    def general_work(self, input_items, output_items) -> int:
+        # pylint: disable=unused-argument
+        if not self._next_tick_time_ns:
+            self._next_tick_time_ns = time.perf_counter_ns()
+        for byte in input_items[0][: self._work_max_samples]:
+            while (
+                self._next_tick_time_ns - time.perf_counter_ns()
+            ) > self._SLEEP_THRESHOLD_NS:
+                _NANOSLEEP(
+                    _Timespec(
+                        0,
+                        # negative values make nanosleep return -1
+                        min(
+                            self._next_tick_time_ns
+                            - time.perf_counter_ns()
+                            - self._SLEEP_THRESHOLD_NS,
+                            999999999,
+                        ),
+                    ),
+                    None,
+                )
+            while (self._next_tick_time_ns - time.perf_counter_ns()) > 0:
+                pass
+            self._serial_port.write(b"\x01" if byte else b"\0")
+            self._next_tick_time_ns += self._tick_interval_ns
+        self.consume(0, min(len(input_items[0]), self._work_max_samples))
+        return 0

+ 245 - 0
transmit.grc

@@ -0,0 +1,245 @@
+options:
+  parameters:
+    author: ''
+    category: '[GRC Hier Blocks]'
+    cmake_opt: ''
+    comment: ''
+    copyright: ''
+    description: ''
+    gen_cmake: 'On'
+    gen_linking: dynamic
+    generate_options: qt_gui
+    hier_block_src_path: '.:'
+    id: transmit
+    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: Arduino Serial Transmitter
+    window_size: ''
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [70, 37]
+    rotation: 0
+    state: enabled
+
+blocks:
+- name: sample_rate_hz
+  id: variable
+  parameters:
+    comment: ''
+    value: '1000'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [668, 314]
+    rotation: 0
+    state: enabled
+- name: analog_sig_source_x_0
+  id: analog_sig_source_x
+  parameters:
+    affinity: ''
+    alias: ''
+    amp: '1'
+    comment: ''
+    freq: '5'
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    offset: '0'
+    phase: '0'
+    samp_rate: sample_rate_hz
+    type: byte
+    waveform: analog.GR_SQR_WAVE
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [70, 187]
+    rotation: 0
+    state: true
+- name: blocks_char_to_float_0
+  id: blocks_char_to_float
+  parameters:
+    affinity: ''
+    alias: ''
+    comment: ''
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    scale: '1'
+    vlen: '1'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [627, 176]
+    rotation: 0
+    state: enabled
+- name: serial_sink_block
+  id: epy_block
+  parameters:
+    _source_code: "import ctypes\nimport ctypes.util\nimport time\n\nimport gnuradio.gr\n\
+      import numpy\nimport serial\n\n_LIBC_NAME = ctypes.util.find_library(\"c\")\n\
+      if not _LIBC_NAME:\n    raise Exception(\"couldn't find libc\")\n_LIBC = ctypes.CDLL(_LIBC_NAME)\n\
+      \n\nclass _Timespec(ctypes.Structure):\n    # pylint: disable=too-few-public-methods\n\
+      \    \"\"\"\n    > struct timespec {\n    >     time_t tv_sec;        /* seconds\
+      \ */\n    >     long   tv_nsec;       /* nanoseconds */\n    > };\n\n    > The\
+      \ value of the nanoseconds field must be in the range 0 to 999999999.\n    \"\
+      \"\"\n    _fields_ = [(\"tv_sec\", ctypes.c_uint32), (\"tv_nsec\", ctypes.c_long)]\n\
+      \n\n_NANOSLEEP = _LIBC.nanosleep\n_NANOSLEEP.argtypes = [ctypes.POINTER(_Timespec),\
+      \ ctypes.POINTER(_Timespec)]\n_NANOSLEEP.restype = ctypes.c_int\n\n\nclass SerialSinkBlock(gnuradio.gr.basic_block):\n\
+      \    _SLEEP_THRESHOLD_NS = 10000\n\n    def __init__(self, port=\"/dev/ttyUSB0\"\
+      , baud_rate=115200, sample_rate_hz=1000):\n        gnuradio.gr.basic_block.__init__(\n\
+      \            self, name=\"Serial Sink Block\", in_sig=[numpy.uint8], out_sig=None\n\
+      \        )\n        self._serial_port = serial.Serial(\n            port=port,\
+      \ baudrate=baud_rate, bytesize=serial.EIGHTBITS\n        )\n        self._tick_interval_ns\
+      \ = int(1e9 / sample_rate_hz)\n        # periodically return from .general_work()\
+      \ to handle signals\n        self._work_max_samples = max(int(sample_rate_hz\
+      \ * 2), 1)\n        self._next_tick_time_ns = None\n        self._libc = ctypes.CDLL(ctypes.util.find_library(\"\
+      c\"))\n\n    def general_work(self, input_items, output_items) -> int:\n   \
+      \     # pylint: disable=unused-argument\n        if not self._next_tick_time_ns:\n\
+      \            self._next_tick_time_ns = time.perf_counter_ns()\n        for byte\
+      \ in input_items[0][: self._work_max_samples]:\n            while (\n      \
+      \          self._next_tick_time_ns - time.perf_counter_ns()\n            ) >\
+      \ self._SLEEP_THRESHOLD_NS:\n                _NANOSLEEP(\n                 \
+      \   _Timespec(\n                        0,\n                        # negative\
+      \ values make nanosleep return -1\n                        min(\n          \
+      \                  self._next_tick_time_ns\n                            - time.perf_counter_ns()\n\
+      \                            - self._SLEEP_THRESHOLD_NS,\n                 \
+      \           999999999,\n                        ),\n                    ),\n\
+      \                    None,\n                )\n            while (self._next_tick_time_ns\
+      \ - time.perf_counter_ns()) > 0:\n                pass\n            self._serial_port.write(b\"\
+      \\x01\" if byte else b\"\\0\")\n            self._next_tick_time_ns += self._tick_interval_ns\n\
+      \        self.consume(0, min(len(input_items[0]), self._work_max_samples))\n\
+      \        return 0\n"
+    affinity: ''
+    alias: ''
+    baud_rate: '115200'
+    comment: ''
+    maxoutbuf: '0'
+    minoutbuf: '0'
+    port: '"/dev/ttyUSB0"'
+    sample_rate_hz: sample_rate_hz
+  states:
+    _io_cache: ('Serial Sink Block', 'SerialSinkBlock', [('port', "'/dev/ttyUSB0'"),
+      ('baud_rate', '115200'), ('sample_rate_hz', '1000')], [('0', 'byte', 1)], [],
+      '', [])
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [625, 417]
+    rotation: 0
+    state: true
+- 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: 'False'
+    marker1: '-1'
+    marker10: '-1'
+    marker2: '-1'
+    marker3: '-1'
+    marker4: '-1'
+    marker5: '-1'
+    marker6: '-1'
+    marker7: '-1'
+    marker8: '-1'
+    marker9: '-1'
+    name: '""'
+    nconnections: '1'
+    size: int(sample_rate_hz*2)
+    srate: sample_rate_hz
+    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_FREE
+    tr_slope: qtgui.TRIG_SLOPE_POS
+    tr_tag: '""'
+    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: Signal
+    ymax: '1'
+    ymin: '0'
+    yunit: '""'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [883, 144]
+    rotation: 0
+    state: enabled
+
+connections:
+- [analog_sig_source_x_0, '0', blocks_char_to_float_0, '0']
+- [analog_sig_source_x_0, '0', serial_sink_block, '0']
+- [blocks_char_to_float_0, '0', qtgui_time_sink_x_0, '0']
+
+metadata:
+  file_format: 1