Skip to content

Commit a5b9059

Browse files
committed
Initial commit
0 parents  commit a5b9059

16 files changed

+1512
-0
lines changed

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.directory
2+
*.kdev4
3+
*.csv
4+
__pycache__/
5+
*.egg-info/
6+
dist/

LICENSE.md

Lines changed: 675 additions & 0 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
2+
# zbnt/python-client
3+
4+
Python library for connecting to a ZBNT server
5+
6+
## License
7+
8+
![GPLv3 Logo](https://www.gnu.org/graphics/gplv3-with-text-84x42.png)
9+
10+
This program is free software: you can redistribute it and/or modify
11+
it under the terms of the GNU General Public License as published by
12+
the Free Software Foundation, either version 3 of the License, or
13+
(at your option) any later version.
14+
This program is distributed in the hope that it will be useful,
15+
but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
GNU General Public License for more details.

setup.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#!/usr/bin/env python3
2+
"""
3+
zbnt/python-client
4+
Copyright (C) 2020 Oscar R.
5+
6+
This program is free software: you can redistribute it and/or modify
7+
it under the terms of the GNU General Public License as published by
8+
the Free Software Foundation, either version 3 of the License, or
9+
(at your option) any later version.
10+
11+
This program is distributed in the hope that it will be useful,
12+
but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
GNU General Public License for more details.
15+
16+
You should have received a copy of the GNU General Public License
17+
along with this program. If not, see <https://www.gnu.org/licenses/>.
18+
"""
19+
20+
import setuptools
21+
22+
setuptools.setup(
23+
name = "zbnt-client",
24+
version = "1.0.0",
25+
packages = setuptools.find_packages(),
26+
27+
install_requires=["netifaces"],
28+
29+
author = "Oscar R.",
30+
author_email = "oscar@oscar-rc.dev",
31+
32+
description = "Python library for controlling ZBNT devices",
33+
license="GPLv3",
34+
keywords = "",
35+
url = "https://github.com/zbnt",
36+
project_urls = {
37+
"Source Code": "https://github.com/zbnt/python-client"
38+
},
39+
classifiers = [
40+
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
41+
"Programming Language :: Python :: 3",
42+
"Topic :: System :: Networking",
43+
"Topic :: System :: Networking :: Monitoring",
44+
"Intended Audience :: Developers",
45+
"Development Status :: 4 - Beta"
46+
]
47+
)

zbnt/AxiDevice.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
"""
2+
zbnt/python-client
3+
Copyright (C) 2020 Oscar R.
4+
5+
This program is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU General Public License as published by
7+
the Free Software Foundation, either version 3 of the License, or
8+
(at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
15+
You should have received a copy of the GNU General Public License
16+
along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
"""
18+
19+
from .Enums import *
20+
21+
class AxiDevice:
22+
def __init__(self, dev_id, initial_props):
23+
self.id = dev_id
24+
self.ports = []
25+
26+
for prop_id, prop_bytes in initial_props:
27+
if prop_id == Properties.PROP_PORTS:
28+
self.ports = list(prop_bytes)
29+
30+
def __repr__(self):
31+
return "zbnt.{0}(dev_id={1}, ports={2})".format(self.__class__.__name__, self.id, str(self.ports))
32+
33+
def receive_measurement(self, data):
34+
pass

zbnt/AxiMdio.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"""
2+
zbnt/python-client
3+
Copyright (C) 2020 Oscar R.
4+
5+
This program is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU General Public License as published by
7+
the Free Software Foundation, either version 3 of the License, or
8+
(at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
15+
You should have received a copy of the GNU General Public License
16+
along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
"""
18+
19+
from .Enums import *
20+
from .AxiDevice import *
21+
22+
class AxiMdio(AxiDevice):
23+
def __init__(self, dev_id, initial_props):
24+
super().__init__(dev_id, initial_props)
25+
26+
for prop_id, prop_bytes in initial_props:
27+
if prop_id == Properties.PROP_PHY_ADDR:
28+
self.phys = list(prop_bytes)
29+
30+
def receive_measurement(self, data):
31+
pass

zbnt/DiscoveryClient.py

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
"""
2+
zbnt/python-client
3+
Copyright (C) 2020 Oscar R.
4+
5+
This program is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU General Public License as published by
7+
the Free Software Foundation, either version 3 of the License, or
8+
(at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
15+
You should have received a copy of the GNU General Public License
16+
along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
"""
18+
19+
import random
20+
import asyncio
21+
import netifaces
22+
import ipaddress
23+
24+
from .MessageReceiver import *
25+
26+
class DiscoveryClient(MessageReceiver):
27+
MSG_DISCOVERY_PORT = 5466
28+
29+
def __init__(self, address_list, on_device_discovered):
30+
super().__init__(self.send_broadcast, self.message_received, None)
31+
32+
self.address_list = address_list
33+
self.on_device_discovered = on_device_discovered
34+
35+
def datagram_received(self, data, addr):
36+
self.remote_addr = addr
37+
super().bytes_received(data)
38+
39+
self.status = MsgRxStatus.MSG_RX_MAGIC
40+
self.buffer = b"\x00\x00\x00\x00"
41+
42+
def send_broadcast(self):
43+
self.validator = random.randint(0, 2**64 - 1)
44+
45+
message = MessageReceiver.MSG_MAGIC_IDENTIFIER
46+
message += Messages.MSG_ID_DISCOVERY.to_bytes(2, byteorder="little")
47+
message += b"\x08\x00"
48+
message += self.validator.to_bytes(8, byteorder="little")
49+
50+
for address in self.address_list:
51+
self.transport.sendto(message, (address, DiscoveryClient.MSG_DISCOVERY_PORT))
52+
53+
def message_received(self, msg_id, msg_payload):
54+
if msg_id != Messages.MSG_ID_DISCOVERY or len(msg_payload) <= 67:
55+
return
56+
57+
validator = int.from_bytes(msg_payload[0:8], byteorder='little', signed=False)
58+
59+
if validator != self.validator:
60+
return
61+
62+
device = dict()
63+
64+
device["version"] = (
65+
msg_payload[11],
66+
msg_payload[10],
67+
int.from_bytes(msg_payload[8:10], byteorder='little', signed=False),
68+
msg_payload[12:28].strip(b"\x00").decode("UTF-8"),
69+
msg_payload[28:44].strip(b"\x00").decode("UTF-8"),
70+
"d" if msg_payload[44] else ""
71+
)
72+
73+
device["versionstr"] = "{0}.{1}.{2}".format(*device["version"][0:3])
74+
75+
if len(device["version"][3]) != 0:
76+
device["versionstr"] += "-" + device["version"][3]
77+
78+
if len(device["version"][4]) != 0:
79+
device["versionstr"] += "+" + device["version"][4]
80+
81+
if len(device["version"][5]) != 0:
82+
device["versionstr"] += ".d"
83+
elif len(device["version"][5]) != 0:
84+
device["versionstr"] += "+d"
85+
86+
msg_ip, _ = self.remote_addr
87+
ip4 = str(ipaddress.IPv4Address(msg_payload[48:44:-1]))
88+
ip6 = str(ipaddress.IPv6Address(msg_payload[49:65]))
89+
address_list = []
90+
91+
if ip4 != msg_ip:
92+
return
93+
94+
if ip4 != "0.0.0.0":
95+
address_list.append(ip4)
96+
97+
if ip6 != "::":
98+
address_list.append(ip6)
99+
100+
if len(address_list) == 0:
101+
return
102+
103+
device["address"] = address_list
104+
device["port"] = int.from_bytes(msg_payload[65:67], byteorder='little', signed=False)
105+
device["name"] = msg_payload[67:].decode("UTF-8")
106+
107+
self.on_device_discovered(device)
108+
109+
@staticmethod
110+
async def create(addr, callback):
111+
loop = asyncio.get_running_loop()
112+
113+
_, protocol = await loop.create_datagram_endpoint(
114+
lambda: DiscoveryClient(addr, callback),
115+
remote_addr=None,
116+
family=socket.AF_INET,
117+
allow_broadcast=True
118+
)
119+
120+
return protocol
121+
122+
async def discover_devices(timeout):
123+
address_list = []
124+
device_list = []
125+
126+
# Get broadcast address of every available interface
127+
for iface in netifaces.interfaces():
128+
for addr_family, addr_list in netifaces.ifaddresses(iface).items():
129+
if netifaces.address_families[addr_family] == "AF_INET":
130+
for addr in addr_list:
131+
if "broadcast" in addr:
132+
address_list.append(addr["broadcast"])
133+
134+
# Broadcast DISCOVERY message on every interface
135+
await DiscoveryClient.create(
136+
address_list,
137+
lambda dev: device_list.append(dev)
138+
)
139+
140+
await asyncio.sleep(timeout)
141+
return device_list

zbnt/Enums.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
"""
2+
zbnt/python-client
3+
Copyright (C) 2020 Oscar R.
4+
5+
This program is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU General Public License as published by
7+
the Free Software Foundation, either version 3 of the License, or
8+
(at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
15+
You should have received a copy of the GNU General Public License
16+
along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
"""
18+
19+
from enum import IntEnum, auto
20+
21+
class Messages(IntEnum):
22+
# Added in 2.0.0
23+
24+
MSG_ID_DISCOVERY = 1
25+
MSG_ID_HELLO = 2
26+
MSG_ID_PROGRAM_PL = 3
27+
MSG_ID_RUN_START = 4
28+
MSG_ID_RUN_STOP = 5
29+
MSG_ID_SET_PROPERTY = 6
30+
MSG_ID_GET_PROPERTY = 7
31+
MSG_ID_USER_MESSAGE = 8
32+
33+
MSG_ID_EXTENDED = 0x7FFF
34+
MSG_ID_MEASUREMENT = 0x8000
35+
36+
class Properties(IntEnum):
37+
# Added in 2.0.0
38+
39+
PROP_ENABLE = 1
40+
PROP_ENABLE_LOG = auto()
41+
PROP_ENABLE_BURST = auto()
42+
PROP_ENABLE_SCRIPT = auto()
43+
PROP_ENABLE_PATTERN = auto()
44+
PROP_ENABLE_BROADCAST = auto()
45+
46+
PROP_TIMER_MODE = auto()
47+
PROP_TIMER_TIME = auto()
48+
PROP_TIMER_LIMIT = auto()
49+
50+
PROP_FRAME_SIZE = auto()
51+
PROP_FRAME_GAP = auto()
52+
PROP_FRAME_PADDING = auto()
53+
PROP_FRAME_TEMPLATE = auto()
54+
PROP_FRAME_PATTERN = auto()
55+
PROP_FRAME_SCRIPT = auto()
56+
PROP_FRAME_SCRIPT_NAME = auto()
57+
58+
PROP_BURST_TIME_ON = auto()
59+
PROP_BURST_TIME_OFF = auto()
60+
61+
PROP_MAC_ADDR = auto()
62+
PROP_IP_ADDR = auto()
63+
PROP_TIMEOUT = auto()
64+
65+
PROP_OVERFLOW_COUNT = auto()
66+
PROP_SAMPLE_PERIOD = auto()
67+
PROP_LFSR_SEED = auto()
68+
PROP_RESET = auto()
69+
70+
PROP_PORTS = auto()
71+
PROP_FEATURE_BITS = auto()
72+
PROP_NUM_SCRIPTS = auto()
73+
PROP_MAX_TEMPLATE_SIZE = auto()
74+
PROP_MAX_SCRIPT_SIZE = auto()
75+
PROP_FIFO_SIZE = auto()
76+
PROP_PHY_ADDR = auto()
77+
PROP_CLOCK_FREQ = auto()
78+
79+
class Devices(IntEnum):
80+
# Added in 2.0.0
81+
82+
DEV_AXI_DMA = 1
83+
DEV_AXI_MDIO = auto()
84+
DEV_DMA_BUFFER = auto()
85+
DEV_SIMPLE_TIMER = auto()
86+
DEV_FRAME_DETECTOR = auto()
87+
DEV_STATS_COLLECTOR = auto()
88+
DEV_LATENCY_MEASURER = auto()
89+
DEV_TRAFFIC_GENERATOR = auto()

0 commit comments

Comments
 (0)