aboutsummaryrefslogtreecommitdiffstats
path: root/src/gr-fadingui/python/netsink.py
blob: 8851fe9880776090fa1ca849c43f2291bc9390d4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2021 Sara Cinzia Halter, Naoki Pross.

import os
import socket
from urllib.parse import urlparse

import numpy as np
from gnuradio import gr

from fadingui.logger import get_logger
log = get_logger("netsink")

class netsink(gr.sync_block):
    """
    Sink that sends the data over the network using UDP.
    Keep in mind that is quite slow.
    """
    def __init__(self, address, dtype, vlen):
        to_numpy = {
            "complex": np.complex64,
            "float": np.float32,
            "int": np.int32,
            "short": np.short,
            "byte": np.byte,
        }

        dt = to_numpy[dtype]
        if vlen > 1:
            dt = np.dtype(dt, (vlen,))

        gr.sync_block.__init__(self,
            name="Network Sink",
            in_sig=[dt],
            out_sig=None)

        # Create a socket and parse remote machine url
        self.url = urlparse(address)
        self.srv = None

        if self.url.scheme == "udp":
            log.debug(f"Creating UDP socket to {self.srv}")
            self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            self.srv = (self.url.hostname, self.url.port)
            self.socket.connect(self.srv)

        elif self.url.scheme == "file":
            log.debug(f"Creating UNIX file socket to {self.url.path}")
            self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
            self.srv = self.url.path
            try:
                self.socket.connect(self.srv)
            except FileNotFoundError:
                log.error("Cannot find socket file, is the server (GUI) running?")
                raise

        else:
            raise NotImplemented


    def send(self, data):
        """
        Send the data to self.srv

        @param data Data as python bytes
        @return Number of bytes that were actually sent
        """
        assert type(data) == bytes
        try:
            return self.socket.sendto(data, self.srv)
        except socket.error as err:
            log.warn(f"No data was sent: {err}")
            return 0

    def encode(self, data):
        """
        Encode the data into a dead simple format

        @param data Array like type
        @return Bytes of ASCII encoded comma separated string of numbers
        """
        # FIXME: this could be (very) slow, is there a faster way with numpy?
        # Maybe numpy.array2string
        values = "[" + ",".join(map(str, data)) + "]"
        return bytes(values, "ascii")

    def work(self, input_items, output_items):
        # send only every k-th sample
        inp = input_items[0][::2]
        inp_len = len(inp)
        blocksize = 1024

        # Check that the packet is not huge
        if len(inp) < blocksize:
            self.send(self.encode(inp))
        else:
            # compute how to split inp into blocks
            nblocks = inp_len // blocksize
            index = blocksize * nblocks

            # send blocks
            blocks = np.array(inp[:index]).reshape((blocksize, nblocks))
            for block in blocks:
                self.send(self.encode(block))

            # sent the rest
            self.send(self.encode(inp[index:]))

        return len(inp)