qlsdk2 0.3.0a2__tar.gz → 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. {qlsdk2-0.3.0a2 → qlsdk2-0.4.0}/PKG-INFO +2 -2
  2. {qlsdk2-0.3.0a2 → qlsdk2-0.4.0}/setup.py +4 -10
  3. {qlsdk2-0.3.0a2 → qlsdk2-0.4.0}/src/qlsdk/__init__.py +1 -0
  4. qlsdk2-0.4.0/src/qlsdk/core/__init__.py +5 -0
  5. qlsdk2-0.4.0/src/qlsdk/core/crc/__init__.py +5 -0
  6. qlsdk2-0.4.0/src/qlsdk/core/crc/crctools.py +95 -0
  7. qlsdk2-0.4.0/src/qlsdk/core/device.py +25 -0
  8. qlsdk2-0.4.0/src/qlsdk/core/entity/__init__.py +92 -0
  9. qlsdk2-0.4.0/src/qlsdk/core/exception.py +0 -0
  10. qlsdk2-0.4.0/src/qlsdk/core/filter/__init__.py +1 -0
  11. qlsdk2-0.4.0/src/qlsdk/core/filter/norch.py +59 -0
  12. qlsdk2-0.4.0/src/qlsdk/core/local.py +34 -0
  13. qlsdk2-0.4.0/src/qlsdk/core/message/__init__.py +2 -0
  14. qlsdk2-0.4.0/src/qlsdk/core/message/command.py +324 -0
  15. qlsdk2-0.4.0/src/qlsdk/core/message/tcp.py +0 -0
  16. qlsdk2-0.4.0/src/qlsdk/core/message/udp.py +96 -0
  17. qlsdk2-0.4.0/src/qlsdk/core/network/__init__.py +34 -0
  18. qlsdk2-0.4.0/src/qlsdk/core/network/monitor.py +55 -0
  19. qlsdk2-0.4.0/src/qlsdk/core/utils.py +70 -0
  20. qlsdk2-0.4.0/src/qlsdk/persist/__init__.py +2 -0
  21. qlsdk2-0.4.0/src/qlsdk/persist/rsc_edf.py +299 -0
  22. qlsdk2-0.4.0/src/qlsdk/rsc/__init__.py +7 -0
  23. qlsdk2-0.4.0/src/qlsdk/rsc/command/__init__.py +214 -0
  24. qlsdk2-0.4.0/src/qlsdk/rsc/command/message.py +239 -0
  25. qlsdk2-0.4.0/src/qlsdk/rsc/device_manager.py +119 -0
  26. qlsdk2-0.4.0/src/qlsdk/rsc/discover.py +87 -0
  27. qlsdk2-0.4.0/src/qlsdk/rsc/eegion.py +360 -0
  28. qlsdk2-0.4.0/src/qlsdk/rsc/entity.py +447 -0
  29. qlsdk2-0.4.0/src/qlsdk/rsc/paradigm.py +313 -0
  30. qlsdk2-0.4.0/src/qlsdk/rsc/proxy.py +76 -0
  31. qlsdk2-0.4.0/src/qlsdk/sdk/libs/libAr4SDK.dll +0 -0
  32. qlsdk2-0.4.0/src/qlsdk/sdk/libs/libwinpthread-1.dll +0 -0
  33. {qlsdk2-0.3.0a2 → qlsdk2-0.4.0}/src/qlsdk2.egg-info/PKG-INFO +2 -2
  34. qlsdk2-0.4.0/src/qlsdk2.egg-info/SOURCES.txt +48 -0
  35. {qlsdk2-0.3.0a2 → qlsdk2-0.4.0}/src/qlsdk2.egg-info/requires.txt +1 -1
  36. qlsdk2-0.4.0/test/test.py +168 -0
  37. qlsdk2-0.3.0a2/src/qlsdk/persist/__init__.py +0 -1
  38. qlsdk2-0.3.0a2/src/qlsdk2.egg-info/SOURCES.txt +0 -19
  39. {qlsdk2-0.3.0a2 → qlsdk2-0.4.0}/README.md +0 -0
  40. {qlsdk2-0.3.0a2 → qlsdk2-0.4.0}/setup.cfg +0 -0
  41. {qlsdk2-0.3.0a2 → qlsdk2-0.4.0}/src/qlsdk/ar4/__init__.py +0 -0
  42. {qlsdk2-0.3.0a2 → qlsdk2-0.4.0}/src/qlsdk/ar4m/__init__.py +0 -0
  43. {qlsdk2-0.3.0a2 → qlsdk2-0.4.0}/src/qlsdk/persist/edf.py +0 -0
  44. {qlsdk2-0.3.0a2 → qlsdk2-0.4.0}/src/qlsdk/sdk/__init__.py +0 -0
  45. {qlsdk2-0.3.0a2 → qlsdk2-0.4.0}/src/qlsdk/sdk/ar4sdk.py +0 -0
  46. {qlsdk2-0.3.0a2 → qlsdk2-0.4.0}/src/qlsdk/sdk/hub.py +0 -0
  47. {qlsdk2-0.3.0a2 → qlsdk2-0.4.0}/src/qlsdk/x8/__init__.py +0 -0
  48. {qlsdk2-0.3.0a2 → qlsdk2-0.4.0}/src/qlsdk/x8m/__init__.py +0 -0
  49. {qlsdk2-0.3.0a2 → qlsdk2-0.4.0}/src/qlsdk2.egg-info/dependency_links.txt +0 -0
  50. {qlsdk2-0.3.0a2 → qlsdk2-0.4.0}/src/qlsdk2.egg-info/top_level.txt +0 -0
  51. {qlsdk2-0.3.0a2 → qlsdk2-0.4.0}/test/test_ar4m.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: qlsdk2
3
- Version: 0.3.0a2
3
+ Version: 0.4.0
4
4
  Summary: SDK for quanlan device
5
5
  Home-page: https://github.com/hehuajun/qlsdk
6
6
  Author: hehuajun
@@ -12,7 +12,7 @@ Requires-Python: >=3.9
12
12
  Description-Content-Type: text/markdown
13
13
  Requires-Dist: loguru>=0.6.0
14
14
  Requires-Dist: numpy>=1.23.5
15
- Requires-Dist: pyedflib>=0.1.40
15
+ Requires-Dist: bitarray>=1.5.3
16
16
  Provides-Extra: dev
17
17
  Requires-Dist: pytest>=6.0; extra == "dev"
18
18
  Requires-Dist: twine>=3.0; extra == "dev"
@@ -6,7 +6,7 @@ with open("README.md", "r") as fh:
6
6
 
7
7
  setuptools.setup(
8
8
  name="qlsdk2",
9
- version="0.3.0a2",
9
+ version="0.4.0",
10
10
  author="hehuajun",
11
11
  author_email="hehuajun@eegion.com",
12
12
  description="SDK for quanlan device",
@@ -24,13 +24,7 @@ setuptools.setup(
24
24
  install_requires=open("requirements.txt").read().splitlines(),
25
25
  include_package_data=True,
26
26
  package_data={
27
- # "src/qlsdk/ar4m/": ["libs/*.dll"],
28
- "qlsdk/sdk": ["libs/*.dll"],
29
- "":["*.txt", "*.md"]
30
- },
31
- # entry_points={
32
- # 'console_scripts': [
33
- # 'qlsdk-cli=qlsdk.cli:main', # 如果有命令行工具
34
- # ],
35
- # },
27
+ # "qlsdk2": ["/**/*.dll"],
28
+ "qlsdk": ["./**/*.dll"]
29
+ }
36
30
  )
@@ -5,6 +5,7 @@ from .ar4m import AR4M
5
5
  from .ar4 import AR4
6
6
  from .x8 import X8
7
7
  from .x8m import X8M
8
+ from .rsc import *
8
9
 
9
10
  __all__ = ['AR4M', 'AR4', 'AR4Packet', 'X8']
10
11
 
@@ -0,0 +1,5 @@
1
+ from qlsdk.core.crc import *
2
+ from qlsdk.core.message import *
3
+ from qlsdk.core.local import *
4
+ from qlsdk.core.utils import *
5
+ from qlsdk.core.entity import *
@@ -0,0 +1,5 @@
1
+ from .crctools import crc16
2
+
3
+ # packet crc validate
4
+ def check_crc(data):
5
+ return int.from_bytes(data[-2:], 'little') == crc16(data[:-2])
@@ -0,0 +1,95 @@
1
+ # len=256
2
+ CRC_HI = [
3
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
4
+ 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
5
+ 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
6
+ 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
7
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
8
+ 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
9
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
10
+ 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
11
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
12
+ 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
13
+ 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
14
+ 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
15
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
16
+ 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
17
+ 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
18
+ 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
19
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
20
+ 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
21
+ 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
22
+ 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
23
+ 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
24
+ 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
25
+ 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
26
+ 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
27
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
28
+ 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
29
+ ]
30
+
31
+ # len=256
32
+ CRC_LO = [
33
+ 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,
34
+ 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
35
+ 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
36
+ 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
37
+ 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
38
+ 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
39
+ 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
40
+ 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
41
+ 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
42
+ 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
43
+ 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,
44
+ 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
45
+ 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,
46
+ 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
47
+ 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
48
+ 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
49
+ 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,
50
+ 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
51
+ 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,
52
+ 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
53
+ 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
54
+ 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
55
+ 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
56
+ 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
57
+ 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
58
+ 0x43, 0x83, 0x41, 0x81, 0x80, 0x40
59
+ ]
60
+
61
+ def crc16(data):
62
+ crcHi = 0xFF
63
+ crcLo = 0xFF
64
+ for i in range(len(data)):
65
+ index = crcHi ^ data[i]
66
+ crcHi = crcLo ^ CRC_HI[index]
67
+ crcLo = CRC_LO[index]
68
+
69
+ return crcHi << 8 | crcLo
70
+
71
+ class CRCEnum(object):
72
+ CRC8 = 8
73
+ CRC16 = 16
74
+ CRC32 = 32
75
+
76
+ class CRC(object):
77
+ def __init__(self, width=CRCEnum.CRC16) :
78
+ self.width = width
79
+ self.crcHi = 0xFF
80
+ self.crcLo = 0xFF
81
+
82
+ def _init(self):
83
+ if self.width == CRCEnum.CRC16:
84
+ self.crcHi = 0xFF
85
+ self.crcLo = 0xFF
86
+
87
+ def calc(self, data):
88
+ for i in range(len(data)):
89
+ index = self.crcHi ^ data[i]
90
+ self.crcHi = self.crcLo ^ CRC_HI[index]
91
+ self.crcLo = CRC_LO[index]
92
+
93
+ def checksum(self):
94
+ return self.crcHi << 8 | self.crcLo
95
+
@@ -0,0 +1,25 @@
1
+ # from abc import ABC, abstractmethod
2
+
3
+ class BaseDevice(object):
4
+ def __init__(self, socket = None):
5
+ self.socket = socket
6
+ self.device_name = None
7
+ self.device_type = None
8
+ self.device_id = None
9
+
10
+ @property
11
+ def acq_channels(self) :
12
+ return None
13
+ @property
14
+ def sample_range(self) -> int:
15
+ return None
16
+ @property
17
+ def sample_rate(self) -> int:
18
+ return None
19
+ @property
20
+ def sample_num(self) -> int:
21
+ return 10
22
+ @property
23
+ def resolution(self):
24
+ return 24
25
+
@@ -0,0 +1,92 @@
1
+ from qlsdk.core.utils import to_channels
2
+ from loguru import logger
3
+
4
+ class DataPacket(object):
5
+ def __init__(self, device_type, device_id, channels, data):
6
+ self.data = data
7
+ self.channels = None
8
+
9
+
10
+ class RscPacket(object):
11
+ def __init__(self):
12
+ self.time_stamp = None
13
+ self.pkg_id = None
14
+ self.result = None
15
+ self.channels = None
16
+ self.origin_sample_rate = None
17
+ self.sample_rate = None
18
+ self.sample_num = None
19
+ self.resolution = None
20
+ self.filter = None
21
+ self.data_len = None
22
+ self.trigger = None
23
+ self.eeg = None
24
+
25
+ def transfer(self, body: bytes) -> 'RscPacket':
26
+ self.time_stamp = int.from_bytes(body[0:8], 'little')
27
+ self.result = body[8]
28
+ self.pkg_id = int.from_bytes(body[9: 13], 'little')
29
+ self.channels = to_channels(body[13: 45])
30
+ self.origin_sample_rate = int.from_bytes(body[45: 49], 'little')
31
+ self.sample_rate = int.from_bytes(body[49: 53], 'little')
32
+ self.sample_num = int.from_bytes(body[53: 57], 'little')
33
+ self.resolution = int(int(body[57]) / 8)
34
+ self.filter = body[58]
35
+ self.data_len = int.from_bytes(body[59: 63], 'little')
36
+ # 步径 相同通道的点间隔
37
+ step = int(len(self.channels) * self.resolution + 4)
38
+ self.trigger = [int.from_bytes(body[i:i+4], 'little') for i in range(63, len(body) - 3, step)]
39
+ b_eeg = body[63:]
40
+ ch_num = len(self.channels)
41
+ self.eeg = [
42
+ [
43
+ int.from_bytes(b_eeg[i * self.resolution + 4 + j * step:i * self.resolution + 4 + j * step + 3], 'big', signed=True)
44
+ for j in range(self.sample_num)
45
+ ]
46
+ for i in range(ch_num)
47
+ ]
48
+
49
+ # logger.trace(self)
50
+ return self
51
+
52
+ def __str__(self):
53
+ return f"""
54
+ time_stamp: {self.time_stamp}
55
+ pkg_id: {self.pkg_id}
56
+ origin_sample_rate: {self.origin_sample_rate}
57
+ sample_rate: {self.sample_rate}
58
+ sample_num: {self.sample_num}
59
+ resolution: {self.resolution}
60
+ filter: {self.filter}
61
+ channels: {self.channels}
62
+ data len: {self.data_len}
63
+ trigger: {self.trigger}
64
+ eeg: {self.eeg}
65
+ """
66
+
67
+ class ImpedancePacket(object):
68
+ def __init__(self):
69
+ self.time_stamp = None
70
+ self.pkg_id = None
71
+ self.result = None
72
+ self.channels = None
73
+ self.data_len = None
74
+ self.impedance = None
75
+
76
+ def transfer(self, body:bytes) -> 'ImpedancePacket':
77
+ self.time_stamp = int.from_bytes(body[0:8], 'little')
78
+ self.result = body[8]
79
+ self.pkg_id = int.from_bytes(body[9: 13], 'little')
80
+ self.channels = to_channels(body[13: 45])
81
+
82
+ logger.debug(f"impedance: {self}")
83
+
84
+ def __str__(self):
85
+ return f"""
86
+ time_stamp: {self.time_stamp}
87
+ pkg_id: {self.pkg_id}
88
+ result: {self.result}
89
+ channels: {self.channels}
90
+ data len: {self.data_len}
91
+ impedance: {self.impedance}
92
+ """
File without changes
@@ -0,0 +1 @@
1
+ from .norch import notch_filter_50hz
@@ -0,0 +1,59 @@
1
+ import numpy as np
2
+
3
+ def notch_filter_50hz(data: np.ndarray,
4
+ fs: float,
5
+ notch_width: float = 2.0,
6
+ max_harmonics: int = 5) -> np.ndarray:
7
+ """
8
+ 多通道50Hz谐波陷波滤波器
9
+
10
+ 参数:
11
+ data : 输入信号,形状为 [通道数, 采样点数] 的二维数组
12
+ fs : 采样频率 (Hz)
13
+ notch_width : 陷波带宽 (Hz),默认2Hz
14
+ max_harmonics : 最大谐波次数,默认处理前10次谐波
15
+
16
+ 返回:
17
+ 滤波后的信号,形状与输入相同
18
+ """
19
+ # 输入校验
20
+ if data.ndim != 2:
21
+ raise ValueError("输入必须为二维数组 [channels, samples]")
22
+ if fs <= 0:
23
+ raise ValueError("采样频率必须为正数")
24
+
25
+ n_channels, n_samples = data.shape
26
+ nyquist = fs / 2
27
+ processed = np.empty_like(data)
28
+
29
+ # 生成频率轴
30
+ freqs = np.fft.fftfreq(n_samples, 1/fs)
31
+
32
+ for ch in range(n_channels):
33
+ # FFT变换
34
+ fft_data = np.fft.fft(data[ch])
35
+
36
+ # 生成陷波掩模
37
+ mask = np.ones(n_samples, dtype=bool)
38
+
39
+ # 计算需要消除的谐波
40
+ for k in range(1, max_harmonics+1):
41
+ target_freq = 50 * k
42
+
43
+ # 超过奈奎斯特频率则停止
44
+ if target_freq > nyquist:
45
+ break
46
+
47
+ # 生成陷波范围
48
+ notch_range = (np.abs(freqs - target_freq) <= notch_width/2) | \
49
+ (np.abs(freqs + target_freq) <= notch_width/2)
50
+
51
+ mask &= ~notch_range
52
+
53
+ # 应用频域滤波
54
+ filtered_fft = fft_data * mask
55
+
56
+ # 逆变换并取实数部分
57
+ processed[ch] = np.real(np.fft.ifft(filtered_fft))
58
+
59
+ return processed
@@ -0,0 +1,34 @@
1
+ import os
2
+ import socket
3
+ from time import time
4
+
5
+ # 读取本机全部ip列表
6
+ # return list
7
+ def get_ips():
8
+ return socket.gethostbyname_ex(socket.gethostname())[-1]
9
+
10
+ # 读取本机的ip地址
11
+ # return str
12
+ def get_ip():
13
+ # 优先读取活跃ip地址
14
+ routes = os.popen('route print').readlines()
15
+ for idx, item in enumerate(routes):
16
+ if ' 0.0.0.0 ' in item and len(item.split()) > 2:
17
+ return item.split()[-2]
18
+
19
+ # 取第一个地址
20
+ ips = get_ips()
21
+ if len(ips) > 0 :
22
+ return ips[0]
23
+
24
+ raise ValueError("Ip address not exists.")
25
+
26
+ def get_cache(fname=None):
27
+ if fname is None:
28
+ fname = int(time())
29
+
30
+ cpath = os.path.abspath(os.path.abspath(__file__))
31
+ print(cpath)
32
+
33
+ if __name__ == '__main__':
34
+ get_cache()
@@ -0,0 +1,2 @@
1
+ from .command import *
2
+ from .udp import UDPMessage