Browse Source

added arduino sketch and dummy flowchart to prepare for transmission

Fabian Peter Hammerle 3 years ago
parent
commit
2e7ca3bd24

+ 4 - 4
receive/plot.grc

@@ -186,7 +186,7 @@ blocks:
     bus_structure: null
     coordinate: [557, 186]
     rotation: 0
-    state: disabled
+    state: enabled
 - name: qtgui_time_raster_sink_x_0_0
   id: qtgui_time_raster_sink_x
   parameters:
@@ -248,7 +248,7 @@ blocks:
   id: epy_block
   parameters:
     _source_code: "import gnuradio\nimport numpy\nimport serial\n\n\nclass SerialSourceBlock(gnuradio.gr.sync_block):\n\
-      \    def __init__(\n        self,\n        port=\"/dev/ttyUSB0\",\n        baud_rate=115200,\n\
+      \    def __init__(\n        self,\n        port=\"/dev/ttyUSB1\",\n        baud_rate=115200,\n\
       \        buffer_max_length=10,\n        timeout=2,\n        invert=False,\n\
       \    ):\n        # pylint: disable=too-many-arguments\n        gnuradio.gr.sync_block.__init__(\n\
       \            self, name=\"Serial Source Block\", in_sig=None, out_sig=[numpy.uint8]\n\
@@ -272,10 +272,10 @@ blocks:
     invert: 'True'
     maxoutbuf: '0'
     minoutbuf: '0'
-    port: '''/dev/ttyUSB0'''
+    port: '''/dev/ttyUSB1'''
     timeout: '2'
   states:
-    _io_cache: ('Serial Source Block', 'SerialSourceBlock', [('port', "'/dev/ttyUSB0'"),
+    _io_cache: ('Serial Source Block', 'SerialSourceBlock', [('port', "'/dev/ttyUSB1'"),
       ('baud_rate', '115200'), ('buffer_max_length', '10'), ('timeout', '2'), ('invert',
       'False')], [], [('0', 'byte', 1)], '', [])
     bus_sink: false

+ 1 - 1
receive/serial_source_block.py

@@ -6,7 +6,7 @@ import serial
 class SerialSourceBlock(gnuradio.gr.sync_block):
     def __init__(
         self,
-        port="/dev/ttyUSB0",
+        port="/dev/ttyUSB1",
         baud_rate=115200,
         buffer_max_length=10,
         timeout=2,

+ 3 - 0
transmit/.gitignore

@@ -0,0 +1,3 @@
+/build-*/
+/circuit.pro
+/transmit.py

+ 6 - 0
transmit/Makefile

@@ -0,0 +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 $^

+ 20 - 0
transmit/README.md

@@ -0,0 +1,20 @@
+## sleep
+
+cpython's `time.sleep` calls `pysleep`:
+https://github.com/python/cpython/blob/v3.8.5/Modules/timemodule.c#L338
+
+`pysleep` calls `Sleep`, probably the one defined in `Modules/_tkinter.c`, with millisecond precision (rounding up):
+https://github.com/python/cpython/blob/v3.8.5/Modules/timemodule.c#L1873
+
+`Modules/_tkinter.c:Sleep` (https://github.com/python/cpython/blob/v3.8.5/Modules/_tkinter.c#L361):
+```c
+static void
+Sleep(int milli)
+{
+    /* XXX Too bad if you don't have select(). */
+    struct timeval t;
+    t.tv_sec = milli/1000;
+    t.tv_usec = (milli%1000) * 1000;
+    select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t);
+}
+```

+ 16 - 0
transmit/arduino-sketch.ino

@@ -0,0 +1,16 @@
+const uint8_t PIN = 4;
+
+void setup() {
+    // $ stty -F /dev/ttyUSB0 | grep speed
+    Serial.begin(115200);
+    pinMode(PIN, OUTPUT);
+}
+
+void loop() {
+    // https://www.arduino.cc/reference/en/language/functions/communication/serial/read/
+    if (Serial.available() > 0) {
+        // $ printf '\0' > /dev/ttyUSB0
+        // $ printf '\x01' > /dev/ttyUSB0
+        digitalWrite(PIN, (Serial.read() > 0) ? HIGH : LOW);
+    }
+}

+ 93 - 0
transmit/circuit.sch

@@ -0,0 +1,93 @@
+EESchema Schematic File Version 4
+EELAYER 30 0
+EELAYER END
+$Descr A4 11693 8268
+encoding utf-8
+Sheet 1 1
+Title ""
+Date ""
+Rev ""
+Comp ""
+Comment1 ""
+Comment2 ""
+Comment3 ""
+Comment4 ""
+$EndDescr
+$Comp
+L MCU_Module:Arduino_UNO_R3 A?
+U 1 1 5FE9E0D1
+P 6600 2750
+F 0 "A?" H 6600 3931 50  0001 C CNN
+F 1 "Arduino_UNO_R3" H 6600 3839 50  0000 C CNN
+F 2 "Module:Arduino_UNO_R3" H 6600 2750 50  0001 C CIN
+F 3 "https://www.arduino.cc/en/Main/arduinoBoardUno" H 6600 2750 50  0001 C CNN
+	1    6600 2750
+	1    0    0    -1  
+$EndComp
+$Comp
+L LED:TSAL4400 D?
+U 1 1 5FE9F625
+P 5350 1550
+F 0 "D?" H 5300 1840 50  0001 C CNN
+F 1 "TSAL6200" H 5300 1749 50  0000 C CNN
+F 2 "" H 5350 1725 50  0001 C CNN
+F 3 "https://www.vishay.com/docs/81010/tsal6200.pdf" H 5300 1550 50  0001 C CNN
+	1    5350 1550
+	1    0    0    -1  
+$EndComp
+$Comp
+L Device:R R?
+U 1 1 5FEA0953
+P 5800 1550
+F 0 "R?" H 5870 1596 50  0001 L CNN
+F 1 "47Ω" V 5685 1550 50  0000 C CNN
+F 2 "" V 5730 1550 50  0001 C CNN
+F 3 "~" H 5800 1550 50  0001 C CNN
+	1    5800 1550
+	0    1    1    0   
+$EndComp
+Wire Wire Line
+	5150 1550 5050 1550
+Wire Wire Line
+	6700 3950 6700 3850
+$Comp
+L Transistor_FET:BUZ11 Q?
+U 1 1 5FEA0605
+P 5150 2550
+F 0 "Q?" H 5355 2596 50  0001 L CNN
+F 1 "BUZ11" H 5355 2550 50  0000 L CNN
+F 2 "Package_TO_SOT_THT:TO-220-3_Vertical" H 5400 2475 50  0001 L CIN
+F 3 "http://www.fairchildsemi.com/ds/BU/BUZ11.pdf" H 5150 2550 50  0001 L CNN
+	1    5150 2550
+	-1   0    0    -1  
+$EndComp
+Wire Wire Line
+	6800 1750 6800 1550
+$Comp
+L Device:R R?
+U 1 1 5FEADCC4
+P 5650 2550
+F 0 "R?" H 5720 2596 50  0001 L CNN
+F 1 "10kΩ" V 5535 2550 50  0000 C CNN
+F 2 "" V 5580 2550 50  0001 C CNN
+F 3 "~" H 5650 2550 50  0001 C CNN
+	1    5650 2550
+	0    1    1    0   
+$EndComp
+Wire Wire Line
+	6100 2550 5800 2550
+Wire Wire Line
+	5050 1550 5050 2350
+Wire Wire Line
+	5350 2550 5500 2550
+Wire Wire Line
+	5050 2750 5050 3950
+Wire Wire Line
+	5050 3950 6700 3950
+Text Notes 5100 1750 0    50   ~ 0
+1.29V 67mA when pin high
+Wire Wire Line
+	5950 1550 6800 1550
+Wire Wire Line
+	5450 1550 5650 1550
+$EndSCHEMATC

+ 75 - 0
transmit/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/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: '1195'
+  states:
+    bus_sink: false
+    bus_source: false
+    bus_structure: null
+    coordinate: [670, 313]
+    rotation: 0
+    state: enabled
+- name: analog_sig_source_x_0
+  id: analog_sig_source_x
+  parameters:
+    affinity: ''
+    alias: ''
+    amp: '1'
+    comment: ''
+    freq: '10'
+    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: 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*1)
+    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
+- 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
+
+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