benchlab-pytools 3.0.0__py3-none-any.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.
- benchlab/__init__.py +14 -0
- benchlab/__main__.py +21 -0
- benchlab/config/README.md +325 -0
- benchlab/config/__init__.py +9 -0
- benchlab/config/config_client.py +631 -0
- benchlab/config/config_manager.py +495 -0
- benchlab/config/config_tool.py +358 -0
- benchlab/config/diff.py +163 -0
- benchlab/config/examples/complete_config.json +56 -0
- benchlab/config/examples/rgb_lighting.json +24 -0
- benchlab/config/examples/simple_fan.json +32 -0
- benchlab/config/schema.py +138 -0
- benchlab/core/README.md +154 -0
- benchlab/core/__init__.py +78 -0
- benchlab/core/config.py +145 -0
- benchlab/core/datasource.py +1209 -0
- benchlab/core/datasource_manager.py +418 -0
- benchlab/core/device_registry.py +206 -0
- benchlab/core/discovery.py +92 -0
- benchlab/core/infrastructure.py +309 -0
- benchlab/core/process_manager.py +356 -0
- benchlab/core/retry.py +85 -0
- benchlab/core/shared_serial.py +235 -0
- benchlab/core/statistics.py +224 -0
- benchlab/csv_log/README.md +206 -0
- benchlab/csv_log/__init__.py +5 -0
- benchlab/csv_log/csv_logger_enhanced.py +416 -0
- benchlab/csv_log/message_batcher.py +361 -0
- benchlab/csv_log/requirements.txt +3 -0
- benchlab/csv_log/smart_retry.py +466 -0
- benchlab/graph/README.md +117 -0
- benchlab/graph/__init__.py +5 -0
- benchlab/graph/app.py +353 -0
- benchlab/graph/requirements.txt +2 -0
- benchlab/graph/runner.py +42 -0
- benchlab/graph/ui.py +288 -0
- benchlab/hwinfo/README.md +135 -0
- benchlab/hwinfo/__init__.py +5 -0
- benchlab/hwinfo/hwinfo_export.py +386 -0
- benchlab/hwinfo/requirements.txt +1 -0
- benchlab/launcher.py +387 -0
- benchlab/link/.env.EXAMPLE +10 -0
- benchlab/link/README.md +172 -0
- benchlab/link/__init__.py +1 -0
- benchlab/link/link_main.py +479 -0
- benchlab/main.py +462 -0
- benchlab/menu.py +729 -0
- benchlab/menu_classic.py +410 -0
- benchlab/mqtt/README.md +201 -0
- benchlab/mqtt/__init__.py +5 -0
- benchlab/mqtt/mqtt.config_template +2 -0
- benchlab/mqtt/mqtt_publisher.py +540 -0
- benchlab/mqtt/requirements.txt +3 -0
- benchlab/prefs.py +67 -0
- benchlab/restapi/.env.example +17 -0
- benchlab/restapi/__init__.py +5 -0
- benchlab/restapi/favicon.ico +0 -0
- benchlab/restapi/readme.md +202 -0
- benchlab/restapi/requirements.txt +5 -0
- benchlab/restapi/telemetry_api.py +808 -0
- benchlab/sources.py +515 -0
- benchlab/tools.py +147 -0
- benchlab/tui/README.md +266 -0
- benchlab/tui/__init__.py +5 -0
- benchlab/tui/config.py +477 -0
- benchlab/tui/requirements.txt +2 -0
- benchlab/tui/tui_core.py +1298 -0
- benchlab/tui/tui_main.py +418 -0
- benchlab/vu/README.md +64 -0
- benchlab/vu/VU-Server/NOTICE.md +13 -0
- benchlab/vu/VU-Server/README.md +80 -0
- benchlab/vu/VU-Server/Running_from_source_on_linux.md +97 -0
- benchlab/vu/VU-Server/__init__.py +0 -0
- benchlab/vu/VU-Server/assets/vu1_hello_world.png +0 -0
- benchlab/vu/VU-Server/community_applications.md +13 -0
- benchlab/vu/VU-Server/config.yaml +9 -0
- benchlab/vu/VU-Server/database.py +256 -0
- benchlab/vu/VU-Server/dial_driver.py +534 -0
- benchlab/vu/VU-Server/dials/Comms_Hub_Gauge.py +78 -0
- benchlab/vu/VU-Server/dials/Comms_Hub_Server.py +100 -0
- benchlab/vu/VU-Server/dials/__init__.py +0 -0
- benchlab/vu/VU-Server/dials/base_logger.py +100 -0
- benchlab/vu/VU-Server/installer/inc/icon.ico +0 -0
- benchlab/vu/VU-Server/installer/install.nsi +148 -0
- benchlab/vu/VU-Server/make_version.py +40 -0
- benchlab/vu/VU-Server/pylintrc +628 -0
- benchlab/vu/VU-Server/requirements.txt +9 -0
- benchlab/vu/VU-Server/serial_driver.py +244 -0
- benchlab/vu/VU-Server/server.py +670 -0
- benchlab/vu/VU-Server/server_config.py +255 -0
- benchlab/vu/VU-Server/server_dial_handler.py +334 -0
- benchlab/vu/VU-Server/vu_notifications.py +24 -0
- benchlab/vu/VU-Server/www/android-chrome-192x192.png +0 -0
- benchlab/vu/VU-Server/www/android-chrome-512x512.png +0 -0
- benchlab/vu/VU-Server/www/apple-touch-icon.png +0 -0
- benchlab/vu/VU-Server/www/assets/css/demo.css +291 -0
- benchlab/vu/VU-Server/www/assets/css/demo.min.css +9 -0
- benchlab/vu/VU-Server/www/assets/css/demo.rtl.css +276 -0
- benchlab/vu/VU-Server/www/assets/css/demo.rtl.min.css +9 -0
- benchlab/vu/VU-Server/www/assets/css/tabler-flags.css +1084 -0
- benchlab/vu/VU-Server/www/assets/css/tabler-flags.min.css +9 -0
- benchlab/vu/VU-Server/www/assets/css/tabler-flags.rtl.css +1084 -0
- benchlab/vu/VU-Server/www/assets/css/tabler-flags.rtl.min.css +9 -0
- benchlab/vu/VU-Server/www/assets/css/tabler-payments.css +528 -0
- benchlab/vu/VU-Server/www/assets/css/tabler-payments.min.css +9 -0
- benchlab/vu/VU-Server/www/assets/css/tabler-payments.rtl.css +528 -0
- benchlab/vu/VU-Server/www/assets/css/tabler-payments.rtl.min.css +9 -0
- benchlab/vu/VU-Server/www/assets/css/tabler-social.css +10 -0
- benchlab/vu/VU-Server/www/assets/css/tabler-social.min.css +8 -0
- benchlab/vu/VU-Server/www/assets/css/tabler-social.rtl.css +10 -0
- benchlab/vu/VU-Server/www/assets/css/tabler-social.rtl.min.css +8 -0
- benchlab/vu/VU-Server/www/assets/css/tabler-vendors.css +1504 -0
- benchlab/vu/VU-Server/www/assets/css/tabler-vendors.min.css +9 -0
- benchlab/vu/VU-Server/www/assets/css/tabler-vendors.rtl.css +1504 -0
- benchlab/vu/VU-Server/www/assets/css/tabler-vendors.rtl.min.css +9 -0
- benchlab/vu/VU-Server/www/assets/css/tabler.css +25813 -0
- benchlab/vu/VU-Server/www/assets/css/tabler.min.css +13 -0
- benchlab/vu/VU-Server/www/assets/css/tabler.rtl.css +25777 -0
- benchlab/vu/VU-Server/www/assets/css/tabler.rtl.min.css +13 -0
- benchlab/vu/VU-Server/www/assets/css/theme.min.css +261 -0
- benchlab/vu/VU-Server/www/assets/img/header.png +0 -0
- benchlab/vu/VU-Server/www/assets/img/logo.png +0 -0
- benchlab/vu/VU-Server/www/assets/js/dark-theme.js +35 -0
- benchlab/vu/VU-Server/www/assets/js/dark-theme.min.js +9 -0
- benchlab/vu/VU-Server/www/assets/js/demo.js +132 -0
- benchlab/vu/VU-Server/www/assets/js/demo.min.js +9 -0
- benchlab/vu/VU-Server/www/assets/js/jquery.min.js +2 -0
- benchlab/vu/VU-Server/www/assets/js/tabler.esm.js +7482 -0
- benchlab/vu/VU-Server/www/assets/js/tabler.esm.min.js +15 -0
- benchlab/vu/VU-Server/www/assets/js/tabler.js +7543 -0
- benchlab/vu/VU-Server/www/assets/js/tabler.min.js +15 -0
- benchlab/vu/VU-Server/www/assets/js/vu1_api.js +68 -0
- benchlab/vu/VU-Server/www/assets/js/vu1_gui_api_key_settings.js +167 -0
- benchlab/vu/VU-Server/www/assets/js/vu1_gui_api_keys.js +138 -0
- benchlab/vu/VU-Server/www/assets/js/vu1_gui_dial.js +179 -0
- benchlab/vu/VU-Server/www/assets/js/vu1_gui_home.js +60 -0
- benchlab/vu/VU-Server/www/assets/js/vu1_gui_root.js +125 -0
- benchlab/vu/VU-Server/www/favicon-16x16.png +0 -0
- benchlab/vu/VU-Server/www/favicon-32x32.png +0 -0
- benchlab/vu/VU-Server/www/favicon.ico +0 -0
- benchlab/vu/VU-Server/www/favicon.png +0 -0
- benchlab/vu/VU-Server/www/index.html +47 -0
- benchlab/vu/VU-Server/www/views/api_keys.html +151 -0
- benchlab/vu/VU-Server/www/views/dial.html +286 -0
- benchlab/vu/VU-Server/www/views/footer.html +27 -0
- benchlab/vu/VU-Server/www/views/header.html +86 -0
- benchlab/vu/VU-Server/www/views/key_settings.html +132 -0
- benchlab/vu/VU-Server/www/views/start.html +124 -0
- benchlab/vu/__init__.py +5 -0
- benchlab/vu/assets/Barlow-Bold.ttf +0 -0
- benchlab/vu/assets/bl_dial_144x200.png +0 -0
- benchlab/vu/assets/bl_logo_144x200.png +0 -0
- benchlab/vu/devices.py +166 -0
- benchlab/vu/requirements.txt +24 -0
- benchlab/vu/sensors.py +18 -0
- benchlab/vu/vu_dial.config_template +90 -0
- benchlab/vu/vu_logo_gen.py +97 -0
- benchlab/vu/vu_server.config_template +5 -0
- benchlab/vu/vu_server_config.py +40 -0
- benchlab/vu/vu_server_manager.py +192 -0
- benchlab/vu/vu_tui.py +919 -0
- benchlab/vu/vu_updater.py +540 -0
- benchlab/wigidash/README.md +182 -0
- benchlab/wigidash/__init__.py +5 -0
- benchlab/wigidash/assets/Inter-Bold.ttf +0 -0
- benchlab/wigidash/assets/Inter.ttf +0 -0
- benchlab/wigidash/assets/benchlab.png +0 -0
- benchlab/wigidash/benchlab_fleet.py +150 -0
- benchlab/wigidash/benchlab_graph.py +517 -0
- benchlab/wigidash/benchlab_overview.py +426 -0
- benchlab/wigidash/benchlab_telemetry.py +105 -0
- benchlab/wigidash/benchlab_ui.py +190 -0
- benchlab/wigidash/benchlab_utils.py +182 -0
- benchlab/wigidash/requirements.txt +9 -0
- benchlab/wigidash/wigidash_device.py +541 -0
- benchlab/wigidash/wigidash_manager.py +342 -0
- benchlab/wigidash/wigidash_session.py +355 -0
- benchlab/wigidash/wigidash_usb.py +247 -0
- benchlab/wigidash/wigidash_widget.py +88 -0
- benchlab_pytools-3.0.0.dist-info/METADATA +239 -0
- benchlab_pytools-3.0.0.dist-info/RECORD +184 -0
- benchlab_pytools-3.0.0.dist-info/WHEEL +4 -0
- benchlab_pytools-3.0.0.dist-info/entry_points.txt +2 -0
- benchlab_pytools-3.0.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,534 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import time
|
|
3
|
+
import textwrap
|
|
4
|
+
import math
|
|
5
|
+
from datetime import timedelta
|
|
6
|
+
from io import BytesIO
|
|
7
|
+
import numpy as np
|
|
8
|
+
from PIL import Image
|
|
9
|
+
from serial.tools.list_ports import comports
|
|
10
|
+
from dials.Comms_Hub_Server import hub_config, hub_commands, hub_data_types, hub_status_codes
|
|
11
|
+
from dials.base_logger import logger
|
|
12
|
+
from serial_driver import SerialHardware
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class DialSerialDriver(SerialHardware):
|
|
16
|
+
dials = {}
|
|
17
|
+
hub_info = {}
|
|
18
|
+
|
|
19
|
+
def __init__(self, port_info):
|
|
20
|
+
super(DialSerialDriver, self).__init__(port_info, timeout=2)
|
|
21
|
+
|
|
22
|
+
self.commands = hub_commands()
|
|
23
|
+
self.hub_config = hub_config()
|
|
24
|
+
self.data_type = hub_data_types()
|
|
25
|
+
self.status_codes = hub_status_codes()
|
|
26
|
+
|
|
27
|
+
def _get_max_packet_size(self):
|
|
28
|
+
max_size = math.floor( (self.hub_config.GAUGE_COMM_MAX_RX_DATA_LEN - (self.hub_config.GAUGE_COMM_HEADER_LEN*2) )/2)
|
|
29
|
+
return max_size
|
|
30
|
+
|
|
31
|
+
def _sendCommand(self, cmd, dataType, dataLen=0, data=None):
|
|
32
|
+
if dataLen == 0:
|
|
33
|
+
payload = ">{:02X}{:02X}{:04X}".format(cmd, dataType, dataLen)
|
|
34
|
+
elif dataLen == 1:
|
|
35
|
+
if data < 256:
|
|
36
|
+
payload = ">{:02X}{:02X}{:04X}{:02X}".format(cmd, dataType, dataLen, data)
|
|
37
|
+
elif data >= 256:
|
|
38
|
+
payload = ">{:02X}{:02X}{:04X}{:04X}".format(cmd, dataType, dataLen+1, data)
|
|
39
|
+
elif dataLen > 1:
|
|
40
|
+
formattedData = ""
|
|
41
|
+
for elem in data:
|
|
42
|
+
if isinstance(elem, str):
|
|
43
|
+
formattedData = formattedData + f"{int(elem):0{2 if int(elem) < 256 else 4}X}"
|
|
44
|
+
elif isinstance(elem, int):
|
|
45
|
+
formattedData = formattedData + f"{elem:0{2 if elem < 256 else 4}X}"
|
|
46
|
+
else:
|
|
47
|
+
raise ValueError('Unsupported data type ({})'.format(type(elem)))
|
|
48
|
+
|
|
49
|
+
payload = ">{:02X}{:02X}{:04X}{}".format(cmd, dataType, int(len(formattedData)/2), formattedData)
|
|
50
|
+
|
|
51
|
+
logger.debug(f"CMD:{cmd} - Type:{dataType} - Len:{dataLen}".format(payload))
|
|
52
|
+
logger.debug("Sending `{}`".format(payload))
|
|
53
|
+
response = self.serial_transaction(payload)
|
|
54
|
+
return self._parseResponse(response)
|
|
55
|
+
|
|
56
|
+
def _send_cmd_with_uin32(self, dialID, cmd, value, dt=None):
|
|
57
|
+
if dt is None:
|
|
58
|
+
dt = self.data_type.COMM_DATA_SINGLE_VALUE
|
|
59
|
+
data = [dialID, ((value>>24)&0xFF), ((value>>16)&0xFF), ((value>>8)&0xFF), (value&0xFF)]
|
|
60
|
+
return self._sendCommand(cmd, dt, len(data), data)
|
|
61
|
+
|
|
62
|
+
def _parseResponse(self, response):
|
|
63
|
+
for line in response:
|
|
64
|
+
logger.debug(line)
|
|
65
|
+
if line.startswith('<'):
|
|
66
|
+
cmd = line[1:3]
|
|
67
|
+
dataType = line[3:5]
|
|
68
|
+
dataLen = line[5:9]
|
|
69
|
+
data = line[9:]
|
|
70
|
+
ret = {'cmd':cmd, 'dataType':dataType, 'dataLen':dataLen, 'data':data}
|
|
71
|
+
|
|
72
|
+
if dataType == self.data_type.COMM_DATA_STATUS_CODE:
|
|
73
|
+
return self._checkStatus(ret['data'])
|
|
74
|
+
return ret['data']
|
|
75
|
+
return False
|
|
76
|
+
|
|
77
|
+
def _checkStatus(self, statusCode):
|
|
78
|
+
if int(statusCode, 16) == self.status_codes.GAUGE_STATUS_OK:
|
|
79
|
+
return True
|
|
80
|
+
logger.error("Error code: {}".format(int(statusCode, 16)))
|
|
81
|
+
return False
|
|
82
|
+
|
|
83
|
+
def _convert_hex_str_to_str(self, hex_string):
|
|
84
|
+
if not hex_string:
|
|
85
|
+
logger.error(f"Empty hex string received {hex_string}")
|
|
86
|
+
return ''
|
|
87
|
+
|
|
88
|
+
if len(hex_string)%2:
|
|
89
|
+
logger.error(f"Hex string should be divisible by 2! (len={len(hex_string)})")
|
|
90
|
+
return ''
|
|
91
|
+
|
|
92
|
+
try:
|
|
93
|
+
byte_array = bytearray.fromhex(hex_string)
|
|
94
|
+
hex_string = byte_array.decode()
|
|
95
|
+
return hex_string
|
|
96
|
+
except Exception as e:
|
|
97
|
+
logger.error(e)
|
|
98
|
+
return ''
|
|
99
|
+
|
|
100
|
+
def _convert_hex_str_to_byte_array(self, hex_string):
|
|
101
|
+
if not hex_string:
|
|
102
|
+
logger.error(f"Empty hex string received {hex_string}")
|
|
103
|
+
return bytes()
|
|
104
|
+
|
|
105
|
+
if len(hex_string)%2:
|
|
106
|
+
logger.error(f"Hex string should be divisible by 2! (len={len(hex_string)})")
|
|
107
|
+
return bytes()
|
|
108
|
+
|
|
109
|
+
try:
|
|
110
|
+
byte_array = bytearray.fromhex(hex_string)
|
|
111
|
+
return byte_array
|
|
112
|
+
except Exception as e:
|
|
113
|
+
logger.error(e)
|
|
114
|
+
return bytes()
|
|
115
|
+
|
|
116
|
+
def bus_rescan(self):
|
|
117
|
+
logger.debug("@bus_rescan")
|
|
118
|
+
return self._sendCommand(self.commands.COMM_CMD_RESCAN_BUS, self.data_type.COMM_DATA_NONE)
|
|
119
|
+
|
|
120
|
+
def get_dial_list(self, rescan=False):
|
|
121
|
+
logger.debug(f"@get_dial_list(rescan={rescan})")
|
|
122
|
+
if rescan:
|
|
123
|
+
resp = self.bus_rescan()
|
|
124
|
+
resp = self._sendCommand(self.commands.COMM_CMD_GET_DEVICES_MAP, self.data_type.COMM_DATA_NONE)
|
|
125
|
+
if not resp:
|
|
126
|
+
logger.error("Invalid response received from COMM_CMD_GET_DEVICES_MAP")
|
|
127
|
+
logger.error(resp)
|
|
128
|
+
return []
|
|
129
|
+
|
|
130
|
+
resp = textwrap.wrap(resp, 2)
|
|
131
|
+
onlineDials = []
|
|
132
|
+
for key, elem in enumerate(resp):
|
|
133
|
+
if int(elem, 16) == 1:
|
|
134
|
+
onlineDials.append(key)
|
|
135
|
+
|
|
136
|
+
for dialIndex in onlineDials:
|
|
137
|
+
deviceUID = self.dial_get_uid(dialIndex) # Read dial UID
|
|
138
|
+
# Friendly name will be added from config
|
|
139
|
+
self.dials[dialIndex] = {
|
|
140
|
+
'index': str(dialIndex),
|
|
141
|
+
'uid': deviceUID,
|
|
142
|
+
'dial_name': 'Not set',
|
|
143
|
+
'value': 0,
|
|
144
|
+
'rgbw': [0, 0, 0, 0],
|
|
145
|
+
'easing': {
|
|
146
|
+
'dial_step': '?',
|
|
147
|
+
'dial_period': '?',
|
|
148
|
+
'backlight_step': '?',
|
|
149
|
+
'backlight_period': '?',
|
|
150
|
+
},
|
|
151
|
+
'fw_hash': '?',
|
|
152
|
+
'fw_version': '?',
|
|
153
|
+
'hw_version': '?',
|
|
154
|
+
'protocol_version': '?',
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
dialList = []
|
|
158
|
+
for key, val in self.dials.items():
|
|
159
|
+
dialList.append(val)
|
|
160
|
+
|
|
161
|
+
return dialList
|
|
162
|
+
|
|
163
|
+
def set_all_dials_to(self, value):
|
|
164
|
+
logger.debug(f"@set_all_dials_to(value={value})")
|
|
165
|
+
dials = []
|
|
166
|
+
values = []
|
|
167
|
+
|
|
168
|
+
for dial in self.dials:
|
|
169
|
+
dials.append(dial)
|
|
170
|
+
values.append(value)
|
|
171
|
+
self.dials[dial]['value'] = 0
|
|
172
|
+
|
|
173
|
+
self.dial_multiple_set_percent(dials, values)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def get_dial(self, dialID=None, UID=None):
|
|
177
|
+
if dialID is None and UID is None:
|
|
178
|
+
logger.error("Both dial ID and UID can't be none!")
|
|
179
|
+
return {}
|
|
180
|
+
|
|
181
|
+
if dialID is None:
|
|
182
|
+
dialID = self._findDial(UID)
|
|
183
|
+
|
|
184
|
+
if dialID is None:
|
|
185
|
+
logger.error("Dial with UID `{}` is not present.".format(UID))
|
|
186
|
+
return None
|
|
187
|
+
|
|
188
|
+
return self.dials[dialID]
|
|
189
|
+
|
|
190
|
+
def set_dial(self, dialID=None, UID=None, value=None, sendCMD=True):
|
|
191
|
+
if dialID is None and UID is None:
|
|
192
|
+
logger.error("Both dial ID and UID can't be none!")
|
|
193
|
+
return {}
|
|
194
|
+
|
|
195
|
+
if dialID is None:
|
|
196
|
+
dialID = self._findDial(UID)
|
|
197
|
+
|
|
198
|
+
if dialID is None:
|
|
199
|
+
logger.error("Dial with UID `{}` is not present.".format(UID))
|
|
200
|
+
return False
|
|
201
|
+
|
|
202
|
+
if sendCMD:
|
|
203
|
+
self.dial_single_set_percent(dialID, int(value))
|
|
204
|
+
return True
|
|
205
|
+
|
|
206
|
+
def _findDial(self, UID):
|
|
207
|
+
for entry in self.dials:
|
|
208
|
+
if self.dials[entry]['uid'] == UID:
|
|
209
|
+
return entry
|
|
210
|
+
return None
|
|
211
|
+
|
|
212
|
+
def _verify_device(self, device):
|
|
213
|
+
if isinstance(device, str):
|
|
214
|
+
if len(device) <= 3:
|
|
215
|
+
return int(device)
|
|
216
|
+
device = self._findDial(device)
|
|
217
|
+
|
|
218
|
+
if device is None:
|
|
219
|
+
logger.error(f"Can not find dial '{device}'")
|
|
220
|
+
return device
|
|
221
|
+
|
|
222
|
+
elif isinstance(device, int):
|
|
223
|
+
return device
|
|
224
|
+
|
|
225
|
+
else:
|
|
226
|
+
raise ValueError(f"Unexpected device type type(device)='{type(device)}'")
|
|
227
|
+
|
|
228
|
+
def dial_get_uid(self, dialIndex):
|
|
229
|
+
logger.debug(f"@dial_get_uid(dialIndex={dialIndex})")
|
|
230
|
+
return self._sendCommand(self.commands.COMM_CMD_GET_DEVICE_UID, self.data_type.COMM_DATA_SINGLE_VALUE, 1, dialIndex)
|
|
231
|
+
|
|
232
|
+
def dial_get_fw_hash(self, dialIndex):
|
|
233
|
+
logger.debug(f"@dial_get_fw_hash(dialIndex={dialIndex})")
|
|
234
|
+
cmd = self.commands.COMM_CMD_GET_BUILD_INFO
|
|
235
|
+
data = dialIndex
|
|
236
|
+
ret = self._sendCommand(cmd, self.data_type.COMM_DATA_SINGLE_VALUE, 1, data)
|
|
237
|
+
return self._convert_hex_str_to_str(ret)
|
|
238
|
+
|
|
239
|
+
def dial_get_fw_version(self, dialIndex):
|
|
240
|
+
logger.debug(f"@dial_get_fw_version(dialIndex={dialIndex})")
|
|
241
|
+
cmd = self.commands.COMM_CMD_GET_FW_INFO
|
|
242
|
+
data = dialIndex
|
|
243
|
+
ret = self._sendCommand(cmd, self.data_type.COMM_DATA_SINGLE_VALUE, 1, data)
|
|
244
|
+
return self._convert_hex_str_to_str(ret)
|
|
245
|
+
|
|
246
|
+
def dial_get_hw_version(self, dialIndex):
|
|
247
|
+
logger.debug(f"@dial_get_hw_version(dialIndex={dialIndex})")
|
|
248
|
+
cmd = self.commands.COMM_CMD_GET_HW_INFO
|
|
249
|
+
data = dialIndex
|
|
250
|
+
ret = self._sendCommand(cmd, self.data_type.COMM_DATA_SINGLE_VALUE, 1, data)
|
|
251
|
+
return self._convert_hex_str_to_str(ret)
|
|
252
|
+
|
|
253
|
+
def dial_get_protocol_version(self, dialIndex):
|
|
254
|
+
logger.debug(f"@dial_get_hw_version(dialIndex={dialIndex})")
|
|
255
|
+
cmd = self.commands.COMM_CMD_GET_PROTOCOL_INFO
|
|
256
|
+
data = dialIndex
|
|
257
|
+
ret = self._sendCommand(cmd, self.data_type.COMM_DATA_SINGLE_VALUE, 1, data)
|
|
258
|
+
return self._convert_hex_str_to_str(ret)
|
|
259
|
+
|
|
260
|
+
def set_dial_power(self, powerOn=True):
|
|
261
|
+
logger.debug(f"@set_dial_power(powerOn={powerOn})")
|
|
262
|
+
data = 0
|
|
263
|
+
if powerOn is True:
|
|
264
|
+
data = 1
|
|
265
|
+
return self._sendCommand(self.commands.COMM_CMD_DIAL_POWER, self.data_type.COMM_DATA_SINGLE_VALUE, 1, data)
|
|
266
|
+
|
|
267
|
+
def dial_calibrate(self, dialID, value, fullScale=True):
|
|
268
|
+
logger.debug(f"@dial_calibrate(dialID={dialID}, value={value}, fullScale={fullScale})")
|
|
269
|
+
if fullScale:
|
|
270
|
+
cmd = self.commands.COMM_CMD_SET_DIAL_CALIBRATE_MAX
|
|
271
|
+
else:
|
|
272
|
+
cmd = self.commands.COMM_CMD_SET_DIAL_CALIBRATE_HALF
|
|
273
|
+
|
|
274
|
+
return self._send_cmd_with_uin32(dialID, cmd, value, dt=self.data_type.COMM_DATA_KEY_VALUE_PAIR)
|
|
275
|
+
|
|
276
|
+
def dial_easing_dial_step(self, dialID, value):
|
|
277
|
+
logger.debug(f"@dial_easing_dial_step(dialID={dialID}, value={value})")
|
|
278
|
+
cmd = self.commands.COMM_CMD_SET_DIAL_EASING_STEP
|
|
279
|
+
data = [dialID, ((value>>24)&0xFF), ((value>>16)&0xFF), ((value>>8)&0xFF), (value&0xFF)]
|
|
280
|
+
return self._sendCommand(cmd, self.data_type.COMM_DATA_SINGLE_VALUE, len(data), data)
|
|
281
|
+
|
|
282
|
+
def dial_easing_dial_period(self, dialID, value):
|
|
283
|
+
logger.debug(f"@dial_easing_dial_period(dialID={dialID}, value={value})")
|
|
284
|
+
cmd = self.commands.COMM_CMD_SET_DIAL_EASING_PERIOD
|
|
285
|
+
data = [dialID, ((value>>24)&0xFF), ((value>>16)&0xFF), ((value>>8)&0xFF), (value&0xFF)]
|
|
286
|
+
return self._sendCommand(cmd, self.data_type.COMM_DATA_SINGLE_VALUE, len(data), data)
|
|
287
|
+
|
|
288
|
+
def dial_easing_backlight_step(self, dialID, value):
|
|
289
|
+
logger.debug(f"@dial_easing_backlight_step(dialID={dialID}, value={value})")
|
|
290
|
+
cmd = self.commands.COMM_CMD_SET_BACKLIGHT_EASING_STEP
|
|
291
|
+
data = [dialID, ((value>>24)&0xFF), ((value>>16)&0xFF), ((value>>8)&0xFF), (value&0xFF)]
|
|
292
|
+
return self._sendCommand(cmd, self.data_type.COMM_DATA_SINGLE_VALUE, len(data), data)
|
|
293
|
+
|
|
294
|
+
def dial_easing_backlight_period(self, dialID, value):
|
|
295
|
+
logger.debug(f"@dial_easing_backlight_period(dialID={dialID}, value={value})")
|
|
296
|
+
cmd = self.commands.COMM_CMD_SET_BACKLIGHT_EASING_PERIOD
|
|
297
|
+
data = [dialID, ((value>>24)&0xFF), ((value>>16)&0xFF), ((value>>8)&0xFF), (value&0xFF)]
|
|
298
|
+
return self._sendCommand(cmd, self.data_type.COMM_DATA_SINGLE_VALUE, len(data), data)
|
|
299
|
+
|
|
300
|
+
def dial_easing_get_config(self, dialID):
|
|
301
|
+
easing = { 'dial_step':0, 'dial_period':0, 'backlight_step':0, 'backlight_period':0 }
|
|
302
|
+
logger.debug(f"@dial_easing_get_config(dialID={dialID})")
|
|
303
|
+
ret = self._sendCommand(self.commands.COMM_CMD_GET_EASING_CONFIG, self.data_type.COMM_DATA_SINGLE_VALUE, 1, dialID)
|
|
304
|
+
ret = self._convert_hex_str_to_byte_array(ret)
|
|
305
|
+
|
|
306
|
+
easing['dial_step'] = int(ret[0]) << 24 | int(ret[1]) << 16 | int(ret[2]) << 8 | int(ret[3])
|
|
307
|
+
easing['dial_period'] = int(ret[4]) << 24 | int(ret[5]) << 16 | int(ret[6]) << 8 | int(ret[7])
|
|
308
|
+
easing['backlight_step'] = int(ret[8]) << 24 | int(ret[9]) << 16 | int(ret[10]) << 8 | int(ret[11])
|
|
309
|
+
easing['backlight_period'] = int(ret[12]) << 24 | int(ret[13]) << 16 | int(ret[14]) << 8 | int(ret[15])
|
|
310
|
+
# logger.debug(f"@ret:{ret}")
|
|
311
|
+
# logger.debug(f"@easing:{easing}")
|
|
312
|
+
|
|
313
|
+
return easing
|
|
314
|
+
|
|
315
|
+
def dial_single_set_raw(self, dialID, value):
|
|
316
|
+
logger.debug(f"@dial_single_set_raw(dialID={dialID}, value={value})")
|
|
317
|
+
data = [dialID, ((value>>8)&0xFF), (value&0xFF)]
|
|
318
|
+
return self._sendCommand(self.commands.COMM_CMD_SET_DIAL_RAW_SINGLE, self.data_type.COMM_DATA_KEY_VALUE_PAIR, len(data), data)
|
|
319
|
+
|
|
320
|
+
def dial_single_set_percent(self, dialID, value):
|
|
321
|
+
logger.debug(f"@dial_single_set_percent(dialID={dialID}, value={value})")
|
|
322
|
+
if self.dials.get(int(dialID), False):
|
|
323
|
+
self.dials[int(dialID)]['value'] = value
|
|
324
|
+
data = [dialID, (value&0xFF)]
|
|
325
|
+
return self._sendCommand(self.commands.COMM_CMD_SET_DIAL_PERC_SINGLE, self.data_type.COMM_DATA_KEY_VALUE_PAIR, len(data), data)
|
|
326
|
+
|
|
327
|
+
def dial_multiple_set_percent(self, devices, values):
|
|
328
|
+
logger.debug(f"@dial_multiple_set_percent(devices={devices}, values={values})")
|
|
329
|
+
if len(devices) != len(values):
|
|
330
|
+
logger.error("Number of devices does not match number of values")
|
|
331
|
+
return False
|
|
332
|
+
|
|
333
|
+
data = []
|
|
334
|
+
for i in range(len(devices)):
|
|
335
|
+
self.set_dial(devices[i], values[i], sendCMD=False)
|
|
336
|
+
data.append(devices[i])
|
|
337
|
+
data.append(values[i])
|
|
338
|
+
|
|
339
|
+
return self._sendCommand(self.commands.COMM_CMD_SET_DIAL_PERC_MULTIPLE, self.data_type.COMM_DATA_KEY_VALUE_PAIR, len(data), data)
|
|
340
|
+
|
|
341
|
+
def dial_display_clear(self, device, whiteBackground=True):
|
|
342
|
+
logger.debug(f"@dial_display_clear(device={device}, whiteBackground={whiteBackground})")
|
|
343
|
+
if whiteBackground:
|
|
344
|
+
data = [int(device), 0]
|
|
345
|
+
else:
|
|
346
|
+
data = [int(device), 1]
|
|
347
|
+
return self._sendCommand(self.commands.COMM_CMD_DISPLAY_CLEAR, self.data_type.COMM_DATA_SINGLE_VALUE, len(data), data)
|
|
348
|
+
|
|
349
|
+
def dial_display_goto_xy(self, device, x, y):
|
|
350
|
+
logger.debug(f"@dial_display_goto_xy(device={device}, x={x}, y={y})")
|
|
351
|
+
data = [int(device), ((x>>8)&0xFF), (x&0xFF), ((y>>8)&0xFF), (y&0xFF)]
|
|
352
|
+
return self._sendCommand(self.commands.COMM_CMD_DISPLAY_GOTO_XY, self.data_type.COMM_DATA_SINGLE_VALUE, len(data), data)
|
|
353
|
+
|
|
354
|
+
def display_send_image(self, device, img_filepath):
|
|
355
|
+
logger.debug(f"@display_send_image(device={device}, img_filepath={img_filepath})")
|
|
356
|
+
if not os.path.exists(img_filepath):
|
|
357
|
+
logger.error(f"File '{img_filepath}' does not exist.")
|
|
358
|
+
return False
|
|
359
|
+
|
|
360
|
+
img_data = self.img_to_binary(img_filepath, True)
|
|
361
|
+
return self.display_send_image_data(device, img_data)
|
|
362
|
+
|
|
363
|
+
def display_send_image_data(self, device, imageData):
|
|
364
|
+
logger.debug(f"@display_send_image_data(device={device}, imageData={imageData})")
|
|
365
|
+
device = self._verify_device(device)
|
|
366
|
+
|
|
367
|
+
# chunkSize = self._get_max_packet_size()
|
|
368
|
+
chunkSize = 1000 # 1000 bytes at a time
|
|
369
|
+
dataLen = len(imageData)
|
|
370
|
+
chunks = math.ceil(len(imageData)/chunkSize)
|
|
371
|
+
|
|
372
|
+
logger.debug(f"Split {dataLen} bytes into {chunks} chunks of {chunkSize} bytes.")
|
|
373
|
+
|
|
374
|
+
start_time = time.time()
|
|
375
|
+
for i in range(chunks):
|
|
376
|
+
start = i*chunkSize
|
|
377
|
+
end = i*chunkSize + chunkSize
|
|
378
|
+
dataChunk = imageData[start:end]
|
|
379
|
+
if not self._send_image_chunk(device, dataChunk):
|
|
380
|
+
return False
|
|
381
|
+
time.sleep(0.2)
|
|
382
|
+
end_time = time.time()
|
|
383
|
+
logger.debug(f"Send image data took {timedelta(seconds=end_time-start_time)}")
|
|
384
|
+
return True
|
|
385
|
+
|
|
386
|
+
def _send_image_chunk(self, device, imageBuffer):
|
|
387
|
+
logger.debug(f"@_send_image_chunk(device={device})")
|
|
388
|
+
if len(imageBuffer) <= 0:
|
|
389
|
+
logger.error("Invalid image buffer size!")
|
|
390
|
+
return False
|
|
391
|
+
if isinstance(device, str):
|
|
392
|
+
device = self._findDial(device)
|
|
393
|
+
device = int(device)
|
|
394
|
+
|
|
395
|
+
data = [ device ]
|
|
396
|
+
data.extend(imageBuffer)
|
|
397
|
+
return self._sendCommand(self.commands.COMM_CMD_DISPLAY_IMG_DATA, self.data_type.COMM_DATA_SINGLE_VALUE, len(data), data)
|
|
398
|
+
|
|
399
|
+
def _format_bits(self, bits):
|
|
400
|
+
buff = []
|
|
401
|
+
for i in bits:
|
|
402
|
+
if i > 127:
|
|
403
|
+
buff.append(1)
|
|
404
|
+
else:
|
|
405
|
+
buff.append(0)
|
|
406
|
+
return buff
|
|
407
|
+
|
|
408
|
+
def binary_to_image_data(self, image):
|
|
409
|
+
img = Image.open(Image.open(BytesIO(image)))
|
|
410
|
+
img = img.convert("L")
|
|
411
|
+
|
|
412
|
+
imgData = np.asarray(img)
|
|
413
|
+
imgData = imgData.T.tolist()
|
|
414
|
+
|
|
415
|
+
buff = []
|
|
416
|
+
# Each byte is 8 vertical bits
|
|
417
|
+
for bits in imgData:
|
|
418
|
+
bits = self._format_bits(bits)
|
|
419
|
+
byte = [int("".join(map(str, bits[i:i+8])), 2) for i in range(0, len(bits), 8)]
|
|
420
|
+
buff.append(byte)
|
|
421
|
+
|
|
422
|
+
buff = [item for sublist in buff for item in sublist]
|
|
423
|
+
|
|
424
|
+
return buff
|
|
425
|
+
|
|
426
|
+
def img_to_binary(self, img_filepath, flatten=True):
|
|
427
|
+
buff = []
|
|
428
|
+
|
|
429
|
+
if not os.path.exists(img_filepath):
|
|
430
|
+
logger.error(f"File {img_filepath} does not exist!. Returning empty array.")
|
|
431
|
+
return buff
|
|
432
|
+
|
|
433
|
+
try:
|
|
434
|
+
#Load image and convert to greyscale
|
|
435
|
+
img = Image.open(img_filepath)
|
|
436
|
+
img = img.convert("L")
|
|
437
|
+
|
|
438
|
+
imgData = np.asarray(img)
|
|
439
|
+
imgData = imgData.T.tolist()
|
|
440
|
+
|
|
441
|
+
# Each byte is 8 vertical bits
|
|
442
|
+
for bits in imgData:
|
|
443
|
+
bits = self._format_bits(bits)
|
|
444
|
+
byte = [int("".join(map(str, bits[i:i+8])), 2) for i in range(0, len(bits), 8)]
|
|
445
|
+
buff.append(byte)
|
|
446
|
+
|
|
447
|
+
if flatten:
|
|
448
|
+
buff = [item for sublist in buff for item in sublist]
|
|
449
|
+
except Exception as e:
|
|
450
|
+
logger.error(e)
|
|
451
|
+
|
|
452
|
+
return buff
|
|
453
|
+
|
|
454
|
+
def update_display(self, device, imageData=None, imageFile=None):
|
|
455
|
+
logger.debug(f"@update_display(device={device})")
|
|
456
|
+
device = self._verify_device(device)
|
|
457
|
+
|
|
458
|
+
self.dial_display_clear(device, True)
|
|
459
|
+
self.dial_display_goto_xy(device, 0, 0)
|
|
460
|
+
|
|
461
|
+
if imageData is not None:
|
|
462
|
+
self.display_send_image_data(device, imageData)
|
|
463
|
+
elif imageFile is not None:
|
|
464
|
+
self.display_send_image(device, imageFile)
|
|
465
|
+
else:
|
|
466
|
+
raise ValueError("Image data and ImageFile can't both be none!")
|
|
467
|
+
self.dial_display_show(device)
|
|
468
|
+
return True
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
def get_dial_rx_buffer_size(self, device):
|
|
472
|
+
logger.debug(f"@get_dial_rx_buffer_size(device={device})")
|
|
473
|
+
rxLen = self._sendCommand(self.commands.COMM_CMD_RX_BUFFER_SIZE, self.data_type.COMM_DATA_SINGLE_VALUE, 1, int(device))
|
|
474
|
+
rxLen = int(rxLen[:8], 16)
|
|
475
|
+
return rxLen
|
|
476
|
+
|
|
477
|
+
def dial_display_show(self, device):
|
|
478
|
+
logger.debug(f"@dial_display_show(device={device})")
|
|
479
|
+
return self._sendCommand(self.commands.COMM_CMD_DISPLAY_SHOW_IMG, self.data_type.COMM_DATA_SINGLE_VALUE, 1, int(device))
|
|
480
|
+
|
|
481
|
+
def dial_set_backlight(self, device, red, green, blue, white):
|
|
482
|
+
logger.debug(f"@dial_set_backlight(device={device}, red={red}, green={green}, green={green}, blue={blue}, white={white})")
|
|
483
|
+
device = self._verify_device(device)
|
|
484
|
+
self.dials[device]['rgbw'][0] = red
|
|
485
|
+
self.dials[device]['rgbw'][1] = green
|
|
486
|
+
self.dials[device]['rgbw'][2] = blue
|
|
487
|
+
self.dials[device]['rgbw'][3] = white
|
|
488
|
+
data = [device, red, green, blue, white]
|
|
489
|
+
return self._sendCommand(self.commands.COMM_CMD_SET_RGB_BACKLIGHT, self.data_type.COMM_DATA_MULTIPLE_VALUE, len(data), data)
|
|
490
|
+
|
|
491
|
+
def dial_send_keep_comm_alive(self, device):
|
|
492
|
+
pass
|
|
493
|
+
# logger.debug(f"@dial_send_keep_comm_alive(device={device})")
|
|
494
|
+
# device = self._verify_device(device)
|
|
495
|
+
# return self._sendCommand(self.commands.DG_HUB_TO_DEV_KEEP_ALIVE, self.data_type.COMM_DATA_NONE)
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
def provision_dials(self):
|
|
499
|
+
logger.debug("@provision_dials")
|
|
500
|
+
return self._sendCommand(self.commands.COMM_CMD_PROVISION_DEVICE, self.data_type.COMM_DATA_NONE)
|
|
501
|
+
|
|
502
|
+
def reset_all_devices(self):
|
|
503
|
+
logger.debug("@reset_all_devices")
|
|
504
|
+
return self._sendCommand(self.commands.COMM_CMD_RESET_ALL_DEVICES, self.data_type.COMM_DATA_NONE)
|
|
505
|
+
|
|
506
|
+
def debug_i2c_scan(self):
|
|
507
|
+
logger.debug("@debug_i2c_scan")
|
|
508
|
+
return self._sendCommand(self.commands.COMM_CMD_DEBUG_I2C_SCAN, self.data_type.COMM_DATA_NONE)
|
|
509
|
+
|
|
510
|
+
def debug_print_all_dials(self):
|
|
511
|
+
# Show found dials
|
|
512
|
+
for entry in self.dials:
|
|
513
|
+
dial = self.dials[entry]
|
|
514
|
+
print(f"Dial #{dial['index']}")
|
|
515
|
+
print(f" - UID:{dial['uid']}")
|
|
516
|
+
print(f" - FriendlyName:{dial['friendlyName']}")
|
|
517
|
+
print(f" - Value:{dial['value']}")
|
|
518
|
+
|
|
519
|
+
@classmethod
|
|
520
|
+
def find_gauge_hub(cls):
|
|
521
|
+
availablePorts = comports()
|
|
522
|
+
logger.debug("Searching for COM port with VID:1027 and PID:24597")
|
|
523
|
+
for port in availablePorts:
|
|
524
|
+
logger.debug(f"{port.device}")
|
|
525
|
+
logger.debug(f"\tProduct: {port.product}")
|
|
526
|
+
logger.debug(f"\tDesc: {port.description}")
|
|
527
|
+
logger.debug(f"\tSN: {port.serial_number}")
|
|
528
|
+
logger.debug(f"\tVID:{port.vid} PID:{port.pid}")
|
|
529
|
+
logger.debug(f"\tLocation: {port.location}")
|
|
530
|
+
logger.debug(f"\tInterface: {port.interface}")
|
|
531
|
+
if port.vid == 1027 and port.pid == 24597:
|
|
532
|
+
logger.debug("Using '{}' as GaugeHub COM port".format(port.description))
|
|
533
|
+
return port
|
|
534
|
+
return None
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# This file was automatically generated using `generate_pyton_classes.py` script.
|
|
2
|
+
# Please don't make any direct modifications to this file as they will be overwritten and lost in the next cycle.
|
|
3
|
+
# Instead please make modification in the respective .yaml file.
|
|
4
|
+
# Generated on 2023-10-06 23:18
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class dial_bus_config:
|
|
8
|
+
GAUGE_HUB_MAX_DEVICES = 100
|
|
9
|
+
GAUGE_HUB_UID_LENGTH = 12
|
|
10
|
+
GAUGE_I2C_ADDRESS_BOOTLOADER = 0x08
|
|
11
|
+
GAUGE_I2C_ADDRESS_PROVISIONING = 0x09
|
|
12
|
+
GAUGE_I2C_ADDRESS_GENERAL_CALL = 0x00
|
|
13
|
+
GAUGE_I2C_ADDRESS_FIRST = 0x0A
|
|
14
|
+
GAUGE_I2C_ADDRESS_LAST = (GAUGE_I2C_ADDRESS_FIRST+GAUGE_HUB_MAX_DEVICES)
|
|
15
|
+
GAUGE_COMMS_POS_CMD = 0
|
|
16
|
+
GAUGE_COMMS_POS_DATA_LEN = 1
|
|
17
|
+
GAUGE_COMMS_POS_DATA = GAUGE_COMMS_POS_DATA_LEN+2
|
|
18
|
+
GAUGE_COMMS_RX_SIZE = 1100
|
|
19
|
+
GAUGE_I2C_DEVICE_READY_RETRIES = 15
|
|
20
|
+
GAUGE_DIAL_PROTOCOL_VERSION = "v1"
|
|
21
|
+
GAUGE_I2C_JUMP_TO_BTL_KEY1 = 0x53
|
|
22
|
+
GAUGE_I2C_JUMP_TO_BTL_KEY2 = 0x4B
|
|
23
|
+
|
|
24
|
+
class dial_commands:
|
|
25
|
+
DG_HUB_CMD_FIRST = 0x00
|
|
26
|
+
DG_HUB_TO_DEV_GET_UID = 0x01
|
|
27
|
+
DG_HUB_TO_DEV_HUB_UID = 0x02
|
|
28
|
+
DG_HUB_TO_DEV_SET_ADDRESS = 0x03
|
|
29
|
+
DG_HUB_TO_DEV_SET_DAC = 0x04
|
|
30
|
+
DG_HUB_TO_DEV_GET_DAC = 0x05
|
|
31
|
+
DG_HUB_TO_DEV_CYCLE_GAUGE = 0x06
|
|
32
|
+
DG_HUB_TO_DEV_PWR_LED_ENABLE = 0x07
|
|
33
|
+
DG_HUB_TO_DEV_PWR_LED_DISABLE = 0x08
|
|
34
|
+
DG_HUB_TO_DEV_ACT_LED_ENABLE = 0x09
|
|
35
|
+
DG_HUB_TO_DEV_ACT_LED_DISABLE = 0x0A
|
|
36
|
+
DG_HUB_TO_DEV_VERIFY_UID = 0x0B
|
|
37
|
+
DG_HUB_TO_DEV_GET_PROPERTIES = 0x0C
|
|
38
|
+
DG_HUB_TO_DEV_SET_PERCENT = 0x0D
|
|
39
|
+
DG_HUB_TO_DEV_GET_PERCENT = 0x0E
|
|
40
|
+
DG_HUB_TO_DEV_SET_DIAL_MAX = 0x0F
|
|
41
|
+
DG_HUB_TO_DEV_SET_DIAL_HALF = 0x10
|
|
42
|
+
DG_HUB_TO_DEV_GET_VERSION = 0x11
|
|
43
|
+
DG_HUB_TO_DEV_SET_RGB_BACKLIGHT = 0x12
|
|
44
|
+
DG_HUB_TO_DEV_GET_RGB_BACKLIGHT = 0x13
|
|
45
|
+
DG_HUB_TO_DEV_DISPLAY_CLEAR = 0x14
|
|
46
|
+
DG_HUB_TO_DEV_DISPLAY_GOTO_XY = 0x15
|
|
47
|
+
DG_HUB_TO_DEV_DISPLAY_IMG_DATA = 0x16
|
|
48
|
+
DG_HUB_TO_DEV_DISPLAY_SHOW_IMG = 0x17
|
|
49
|
+
DG_HUB_TO_DEV_RX_BUFFER_SIZE = 0x18
|
|
50
|
+
DG_HUB_TO_DEV_KEEP_ALIVE = 0x19
|
|
51
|
+
DG_HUB_TO_DEV_SERVER_ABSENT = 0x1A
|
|
52
|
+
DG_HUB_TO_DEV_SERVER_PRESENT = 0x1B
|
|
53
|
+
DG_HUB_TO_DEV_DIAL_EASING_STEP = 0x1C
|
|
54
|
+
DG_HUB_TO_DEV_DIAL_EASING_PERIOD = 0x1D
|
|
55
|
+
DG_HUB_TO_DEV_BACKLIGHT_EASING_STEP = 0x1E
|
|
56
|
+
DG_HUB_TO_DEV_BACKLIGHT_EASING_PERIOD = 0x1F
|
|
57
|
+
DG_HUB_TO_DEV_GET_EASING_CONFIG = 0x20
|
|
58
|
+
DG_HUB_TO_DEV_BUILD_INFO = 0x21
|
|
59
|
+
DG_HUB_TO_DEV_FW_INFO = 0x22
|
|
60
|
+
DG_HUB_TO_DEV_HW_INFO = 0x23
|
|
61
|
+
DG_HUB_TO_DEV_PROTOCOL_INFO = 0x24
|
|
62
|
+
DG_HUB_TO_DEV_BTL_JUMP_TO_BOOTLOADER = 0xF0
|
|
63
|
+
DG_HUB_TO_DEV_BTL_BOOTLOADER_INFO = 0xF1
|
|
64
|
+
DG_HUB_TO_DEV_BTL_GET_CRC = 0xF2
|
|
65
|
+
DG_HUB_TO_DEV_BTL_ERASE_APP = 0xF3
|
|
66
|
+
DG_HUB_TO_DEV_FWUP_PACKAGE = 0xF4
|
|
67
|
+
DG_HUB_TO_DEV_FWUP_FINISHED = 0xF5
|
|
68
|
+
DG_HUB_TO_DEV_BTL_EXIT = 0xF6
|
|
69
|
+
DG_HUB_TO_DEV_BTL_RESTART_UPLOAD = 0xF7
|
|
70
|
+
DG_HUB_TO_DEV_BTL_READ_STATUS_CODE = 0xF8
|
|
71
|
+
DG_HUB_TO_DEV_RESET_CFG = 0xFA
|
|
72
|
+
DG_HUB_CMD_LAST = None
|
|
73
|
+
|
|
74
|
+
class device_types:
|
|
75
|
+
DG_DEVICE_TYPE_FIRST = 0x00
|
|
76
|
+
DG_DEVICE_TYPE_ANALOG_GAUGE = 0x01
|
|
77
|
+
DG_DEVICE_TYPE_EINK_GAUGE = 0x02
|
|
78
|
+
DG_DEVICE_TYPE_LAST = None
|