tlkcore 255.255.255__cp38-none-win_amd64.whl
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.
- tlkcore/TLKCoreService.cp38-win_amd64.pyd +0 -0
- tlkcore/TMYBeamConfig.py +211 -0
- tlkcore/TMYCommService.cp38-win_amd64.pyd +0 -0
- tlkcore/TMYDFU.cp38-win_amd64.pyd +0 -0
- tlkcore/TMYLogging.py +112 -0
- tlkcore/TMYPublic.py +291 -0
- tlkcore/TMYUtils.cp38-win_amd64.pyd +0 -0
- tlkcore/__init__.py +1 -0
- tlkcore/db/TMYDBQueryer.cp38-win_amd64.pyd +0 -0
- tlkcore/db/__init__.py +3 -0
- tlkcore/tmydev/DevBBoard.cp38-win_amd64.pyd +0 -0
- tlkcore/tmydev/DevBBox.cp38-win_amd64.pyd +0 -0
- tlkcore/tmydev/DevBBoxLite.cp38-win_amd64.pyd +0 -0
- tlkcore/tmydev/DevBBoxOne.cp38-win_amd64.pyd +0 -0
- tlkcore/tmydev/DevCloverCell.cp38-win_amd64.pyd +0 -0
- tlkcore/tmydev/DevPD.cp38-win_amd64.pyd +0 -0
- tlkcore/tmydev/DevRIS.cp38-win_amd64.pyd +0 -0
- tlkcore/tmydev/DevUDB.cp38-win_amd64.pyd +0 -0
- tlkcore/tmydev/DevUDBox.cp38-win_amd64.pyd +0 -0
- tlkcore/tmydev/DevUDC.cp38-win_amd64.pyd +0 -0
- tlkcore/tmydev/DevUDM.cp38-win_amd64.pyd +0 -0
- tlkcore/tmydev/RIS_pattern_generator.cp38-win_amd64.pyd +0 -0
- tlkcore/tmydev/TMYTableManager.cp38-win_amd64.pyd +0 -0
- tlkcore/tmydev/__init__.py +13 -0
- tlkcore/tmydev/device.cp38-win_amd64.pyd +0 -0
- tlkcore-255.255.255.dist-info/LICENSE.txt +9 -0
- tlkcore-255.255.255.dist-info/METADATA +113 -0
- tlkcore-255.255.255.dist-info/RECORD +30 -0
- tlkcore-255.255.255.dist-info/WHEEL +5 -0
- tlkcore-255.255.255.dist-info/top_level.txt +1 -0
|
Binary file
|
tlkcore/TMYBeamConfig.py
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import csv
|
|
2
|
+
import logging
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
from tlkcore.TMYPublic import RetCode, RFMode, BeamType
|
|
6
|
+
|
|
7
|
+
logger = logging.getLogger("TMYBeamConfig")
|
|
8
|
+
|
|
9
|
+
class TMYBeamConfig():
|
|
10
|
+
def __init__(self, sn:str, service, path="CustomBatchBeams.csv", delimiter=","):
|
|
11
|
+
"""
|
|
12
|
+
Test for parsing batch beam configs then apply it,
|
|
13
|
+
please edit gains to feet available gain range for your BeamForm devices, e.g., BBoxOne
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
sn (str): Device serail number
|
|
17
|
+
service (_type_): TLKCoreService instance
|
|
18
|
+
path (str, optional): _description_. Defaults to "CustomBatchBeams.csv".
|
|
19
|
+
delimiter (str, optional): delimiter in csv. Defaults to ",".
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
self.__sn = sn
|
|
23
|
+
self.__service = service
|
|
24
|
+
self.__config = None
|
|
25
|
+
if not os.path.exists(path):
|
|
26
|
+
logger.error("Not exist: %s" %path)
|
|
27
|
+
return
|
|
28
|
+
self.__config = self.__parse(path, delimiter)
|
|
29
|
+
|
|
30
|
+
def __parse(self, path:str, delimiter:str):
|
|
31
|
+
logger.info("Start to parsing...")
|
|
32
|
+
try:
|
|
33
|
+
aakit_selected = True if self.__service.getAAKitInfo(self.__sn).RetCode is RetCode.OK else False
|
|
34
|
+
logger.info("[AppyBatchBeams] AAKit %sselected" %"" if aakit_selected else "NOT ")
|
|
35
|
+
|
|
36
|
+
file = open(path)
|
|
37
|
+
reader = csv.reader((_.replace('\x00', '') for _ in file), delimiter=delimiter)
|
|
38
|
+
custom = { 'TX': {}, 'RX': {}}
|
|
39
|
+
# Parsing CSV
|
|
40
|
+
for col in reader:
|
|
41
|
+
if len(col) == 0 or len(col[0]) == 0 or col[0] == 'Mode':
|
|
42
|
+
continue
|
|
43
|
+
# print(col)
|
|
44
|
+
mode_name = col[0]
|
|
45
|
+
beamID = int(col[1])
|
|
46
|
+
beam_type = BeamType(int(col[2]))
|
|
47
|
+
|
|
48
|
+
if beam_type is BeamType.BEAM:
|
|
49
|
+
if not aakit_selected:
|
|
50
|
+
logger.warning("PhiA mode not support whole beam config -> skip")
|
|
51
|
+
continue
|
|
52
|
+
# Fetch col 3~5 for db,theta,phi
|
|
53
|
+
config = [col[i] for i in range(3, 6)]
|
|
54
|
+
else: #CHANNEL
|
|
55
|
+
ch = int(col[6])
|
|
56
|
+
# Fetch col 7~9 for sw,db,deg
|
|
57
|
+
config = {str(ch): [col[i] for i in range(7, 10)]}
|
|
58
|
+
|
|
59
|
+
if custom[mode_name].get(str(beamID)) is None:
|
|
60
|
+
# Create new beam config
|
|
61
|
+
beam = {'beam_type': beam_type.value, 'config': config}
|
|
62
|
+
custom[mode_name][str(beamID)] = beam
|
|
63
|
+
else:
|
|
64
|
+
# If exist, replace or add new channel config into beam config
|
|
65
|
+
custom[mode_name][str(beamID)]['config'].update(config)
|
|
66
|
+
# custom[mode_name][str(beamID)].update(beam)
|
|
67
|
+
|
|
68
|
+
# Parsing done
|
|
69
|
+
logger.info("[CustomCSV] " + str(custom))
|
|
70
|
+
return custom
|
|
71
|
+
except:
|
|
72
|
+
logger.exception("Something wrong while parsing")
|
|
73
|
+
return None
|
|
74
|
+
|
|
75
|
+
def getConfig(self):
|
|
76
|
+
if self.__config is None:
|
|
77
|
+
return None
|
|
78
|
+
return self.__config
|
|
79
|
+
|
|
80
|
+
def applyBeams(self):
|
|
81
|
+
try:
|
|
82
|
+
if self.__service is None:
|
|
83
|
+
logger.error("service is None")
|
|
84
|
+
return False
|
|
85
|
+
if self.__config is None:
|
|
86
|
+
logger.error("Beam config is empty!")
|
|
87
|
+
return False
|
|
88
|
+
|
|
89
|
+
service = self.__service
|
|
90
|
+
sn = self.__sn
|
|
91
|
+
custom = self.__config
|
|
92
|
+
|
|
93
|
+
channel_count = service.getChannelCount(sn).RetData
|
|
94
|
+
dr = service.getDR(sn).RetData
|
|
95
|
+
com_dr = service.getCOMDR(sn).RetData
|
|
96
|
+
# print(com_dr)
|
|
97
|
+
ele_dr_limit = service.getELEDR(sn).RetData
|
|
98
|
+
# print(ele_dr_limit)
|
|
99
|
+
|
|
100
|
+
# Get Beam then update custom beam
|
|
101
|
+
for mode_name in [*custom]:
|
|
102
|
+
mode = getattr(RFMode, mode_name)
|
|
103
|
+
# print(mode)
|
|
104
|
+
for id in [*custom[mode_name]]:
|
|
105
|
+
beamID = int(id)
|
|
106
|
+
ret = service.getBeamPattern(sn, mode, beamID)
|
|
107
|
+
beam = ret.RetData
|
|
108
|
+
logger.debug("Get [%s]BeamID %02d info: %s" %(mode_name, beamID, beam))
|
|
109
|
+
|
|
110
|
+
beam_type = BeamType(custom[mode_name][str(beamID)]['beam_type'])
|
|
111
|
+
value = custom[mode_name][str(beamID)]['config']
|
|
112
|
+
logger.info("Get [%s]BeamID %02d custom: %s" %(mode_name, beamID, value))
|
|
113
|
+
|
|
114
|
+
if beam_type is BeamType.BEAM:
|
|
115
|
+
if beam['beam_type'] != beam_type.value:
|
|
116
|
+
# Construct a new config
|
|
117
|
+
beam = {'beam_config': {'db': dr[mode.name][1], 'theta': 0, 'phi':0 }}
|
|
118
|
+
config = beam['beam_config']
|
|
119
|
+
if len(value[0]) > 0:
|
|
120
|
+
config['db'] = float(value[0])
|
|
121
|
+
if len(value[1]) > 0:
|
|
122
|
+
config['theta'] = int(value[1])
|
|
123
|
+
if len(value[2]) > 0:
|
|
124
|
+
config['phi'] = int(value[2])
|
|
125
|
+
else: #CHANNEL
|
|
126
|
+
if beam['beam_type'] != beam_type.value:
|
|
127
|
+
# Construct a new config
|
|
128
|
+
beam = {'channel_config': {}}
|
|
129
|
+
for ch in range(1, channel_count+1):
|
|
130
|
+
if ch%4 == 1: # 4 channels in one board
|
|
131
|
+
# First channel in board: construct brd_cfg
|
|
132
|
+
board = int(ch/4) + 1
|
|
133
|
+
brd_cfg = {}
|
|
134
|
+
# Use MAX COMDR - will check with assign gain to adjust
|
|
135
|
+
brd_cfg['common_db'] = com_dr[mode.value][board-1][1]
|
|
136
|
+
ch_cfg = {
|
|
137
|
+
'sw': 0,
|
|
138
|
+
# Use MAX ELEDR
|
|
139
|
+
'db': ele_dr_limit[mode.value][board-1],
|
|
140
|
+
'deg': 0
|
|
141
|
+
}
|
|
142
|
+
brd_cfg['channel_'+str((ch-1)%4 + 1)] = ch_cfg
|
|
143
|
+
if ch%4 == 0:
|
|
144
|
+
beam['channel_config'].update({'board_'+str(board): brd_cfg})
|
|
145
|
+
|
|
146
|
+
config = beam['channel_config']
|
|
147
|
+
|
|
148
|
+
# Update each channel
|
|
149
|
+
for ch_str, ch_value in value.items():
|
|
150
|
+
ch = int(ch_str)
|
|
151
|
+
if ch > channel_count:
|
|
152
|
+
logger.error("[%s]BeamID %02d - Invalid ch_%s exceeds %d channels! -> skip it"
|
|
153
|
+
%(mode_name, beamID, ch, channel_count))
|
|
154
|
+
return False
|
|
155
|
+
# logger.debug("Update ch%d info: %s" %(ch, ch_value))
|
|
156
|
+
board_idx = int((ch-1)/4)
|
|
157
|
+
board_name = 'board_'+str(board_idx + 1)
|
|
158
|
+
board_ch = (ch-1)%4 + 1
|
|
159
|
+
ch_name = 'channel_'+str(board_ch)
|
|
160
|
+
if len(ch_value[0]) > 0:
|
|
161
|
+
config[board_name][ch_name]['sw'] = int(ch_value[0])
|
|
162
|
+
if len(ch_value[1]) > 0:
|
|
163
|
+
db = float(ch_value[1])
|
|
164
|
+
ele_gain = db - config[board_name]['common_db']
|
|
165
|
+
if ele_gain < 0:
|
|
166
|
+
logger.warning("Ch_%d changed to db:%.1f < com gain:%.1f, adjust com gain later" %(ch, db, config[board_name]['common_db']))
|
|
167
|
+
config[board_name][ch_name]['db'] = ele_gain
|
|
168
|
+
if len(ch_value[2]) > 0:
|
|
169
|
+
config[board_name][ch_name]['deg'] = int(ch_value[2])
|
|
170
|
+
logger.debug("Tmp [%s]BeamID %02d custom: %s" %(mode_name, beamID, config))
|
|
171
|
+
|
|
172
|
+
# Simple check each com_gain, ele_gain for board/channel
|
|
173
|
+
for brd, brd_cfg in config.items():
|
|
174
|
+
brd_idx = int(brd.replace("board_", ""))-1
|
|
175
|
+
brd_db = [v['db'] for k, v in brd_cfg.items() if k.startswith("channel_")]
|
|
176
|
+
# print(brd_db)
|
|
177
|
+
if max(brd_db) - min(brd_db) > ele_dr_limit[mode.value][board_idx]:
|
|
178
|
+
logger.error("[%s]BeamID %02d - [%s] Invalid db setting: %s, the max diff of each db field exceeds the limit: %.1f"
|
|
179
|
+
%(mode_name, beamID, brd, [d+brd_cfg['common_db'] for d in brd_db], ele_dr_limit[mode.value][board_idx]))
|
|
180
|
+
return False
|
|
181
|
+
if min(brd_db) < 0:
|
|
182
|
+
# Lower the common gain to min db
|
|
183
|
+
new_com = brd_cfg['common_db'] + min(brd_db)
|
|
184
|
+
if new_com < com_dr[mode.value][brd_idx][0]:
|
|
185
|
+
logger.error("[%s]BeamID %02d - [%s] Invalid common gain: %.1f < min common gain: %.1f, please tune higher the minimal db field"
|
|
186
|
+
%(mode_name, beamID, brd, new_com, com_dr[mode.value][brd_idx][0]))
|
|
187
|
+
return False
|
|
188
|
+
logger.info("[%s]BeamID %02d - Adjust [%s]com gain: %.1f -> %.1f, and ele gain: %s -> %s"
|
|
189
|
+
%(mode_name, beamID, brd, brd_cfg['common_db'], new_com,
|
|
190
|
+
[v['db'] for k, v in brd_cfg.items() if k.startswith("channel_")],
|
|
191
|
+
[v['db']-min(brd_db) for k, v in brd_cfg.items() if k.startswith("channel_")]))
|
|
192
|
+
brd_cfg['common_db'] = new_com
|
|
193
|
+
for k, v in brd_cfg.items():
|
|
194
|
+
if k.startswith("channel_"):
|
|
195
|
+
v['db'] -= min(brd_db)
|
|
196
|
+
logger.info("Set [%s]BeamID %02d info: %s" %(mode_name, beamID, config))
|
|
197
|
+
ret = service.setBeamPattern(sn, mode, beamID, beam_type, config)
|
|
198
|
+
if ret.RetCode is not RetCode.OK:
|
|
199
|
+
logger.error(ret.RetMsg)
|
|
200
|
+
return False
|
|
201
|
+
except:
|
|
202
|
+
logger.exception("Something wrong while parsing")
|
|
203
|
+
return False
|
|
204
|
+
logger.info("Apply beam configs to %s successfully" %sn)
|
|
205
|
+
return True
|
|
206
|
+
|
|
207
|
+
# if __name__ == '__main__':
|
|
208
|
+
# import logging.config
|
|
209
|
+
# if not os.path.isdir('tlk_core_log/'):
|
|
210
|
+
# os.mkdir('tlk_core_log/')
|
|
211
|
+
# logging.config.fileConfig('logging.conf')
|
|
Binary file
|
|
Binary file
|
tlkcore/TMYLogging.py
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
import logging
|
|
3
|
+
import logging.config
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
from tlkcore.TMYUtils import _Utils
|
|
7
|
+
|
|
8
|
+
class TMYLogging():
|
|
9
|
+
"""
|
|
10
|
+
Customerize your logging setting here
|
|
11
|
+
"""
|
|
12
|
+
_LOGGING_CONFIG = {
|
|
13
|
+
"version": 1,
|
|
14
|
+
"disable_existing_loggers": False,
|
|
15
|
+
"loggers": {
|
|
16
|
+
"": { # root logger
|
|
17
|
+
"handlers": ["console", "file"],
|
|
18
|
+
"level": logging.DEBUG,
|
|
19
|
+
"propagate": False,
|
|
20
|
+
},
|
|
21
|
+
"TLKCoreService": {
|
|
22
|
+
"handlers": ["console", "libFile"],
|
|
23
|
+
"qualname": "TLKCoreService",
|
|
24
|
+
"propagate": False,
|
|
25
|
+
},
|
|
26
|
+
"Comm":{
|
|
27
|
+
"handlers": ["libConsole", "libFile"],
|
|
28
|
+
"qualname": "Comm",
|
|
29
|
+
"propagate": False,
|
|
30
|
+
},
|
|
31
|
+
"Device":{
|
|
32
|
+
"handlers": ["libConsole", "libFile"],
|
|
33
|
+
"qualname": "Device",
|
|
34
|
+
"propagate": False,
|
|
35
|
+
},
|
|
36
|
+
"DFU":{
|
|
37
|
+
"handlers": ["console", "libFile"],
|
|
38
|
+
"qualname": "DFU",
|
|
39
|
+
"propagate": False,
|
|
40
|
+
},
|
|
41
|
+
"CaliTbl":{
|
|
42
|
+
"handlers": ["libFile"],
|
|
43
|
+
"qualname": "CaliTbl",
|
|
44
|
+
"propagate": False,
|
|
45
|
+
},
|
|
46
|
+
"AAKitTbl":{
|
|
47
|
+
"handlers": ["libFile"],
|
|
48
|
+
"qualname": "AAKitTbl",
|
|
49
|
+
"propagate": False,
|
|
50
|
+
},
|
|
51
|
+
"BeamTbl":{
|
|
52
|
+
"handlers": ["libFile"],
|
|
53
|
+
"qualname": "BeamTbl",
|
|
54
|
+
"propagate": False,
|
|
55
|
+
},
|
|
56
|
+
"UDDeltaTbl":{
|
|
57
|
+
"handlers": ["libFile"],
|
|
58
|
+
"qualname": "UDDeltaTbl",
|
|
59
|
+
"propagate": False,
|
|
60
|
+
},
|
|
61
|
+
"TblDB":{
|
|
62
|
+
"handlers": ["libFile"],
|
|
63
|
+
"qualname": "TblDB",
|
|
64
|
+
"propagate": False,
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
"handlers": {
|
|
68
|
+
"console": {
|
|
69
|
+
"class": "logging.StreamHandler",
|
|
70
|
+
"level": logging.INFO,
|
|
71
|
+
"formatter": "default",
|
|
72
|
+
},
|
|
73
|
+
"file":{
|
|
74
|
+
"class": "logging.FileHandler",
|
|
75
|
+
"level": logging.DEBUG,
|
|
76
|
+
"filename": datetime.now().strftime("tlk_core_log/main-%Y-%m-%d.log"),
|
|
77
|
+
"formatter": "default",
|
|
78
|
+
},
|
|
79
|
+
"libConsole": {
|
|
80
|
+
"class": "logging.StreamHandler",
|
|
81
|
+
"level": logging.ERROR,
|
|
82
|
+
"formatter": "default",
|
|
83
|
+
},
|
|
84
|
+
"libFile":{
|
|
85
|
+
"class": "logging.FileHandler",
|
|
86
|
+
"level": logging.DEBUG,
|
|
87
|
+
"filename": datetime.now().strftime("tlk_core_log/tlkcore-%Y-%m-%d.log"),
|
|
88
|
+
"formatter": "default",
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
"formatters": {
|
|
92
|
+
"default": {
|
|
93
|
+
"format": "%(asctime)s.%(msecs)3d - %(name)s - %(levelname)s : %(message)s",
|
|
94
|
+
"datefmt": "%Y-%m-%d %H:%M:%S"
|
|
95
|
+
},
|
|
96
|
+
"plain": {
|
|
97
|
+
"format": "%(message)s",
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
def __init__(self):
|
|
103
|
+
"""TLKCoreService calls TMYLogging.py if change another root path"""
|
|
104
|
+
print('TMYLogging __init__')
|
|
105
|
+
|
|
106
|
+
def applyLogger(self):
|
|
107
|
+
# Update current dict
|
|
108
|
+
print("Apply logger path to : %s" %_Utils.root)
|
|
109
|
+
self._LOGGING_CONFIG["handlers"]["file"]["filename"] = os.path.join(_Utils.root, self._LOGGING_CONFIG["handlers"]["file"]["filename"])
|
|
110
|
+
self._LOGGING_CONFIG["handlers"]["libFile"]["filename"] = os.path.join(_Utils.root, self._LOGGING_CONFIG["handlers"]["libFile"]["filename"])
|
|
111
|
+
|
|
112
|
+
logging.config.dictConfig(self._LOGGING_CONFIG)
|
tlkcore/TMYPublic.py
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
from enum import Enum, Flag, auto, IntEnum
|
|
2
|
+
from typing import Union
|
|
3
|
+
|
|
4
|
+
class RIS_Dir(dict):
|
|
5
|
+
"""
|
|
6
|
+
A dict structure for RIS direction includes distance and angle.
|
|
7
|
+
|
|
8
|
+
Args:
|
|
9
|
+
distance (float): Distance from RIS to the source/target
|
|
10
|
+
angle (tuple): Angle of the target, given in (theta, phi) format or theta only with phi=0, Defaults to (0,0)
|
|
11
|
+
|
|
12
|
+
Examples:
|
|
13
|
+
* For a distance of 1 meter and an angle of (0, 0):
|
|
14
|
+
>>> RIS_Dir(1)
|
|
15
|
+
* For a distance of 1 meter and an angle of (0, 0):
|
|
16
|
+
>>> RIS_Dir(1, (0, 0))
|
|
17
|
+
* For a distance of 1 meter and an angle of (30, 0):
|
|
18
|
+
>>> RIS_Dir(1, (30, 0))
|
|
19
|
+
"""
|
|
20
|
+
def __init__(self, distance, angle:Union[int, tuple]=(0,0)):
|
|
21
|
+
self['distance'] = distance
|
|
22
|
+
if isinstance(angle, int):
|
|
23
|
+
self['angle'] = (angle, 0)
|
|
24
|
+
# elif isinstance(angle, tuple):
|
|
25
|
+
# # TODO: for multiple reflection angle only
|
|
26
|
+
# self['angle'] = [angle]
|
|
27
|
+
else:
|
|
28
|
+
self['angle'] = angle
|
|
29
|
+
|
|
30
|
+
class RIS_ModuleConfig(dict):
|
|
31
|
+
"""
|
|
32
|
+
A data structure for RIS module configuration.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
central_freq_mhz (int): Operating central frequency in MHz.
|
|
36
|
+
module (Union[int, list]): Specifies the target module partition to control.
|
|
37
|
+
It can be a single value (e.g. 1), or a list (e.g. [1, 2]),
|
|
38
|
+
or a nested list (e.g. [[1, 2]] or [[1, 2], [3, 4]]). Defaults to 1.
|
|
39
|
+
module_rotate (dict): Specifies the clockwise rotation degree for each module, therefore the actual pattern will be counter-clockwise rotation
|
|
40
|
+
The degree must be a multiple of 90.
|
|
41
|
+
|
|
42
|
+
Examples:
|
|
43
|
+
* 28GHz with only module 1, no rotation:
|
|
44
|
+
>>> RIS_ModuleConfig(28000, 1)
|
|
45
|
+
* 28GHz with module 1 and 2 in landscape orientation, no rotation:
|
|
46
|
+
>>> RIS_ModuleConfig(28000, [1, 2])
|
|
47
|
+
* 28GHz with module 1 and 2 in portrait orientation, rotate module 1 by 90 degrees:
|
|
48
|
+
>>> RIS_ModuleConfig(28000, [[1], [2]], {'1': 90})
|
|
49
|
+
* 28GHz with module 1 and 2 in landscape orientation, rotate module 1 by 90 degrees and module 2 by 180 degrees:
|
|
50
|
+
>>> RIS_ModuleConfig(28000, [1, 2], {'1': 90, '2': 180})
|
|
51
|
+
* 28GHz with module 1,2,3,4 in landscape orientation, no rotation:
|
|
52
|
+
>>> RIS_ModuleConfig(28000, [1, 2, 3, 4])
|
|
53
|
+
* 28GHz with module 1,2,3,4 in portrait orientation, no rotation:
|
|
54
|
+
>>> RIS_ModuleConfig(28000, [[1], [2], [3], [4]])
|
|
55
|
+
* 28GHz with module 1,2,3,4 in square orientation, rotate module 1 by 90 degrees and module 2 by 180 degrees:
|
|
56
|
+
>>> RIS_ModuleConfig(28000, [[1, 2],
|
|
57
|
+
[3, 4]], {'1': 90, '2': 180})
|
|
58
|
+
"""
|
|
59
|
+
def __init__(self, central_freq_mhz:float, module:Union[int, list]=1, module_rotate=None):
|
|
60
|
+
self['central_freq_mhz'] = central_freq_mhz
|
|
61
|
+
self['module'] = module
|
|
62
|
+
self['module_rotate'] = module_rotate
|
|
63
|
+
|
|
64
|
+
class DevInterface(Flag):
|
|
65
|
+
"""
|
|
66
|
+
Defines device connect interface for scanning.
|
|
67
|
+
"""
|
|
68
|
+
UNKNOWN = 0
|
|
69
|
+
LAN = auto()
|
|
70
|
+
COMPORT = auto()
|
|
71
|
+
USB = auto()
|
|
72
|
+
ALL = LAN | COMPORT | USB
|
|
73
|
+
|
|
74
|
+
class ScanFilter(Flag):
|
|
75
|
+
NONE = 0
|
|
76
|
+
NORMAL = auto()
|
|
77
|
+
DFU = auto()
|
|
78
|
+
ALL = NORMAL | DFU
|
|
79
|
+
|
|
80
|
+
class IPMode(Enum):
|
|
81
|
+
"""
|
|
82
|
+
Defines device IP mode as DHCP or static IP mode.
|
|
83
|
+
"""
|
|
84
|
+
DHCP = 0
|
|
85
|
+
STATIC_IP = auto()
|
|
86
|
+
|
|
87
|
+
class RFMode(Enum):
|
|
88
|
+
"""
|
|
89
|
+
Defines RF mode of beamform devices series.
|
|
90
|
+
"""
|
|
91
|
+
TX = 0
|
|
92
|
+
RX = auto()
|
|
93
|
+
|
|
94
|
+
class CellRFMode(Enum):
|
|
95
|
+
STANDBY = -1
|
|
96
|
+
TX = 0
|
|
97
|
+
RX = auto()
|
|
98
|
+
|
|
99
|
+
class BeamType(Enum):
|
|
100
|
+
"""
|
|
101
|
+
Defines beam type of beamform devices series for beam configuration.
|
|
102
|
+
"""
|
|
103
|
+
BEAM = 0
|
|
104
|
+
CHANNEL = auto()
|
|
105
|
+
|
|
106
|
+
class RetCode(Enum):
|
|
107
|
+
"""
|
|
108
|
+
Error code to represent the status of operations in TLKCore.
|
|
109
|
+
"""
|
|
110
|
+
def __str__(self):
|
|
111
|
+
return self.name
|
|
112
|
+
def __int__(self):
|
|
113
|
+
return self.value
|
|
114
|
+
OK = 0
|
|
115
|
+
WARNING = auto()
|
|
116
|
+
ERROR = auto()
|
|
117
|
+
NO_RESPONSE = auto()
|
|
118
|
+
# genereal operations
|
|
119
|
+
ERROR_GET_SN = 10
|
|
120
|
+
ERROR_DEV_TYPE = auto()
|
|
121
|
+
ERROR_SCAN = auto()
|
|
122
|
+
ERROR_INIT_OBJECT = auto()
|
|
123
|
+
ERROR_DEV_NOT_INIT = auto()
|
|
124
|
+
ERROR_METHOD_NOT_FOUND = auto()
|
|
125
|
+
ERROR_METHOD_NOT_SUPPORT= auto()
|
|
126
|
+
ERROR_REFLECTION = auto()
|
|
127
|
+
ERROR_POWER = auto()
|
|
128
|
+
ERROR_EXPORT_LOG = auto()
|
|
129
|
+
ERROR_FW_NOT_SUPPORT = auto()
|
|
130
|
+
|
|
131
|
+
# Communication interface related
|
|
132
|
+
ERROR_COMM_NOT_INIT = 30
|
|
133
|
+
ERROR_COMM_INIT = auto()
|
|
134
|
+
ERROR_DISCONNECT = auto()
|
|
135
|
+
ERROR_SOCKET = auto()
|
|
136
|
+
ERROR_SEND_CMD = auto()
|
|
137
|
+
ERROR_RESP_CMD = auto()
|
|
138
|
+
ERROR_SEND_CMD_TIMEOUT = auto()
|
|
139
|
+
ERROR_COMPORT = auto()
|
|
140
|
+
ERROR_USB = auto()
|
|
141
|
+
|
|
142
|
+
# CMD to device
|
|
143
|
+
ERROR_CMD = 40
|
|
144
|
+
ERROR_CMD_INIT = auto()
|
|
145
|
+
ERROR_CMD_PARAM = auto()
|
|
146
|
+
|
|
147
|
+
# WEB - Database related
|
|
148
|
+
ERROR_DB_SERVER = 50
|
|
149
|
+
ERROR_DB_FEEDBACK = auto()
|
|
150
|
+
|
|
151
|
+
# DFU - Device Firmware Update related
|
|
152
|
+
ERROR_DFU = 60
|
|
153
|
+
ERROR_DFU_NOT_SUPPORT = auto()
|
|
154
|
+
ERROR_DFU_TYPE = auto()
|
|
155
|
+
ERROR_DFU_HEADER = auto()
|
|
156
|
+
ERROR_DFU_TRANSMIT = auto()
|
|
157
|
+
|
|
158
|
+
# Beamforming device
|
|
159
|
+
ERROR_BF_STATE = 100
|
|
160
|
+
ERROR_BF_AAKIT = auto()
|
|
161
|
+
ERROR_BF_NO_AAKIT = auto()
|
|
162
|
+
ERROR_BF_CALI_PATH = auto()
|
|
163
|
+
ERROR_BF_BEAM = auto()
|
|
164
|
+
ERROR_BF_GAIN = auto()
|
|
165
|
+
ERROR_BF_PHASE = auto()
|
|
166
|
+
ERROR_BF_RFMODE = auto()
|
|
167
|
+
ERROR_BF_CALI_INCOMPLTE = auto()
|
|
168
|
+
ERROR_BF_CALI_PARSE = auto()
|
|
169
|
+
ERROR_BF_TC = auto()
|
|
170
|
+
ERROR_BF_BEAM_FILE = auto()
|
|
171
|
+
# PD device
|
|
172
|
+
ERROR_PD_CALI = 150
|
|
173
|
+
ERROR_PD_SOURCE = auto()
|
|
174
|
+
# RIS device
|
|
175
|
+
ERROR_RIS_MODULE = 160
|
|
176
|
+
ERROR_RIS_CONFIG = auto()
|
|
177
|
+
# UDM/UDB device
|
|
178
|
+
ERROR_FREQ_RANGE = 240
|
|
179
|
+
ERROR_LICENSE_LENGTH = auto()
|
|
180
|
+
ERROR_LICENSE_KEY = auto()
|
|
181
|
+
ERROR_REF_CHANGE = auto()
|
|
182
|
+
# UD device
|
|
183
|
+
ERROR_UD_FREQ = 245
|
|
184
|
+
ERROR_FREQ_EQUATION = 250
|
|
185
|
+
WARNING_HARMONIC = auto()
|
|
186
|
+
ERROR_HARMONIC_BLOCK = auto()
|
|
187
|
+
ERROR_PLO_UNLOCK = 253
|
|
188
|
+
ERROR_PLO_CRC = auto()
|
|
189
|
+
ERROR_UD_STATE = auto()
|
|
190
|
+
|
|
191
|
+
class UDFreq(Enum):
|
|
192
|
+
"""
|
|
193
|
+
UD frequency related categories, also used for key name of dict when calling :func:`~tlkcore.tmydev.DevUDBox.getUDFreq`
|
|
194
|
+
"""
|
|
195
|
+
def __str__(self):
|
|
196
|
+
return self.name
|
|
197
|
+
UDFreq = 0
|
|
198
|
+
RFFreq = auto()
|
|
199
|
+
IFFreq = auto()
|
|
200
|
+
|
|
201
|
+
class UDState(Enum):
|
|
202
|
+
"""
|
|
203
|
+
The state of UDBox5G
|
|
204
|
+
"""
|
|
205
|
+
NO_SET = -1
|
|
206
|
+
PLO_LOCK = 0
|
|
207
|
+
CH1 = auto()
|
|
208
|
+
CH2 = auto() # ignore it if single UD
|
|
209
|
+
OUT_10M = auto()
|
|
210
|
+
OUT_100M = auto()
|
|
211
|
+
SOURCE_100M = auto() # 0:Internal, 1:External
|
|
212
|
+
LED_100M = auto() # 0:OFF, 1:WHITE, 2:BLUE
|
|
213
|
+
PWR_5V = auto()
|
|
214
|
+
PWR_9V = auto()
|
|
215
|
+
|
|
216
|
+
class UDMState(Flag):
|
|
217
|
+
"""
|
|
218
|
+
The state of UDM
|
|
219
|
+
"""
|
|
220
|
+
NO_SET = 0
|
|
221
|
+
SYSTEM = auto()
|
|
222
|
+
PLO_LOCK = auto()
|
|
223
|
+
REF_LOCK = auto()
|
|
224
|
+
LICENSE = auto()
|
|
225
|
+
ALL = SYSTEM | PLO_LOCK | REF_LOCK | LICENSE
|
|
226
|
+
|
|
227
|
+
class UDM_SYS(Enum):
|
|
228
|
+
"""
|
|
229
|
+
It defines the :attr:`UDMState.SYSTEM` state of UDM
|
|
230
|
+
"""
|
|
231
|
+
SYS_ERROR = -1
|
|
232
|
+
NORMAL = 0
|
|
233
|
+
|
|
234
|
+
class UD_PLO(Enum):
|
|
235
|
+
"""
|
|
236
|
+
It defines the :attr:`UDMState.PLO_LOCK` state of UD series
|
|
237
|
+
"""
|
|
238
|
+
UNLOCK = -1
|
|
239
|
+
LOCK = 0
|
|
240
|
+
|
|
241
|
+
class UD_REF(Enum):
|
|
242
|
+
"""
|
|
243
|
+
It defines the :attr:`UDMState.REF_LOCK` state of UD series
|
|
244
|
+
"""
|
|
245
|
+
UNLOCK = -1
|
|
246
|
+
INTERNAL = 0
|
|
247
|
+
EXTERNAL = auto()
|
|
248
|
+
|
|
249
|
+
class UDM_LICENSE(Enum):
|
|
250
|
+
"""
|
|
251
|
+
It defines the :attr:`UDMState.LICENSE` state of UDM
|
|
252
|
+
"""
|
|
253
|
+
VERIFY_FAIL_FLASH = -2
|
|
254
|
+
VERIFY_FAIL_DIGEST = -1
|
|
255
|
+
NON_LICENSE = 0
|
|
256
|
+
VERIFY_PASS = auto()
|
|
257
|
+
|
|
258
|
+
class UD_SN_TYPE(Flag):
|
|
259
|
+
"""
|
|
260
|
+
The SN type of UD
|
|
261
|
+
"""
|
|
262
|
+
UD_BOX = 1
|
|
263
|
+
UD_MODULE = auto()
|
|
264
|
+
ALL = UD_BOX | UD_MODULE
|
|
265
|
+
|
|
266
|
+
class UD_LO_CONFIG(Enum):
|
|
267
|
+
"""
|
|
268
|
+
It defines the LO config for UDB series
|
|
269
|
+
"""
|
|
270
|
+
LO_CFG_INTERNAL = 0
|
|
271
|
+
LO_CFG_INTERNAL_OUT = auto()
|
|
272
|
+
LO_CFG_EXTERNAL_IN = auto()
|
|
273
|
+
def __str__(self):
|
|
274
|
+
return self.name
|
|
275
|
+
|
|
276
|
+
class POLARIZATION(Flag):
|
|
277
|
+
HORIZON = 1
|
|
278
|
+
VERTICAL = auto()
|
|
279
|
+
DUAL = HORIZON | VERTICAL
|
|
280
|
+
def __str__(self):
|
|
281
|
+
return self.name.lower()
|
|
282
|
+
|
|
283
|
+
class POLAR_SYNTHESIS(IntEnum):
|
|
284
|
+
FORWARD = 0
|
|
285
|
+
BACKWARD = 180
|
|
286
|
+
RIGHT_HAND_CIRCULAR = 90
|
|
287
|
+
LEFT_HAND_CIRCULAR = 270
|
|
288
|
+
def __str__(self):
|
|
289
|
+
return self.name
|
|
290
|
+
def __int__(self):
|
|
291
|
+
return self.value
|
|
Binary file
|
tlkcore/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "255.255.255"
|
|
Binary file
|
tlkcore/db/__init__.py
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
__file = Path(__file__).absolute()
|
|
5
|
+
__root = __file.parent.parent.parent
|
|
6
|
+
if sys.path.count(__root) == 0:
|
|
7
|
+
sys.path.insert(0, __root)
|
|
8
|
+
# print(sys.path)
|
|
9
|
+
|
|
10
|
+
fromLib = True
|
|
11
|
+
|
|
12
|
+
if __file.suffix == '.py':
|
|
13
|
+
fromLib = False
|
|
Binary file
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
This software is proprietary to TMYTEK.
|
|
2
|
+
|
|
3
|
+
Unauthorized reproduction, reverse engineering, decompilation, modification, or redistribution of this software is strictly prohibited.
|
|
4
|
+
|
|
5
|
+
The software may only be used for development and operation in conjunction with TLKCore as authorized.
|
|
6
|
+
|
|
7
|
+
Any usage beyond the licensed scope constitutes a breach of agreement, and TMYTEK reserves all legal rights.
|
|
8
|
+
|
|
9
|
+
Copyright © 2025 TMYTEK. All rights reserved.
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: tlkcore
|
|
3
|
+
Version: 255.255.255
|
|
4
|
+
Summary: TLKCore library
|
|
5
|
+
Home-page: https://github.com/TMYtek/tlkcore-examples/
|
|
6
|
+
Author: TMYTEK Software Team
|
|
7
|
+
Author-email: rd2_common@tmytek.com
|
|
8
|
+
License: UNKNOWN
|
|
9
|
+
Platform: UNKNOWN
|
|
10
|
+
Classifier: License :: Other/Proprietary License
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
14
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
15
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
16
|
+
Classifier: Topic :: Software Development :: Testing
|
|
17
|
+
Classifier: Programming Language :: Python
|
|
18
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
25
|
+
Requires-Python: >=3.8
|
|
26
|
+
Description-Content-Type: text/x-rst
|
|
27
|
+
Requires-Dist: psutil>=6.1.0
|
|
28
|
+
Requires-Dist: pyserial>=3.5
|
|
29
|
+
Requires-Dist: ft4222>=1.10.0
|
|
30
|
+
Requires-Dist: tftpy==0.8.5
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
Introduction
|
|
34
|
+
============
|
|
35
|
+
|
|
36
|
+
**TLKCore** is a core service which inside the TMXLAB KIT(TLK/[WEB-TLK](https://web-tlk.tmytek.com/)), it integrates Python built libraries which developing mmWave( n257 / n258 / n260 / n261 ) **beamforming** and **beam steering** applications on **BBox 5G Series(mmwave beamformer)** and **UDBox 5G Series(mmwave Up-down frequency converter)** and other standard products developed by TMYTEK.
|
|
37
|
+
It provides a simple and efficient way to interact with the hardware, allowing developers to focus on building applications without worrying about low-level details.
|
|
38
|
+
|
|
39
|
+
Installation Troubleshooting
|
|
40
|
+
-----------------------------
|
|
41
|
+
|
|
42
|
+
* If you encounter any issues during `tlkcore` installation or usage, please check the following:
|
|
43
|
+
|
|
44
|
+
1. Ensure you have the required dependencies installed.
|
|
45
|
+
2. Check the compatibility of your Python version.
|
|
46
|
+
3. Review the documentation for any specific configuration steps.
|
|
47
|
+
|
|
48
|
+
* If you meet the error message likes: CERTIFICATE_VERIFY_FAILED,
|
|
49
|
+
you can try the following steps:
|
|
50
|
+
|
|
51
|
+
1. Update your `pip` to the latest version:
|
|
52
|
+
.. code-block:: bash
|
|
53
|
+
|
|
54
|
+
pip install --upgrade pip
|
|
55
|
+
|
|
56
|
+
2. You may need to configure your proxy settings if you are behind a corporate firewall.
|
|
57
|
+
3. You can also try to disable SSL verification (not recommended for production):
|
|
58
|
+
.. code-block:: bash
|
|
59
|
+
|
|
60
|
+
pip install tlkcore --trusted-host pypi.org --trusted-host files.pythonhosted.org
|
|
61
|
+
|
|
62
|
+
4. Or download cacert.pem from https://curl.se/ca/cacert.pem , then set environment variable `SSL_CERT_FILE` to the path of the downloaded file.
|
|
63
|
+
.. code-block:: bash
|
|
64
|
+
|
|
65
|
+
set SSL_CERT_FILE={$your_path}/cacert.pem
|
|
66
|
+
|
|
67
|
+
Hardware Prequisites
|
|
68
|
+
=======================
|
|
69
|
+
|
|
70
|
+
* Architecture:
|
|
71
|
+
|
|
72
|
+
.. image:: https://github.com/tmytek/tlkcore-examples/blob/master/images/TLKCore_usage.png
|
|
73
|
+
:alt: TLKCore usage architecture
|
|
74
|
+
:width: 600px
|
|
75
|
+
|
|
76
|
+
* USB driver for scanning/connect device
|
|
77
|
+
|
|
78
|
+
- `Installation Guides for all platforms <https://ftdichip.com/document/installation-guides/>`_
|
|
79
|
+
- Windows
|
|
80
|
+
|
|
81
|
+
- Online-Host with external internet capability
|
|
82
|
+
- Auto detect a new device and install driver
|
|
83
|
+
|
|
84
|
+
- Offline-Host
|
|
85
|
+
- Download `setup executable driver from FTDI <https://ftdichip.com/drivers/d2xx-drivers/>`_ and install it.
|
|
86
|
+
|
|
87
|
+
- Linux
|
|
88
|
+
|
|
89
|
+
1. Follow `steps <https://gitlab.com/msrelectronics/python-ft4222/-/tree/master#accessrights>`_ to create or extend **/etc/udev/rules.d/99-ftdi.rules** includes::
|
|
90
|
+
|
|
91
|
+
SUBSYSTEM=="usb", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="601c", GROUP="plugdev", MODE="0666"
|
|
92
|
+
|
|
93
|
+
2. Try to reload udev rules or re-plugin USB devices::
|
|
94
|
+
|
|
95
|
+
sudo udevadm control --reload-rules
|
|
96
|
+
sudo udevadm trigger
|
|
97
|
+
|
|
98
|
+
Examples
|
|
99
|
+
=========
|
|
100
|
+
|
|
101
|
+
This represents how to use the `tlkcore` API. Please refer to the example from github: https://github.com/tmytek/tlkcore-examples for more details.
|
|
102
|
+
|
|
103
|
+
Initialize & scanDevices
|
|
104
|
+
------------------------
|
|
105
|
+
|
|
106
|
+
.. code-block:: python
|
|
107
|
+
|
|
108
|
+
from tlkcore.TLKCoreService import TLKCoreService
|
|
109
|
+
service = TLKCoreService(".")
|
|
110
|
+
ret = service.scanDevices()
|
|
111
|
+
print(ret)
|
|
112
|
+
|
|
113
|
+
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
tlkcore/TLKCoreService.cp38-win_amd64.pyd,sha256=4JMv18JBI1f7fzk4IylkJnRj--xQTzMgCBFG5tTYiME,188928
|
|
2
|
+
tlkcore/TMYBeamConfig.py,sha256=r4AC7Pp3lSRVzZefIRlsEuPikH9OHHWQkJAmBykRstw,10970
|
|
3
|
+
tlkcore/TMYCommService.cp38-win_amd64.pyd,sha256=uDC6ql9HL1UbREjlAHPTuxfiazzf2txZjNC029a4OOc,394240
|
|
4
|
+
tlkcore/TMYDFU.cp38-win_amd64.pyd,sha256=S6-j8ZQrjnJrStIvTqq_J7seIjyi3KlT6fvKPmak43Q,272896
|
|
5
|
+
tlkcore/TMYLogging.py,sha256=IfJ3bihGbZqZx9HLX3EMEIJyqmk4Kg9Wu0vBQjcR3Ak,3828
|
|
6
|
+
tlkcore/TMYPublic.py,sha256=tiZkCU4ET_b1DT3F6YdLVtHSkZrcU2t5PcqHTCp30M4,9110
|
|
7
|
+
tlkcore/TMYUtils.cp38-win_amd64.pyd,sha256=2HXBs5FixDtFAiOuq3tv0DvKaLVTMNq6_2Vz_pyWnQk,132096
|
|
8
|
+
tlkcore/__init__.py,sha256=oU1ki7IC-ioCzroJrPr_PNM-FqyoTSi23COec0nfVfU,27
|
|
9
|
+
tlkcore/db/TMYDBQueryer.cp38-win_amd64.pyd,sha256=_S9qsHlCZIXywunG5en_cQK7RMSinmO6Y10tMDhNuZg,59904
|
|
10
|
+
tlkcore/db/__init__.py,sha256=7c0_FWO1wyv9J2X0ZS-AZGI-4fOJFQVQAtJkDf963BE,62
|
|
11
|
+
tlkcore/tmydev/DevBBoard.cp38-win_amd64.pyd,sha256=-cPy3aNlYdiZYUw7XjKwltFFrOEr72ja6Y4FpjM5YZs,87552
|
|
12
|
+
tlkcore/tmydev/DevBBox.cp38-win_amd64.pyd,sha256=6KmRm_Og8Wmi3HsYthgRrj0eMfeU5f-BoX65TqS9LSE,583168
|
|
13
|
+
tlkcore/tmydev/DevBBoxLite.cp38-win_amd64.pyd,sha256=2kdLdyxP49Fu3dkB7C1dlyUGn8ppOkJeyEinCfQaY2Y,72704
|
|
14
|
+
tlkcore/tmydev/DevBBoxOne.cp38-win_amd64.pyd,sha256=1EVbwHMne1LFbcMX1eBe9ZtamvPayDa8XwyA1gaxHmc,70656
|
|
15
|
+
tlkcore/tmydev/DevCloverCell.cp38-win_amd64.pyd,sha256=WoQCmnXZnqI5vIjcIHGg95QE7LWt_Y7uyqdf2wf7q8A,439296
|
|
16
|
+
tlkcore/tmydev/DevPD.cp38-win_amd64.pyd,sha256=O5G-qVRJC4cn__Wh6kGYqzBeb2avg1GoHYg1ujZSbeM,107520
|
|
17
|
+
tlkcore/tmydev/DevRIS.cp38-win_amd64.pyd,sha256=S6RgDbg681kcojdyofFi1QXupmHVR_RO6fahMoKQllc,243712
|
|
18
|
+
tlkcore/tmydev/DevUDB.cp38-win_amd64.pyd,sha256=FVjf6mKwsYc_7w6tuj92L8Xkf-Vq9TwyU1EEjcPwMDQ,82432
|
|
19
|
+
tlkcore/tmydev/DevUDBox.cp38-win_amd64.pyd,sha256=sD1mcqlyf4YS1SnE3u_MpEzxBaTFzmjjY4J9sM6gMls,135168
|
|
20
|
+
tlkcore/tmydev/DevUDC.cp38-win_amd64.pyd,sha256=fbnBMcgSzx0i5kUJN6JuAE-IryZLRkSEJHIgdtJwitY,237568
|
|
21
|
+
tlkcore/tmydev/DevUDM.cp38-win_amd64.pyd,sha256=g98B29pw2ET_2aCi3P-KjOG76ejyZTLS-wYpdKZ6MSQ,138240
|
|
22
|
+
tlkcore/tmydev/RIS_pattern_generator.cp38-win_amd64.pyd,sha256=4aO7A_KpPXmG_IRj1NP7ansm0kPTWFEOBAaBYV3-aPE,174080
|
|
23
|
+
tlkcore/tmydev/TMYTableManager.cp38-win_amd64.pyd,sha256=Nh--zCZrY7SALkoOc3HdtdfksRk9dtAtGmbGW8GzAkU,645632
|
|
24
|
+
tlkcore/tmydev/__init__.py,sha256=8ksasd6qXYtFXfv7JehWF_xCHllYtmAlDTLho53Xts0,269
|
|
25
|
+
tlkcore/tmydev/device.cp38-win_amd64.pyd,sha256=s_GT8ZMfyea7Is0R37AWoz8id66NdchUZjy43U4s1bU,202752
|
|
26
|
+
tlkcore-255.255.255.dist-info/LICENSE.txt,sha256=6_K8eSrAQ-FGMhnjUnh9X_ZtghXE8DOa6TJNaYACAIE,448
|
|
27
|
+
tlkcore-255.255.255.dist-info/METADATA,sha256=XIDgXs_sDdt4zyvQnBZ7ykuA_NkGGPThQC9UP76AZK4,4406
|
|
28
|
+
tlkcore-255.255.255.dist-info/WHEEL,sha256=od_9EmQVrRx-JFmipR6J48h0F4WT4MdLLqLKdbBMHiM,99
|
|
29
|
+
tlkcore-255.255.255.dist-info/top_level.txt,sha256=a5TMUMf1qbFol7Px5jWhx6ZvMZke2kKrwYbrUCjcOQ4,8
|
|
30
|
+
tlkcore-255.255.255.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
tlkcore
|