enode-host 0.1.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 (44) hide show
  1. enode_host-0.1.0/PKG-INFO +81 -0
  2. enode_host-0.1.0/README.md +69 -0
  3. enode_host-0.1.0/pyproject.toml +25 -0
  4. enode_host-0.1.0/setup.cfg +4 -0
  5. enode_host-0.1.0/src/enode_host/__init__.py +1 -0
  6. enode_host-0.1.0/src/enode_host/async_socket.py +165 -0
  7. enode_host-0.1.0/src/enode_host/backup/c-wing3.py +226 -0
  8. enode_host-0.1.0/src/enode_host/backup/c.py +226 -0
  9. enode_host-0.1.0/src/enode_host/backup/esp_mesh.py +136 -0
  10. enode_host-0.1.0/src/enode_host/backup/gui_comps.py +113 -0
  11. enode_host-0.1.0/src/enode_host/backup/gui_wx_bk.py +270 -0
  12. enode_host-0.1.0/src/enode_host/backup/load_file.py +27 -0
  13. enode_host-0.1.0/src/enode_host/backup/mesh.py +0 -0
  14. enode_host-0.1.0/src/enode_host/backup/mesh_bk.py +0 -0
  15. enode_host-0.1.0/src/enode_host/backup/s.py +151 -0
  16. enode_host-0.1.0/src/enode_host/backup/sandbox.py +93 -0
  17. enode_host-0.1.0/src/enode_host/backup/shm.py +262 -0
  18. enode_host-0.1.0/src/enode_host/backup/shmtools.py +70 -0
  19. enode_host-0.1.0/src/enode_host/backup/smarts.py +243 -0
  20. enode_host-0.1.0/src/enode_host/backup/test_wxpython_choice.py +49 -0
  21. enode_host-0.1.0/src/enode_host/backup/view-wing3.py +494 -0
  22. enode_host-0.1.0/src/enode_host/backup/wx_example.py +55 -0
  23. enode_host-0.1.0/src/enode_host/backup/wx_test01.py +43 -0
  24. enode_host-0.1.0/src/enode_host/cli.py +192 -0
  25. enode_host-0.1.0/src/enode_host/config.py +8 -0
  26. enode_host-0.1.0/src/enode_host/constants.py +25 -0
  27. enode_host-0.1.0/src/enode_host/framed_mesh.py +237 -0
  28. enode_host-0.1.0/src/enode_host/gui_framed.py +207 -0
  29. enode_host-0.1.0/src/enode_host/model.py +1415 -0
  30. enode_host-0.1.0/src/enode_host/protocol.py +311 -0
  31. enode_host-0.1.0/src/enode_host/psd_recursive.py +139 -0
  32. enode_host-0.1.0/src/enode_host/queues.py +11 -0
  33. enode_host-0.1.0/src/enode_host/resampling.py +206 -0
  34. enode_host-0.1.0/src/enode_host/shm_sigproc.py +47 -0
  35. enode_host-0.1.0/src/enode_host/storage.py +93 -0
  36. enode_host-0.1.0/src/enode_host/timestamping.py +79 -0
  37. enode_host-0.1.0/src/enode_host/types.py +38 -0
  38. enode_host-0.1.0/src/enode_host/view.py +1233 -0
  39. enode_host-0.1.0/src/enode_host.egg-info/PKG-INFO +81 -0
  40. enode_host-0.1.0/src/enode_host.egg-info/SOURCES.txt +42 -0
  41. enode_host-0.1.0/src/enode_host.egg-info/dependency_links.txt +1 -0
  42. enode_host-0.1.0/src/enode_host.egg-info/entry_points.txt +2 -0
  43. enode_host-0.1.0/src/enode_host.egg-info/requires.txt +3 -0
  44. enode_host-0.1.0/src/enode_host.egg-info/top_level.txt +1 -0
@@ -0,0 +1,81 @@
1
+ Metadata-Version: 2.4
2
+ Name: enode-host
3
+ Version: 0.1.0
4
+ Summary: Host-side tools that interact with the ESP-IDF firmware.
5
+ Author: eNode team
6
+ License: MIT
7
+ Requires-Python: >=3.10
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: PyQt5>=5.15
10
+ Requires-Dist: matplotlib>=3.8
11
+ Requires-Dist: pandas>=2.2
12
+
13
+ # Host Python Tools
14
+
15
+ This folder contains host-side Python code that interacts with the ESP-IDF
16
+ firmware (e.g., over serial, sockets, or file exchange). It is kept separate
17
+ from the firmware build to avoid mixing tool dependencies with ESP-IDF.
18
+
19
+ ## Quick start
20
+
21
+ ```bash
22
+ python -m venv .venv
23
+ source .venv/bin/activate
24
+ pip install -e .
25
+
26
+ enode-host --help
27
+ enode-host socket 127.0.0.1 3333 "hello"
28
+ enode-host server --port 3333 --interactive
29
+ enode-host gui --port 3333
30
+ ```
31
+
32
+ ## Notes
33
+
34
+ - Add runtime dependencies to `pyproject.toml` under `project.dependencies`.
35
+ - Keep device/transport details in small modules so they can be shared by
36
+ scripts and tests.
37
+ - The GUI uses wxPython; install it if you plan to run `enode-host gui`.
38
+
39
+ ## Protocol (TCP, length-prefixed)
40
+
41
+ Frame format: 1 byte message type, 2 bytes big-endian payload length, payload.
42
+
43
+ Message types:
44
+ - 0x10 COMMAND (host -> device)
45
+ - 0x20 STATUS (device -> host)
46
+ - 0x30 ACK (either direction)
47
+ - 0x40 DATA (device -> host, ACC batch)
48
+ - 0x41 PPS (device -> host, immediate PPS)
49
+
50
+ Commands (payload begins with command_id):
51
+ - 0x01 start_daq
52
+ - 0x02 stop_daq
53
+ - 0x03 set_mode (1 byte: 0 realtime, 1 past)
54
+ - 0x04 start_realtime_stream
55
+ - 0x05 stop_realtime_stream
56
+ - 0x06 start_past_stream (payload: 8-byte start_ms, 8-byte end_ms)
57
+ - 0x07 stop_past_stream
58
+
59
+ Status payload (16 bytes):
60
+ - node_type: uint8
61
+ - node_number: uint8
62
+ - level: uint8
63
+ - parent_mac: 6 bytes
64
+ - self_mac: 6 bytes
65
+ - rssi: int8
66
+
67
+ DATA payload:
68
+ - node_type: uint8
69
+ - node_number: uint8
70
+ - sample_count: uint8
71
+ - repeated samples (count):
72
+ - cc: uint64 (big-endian)
73
+ - acc_x: float32 (big-endian)
74
+ - acc_y: float32 (big-endian)
75
+ - acc_z: float32 (big-endian)
76
+
77
+ PPS payload:
78
+ - node_type: uint8
79
+ - node_number: uint8
80
+ - cc: uint64 (big-endian)
81
+ - epoch: int64 (big-endian)
@@ -0,0 +1,69 @@
1
+ # Host Python Tools
2
+
3
+ This folder contains host-side Python code that interacts with the ESP-IDF
4
+ firmware (e.g., over serial, sockets, or file exchange). It is kept separate
5
+ from the firmware build to avoid mixing tool dependencies with ESP-IDF.
6
+
7
+ ## Quick start
8
+
9
+ ```bash
10
+ python -m venv .venv
11
+ source .venv/bin/activate
12
+ pip install -e .
13
+
14
+ enode-host --help
15
+ enode-host socket 127.0.0.1 3333 "hello"
16
+ enode-host server --port 3333 --interactive
17
+ enode-host gui --port 3333
18
+ ```
19
+
20
+ ## Notes
21
+
22
+ - Add runtime dependencies to `pyproject.toml` under `project.dependencies`.
23
+ - Keep device/transport details in small modules so they can be shared by
24
+ scripts and tests.
25
+ - The GUI uses wxPython; install it if you plan to run `enode-host gui`.
26
+
27
+ ## Protocol (TCP, length-prefixed)
28
+
29
+ Frame format: 1 byte message type, 2 bytes big-endian payload length, payload.
30
+
31
+ Message types:
32
+ - 0x10 COMMAND (host -> device)
33
+ - 0x20 STATUS (device -> host)
34
+ - 0x30 ACK (either direction)
35
+ - 0x40 DATA (device -> host, ACC batch)
36
+ - 0x41 PPS (device -> host, immediate PPS)
37
+
38
+ Commands (payload begins with command_id):
39
+ - 0x01 start_daq
40
+ - 0x02 stop_daq
41
+ - 0x03 set_mode (1 byte: 0 realtime, 1 past)
42
+ - 0x04 start_realtime_stream
43
+ - 0x05 stop_realtime_stream
44
+ - 0x06 start_past_stream (payload: 8-byte start_ms, 8-byte end_ms)
45
+ - 0x07 stop_past_stream
46
+
47
+ Status payload (16 bytes):
48
+ - node_type: uint8
49
+ - node_number: uint8
50
+ - level: uint8
51
+ - parent_mac: 6 bytes
52
+ - self_mac: 6 bytes
53
+ - rssi: int8
54
+
55
+ DATA payload:
56
+ - node_type: uint8
57
+ - node_number: uint8
58
+ - sample_count: uint8
59
+ - repeated samples (count):
60
+ - cc: uint64 (big-endian)
61
+ - acc_x: float32 (big-endian)
62
+ - acc_y: float32 (big-endian)
63
+ - acc_z: float32 (big-endian)
64
+
65
+ PPS payload:
66
+ - node_type: uint8
67
+ - node_number: uint8
68
+ - cc: uint64 (big-endian)
69
+ - epoch: int64 (big-endian)
@@ -0,0 +1,25 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "enode-host"
7
+ version = "0.1.0"
8
+ description = "Host-side tools that interact with the ESP-IDF firmware."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = {text = "MIT"}
12
+ authors = [
13
+ {name = "eNode team"}
14
+ ]
15
+ dependencies = [
16
+ "PyQt5>=5.15",
17
+ "matplotlib>=3.8",
18
+ "pandas>=2.2",
19
+ ]
20
+
21
+ [project.scripts]
22
+ enode-host = "enode_host.cli:main"
23
+
24
+ [tool.setuptools.packages.find]
25
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1 @@
1
+ """Host-side utilities for interacting with the ESP-IDF firmware."""
@@ -0,0 +1,165 @@
1
+ import asyncio
2
+ import struct
3
+ from dataclasses import dataclass
4
+ from typing import Dict, Optional
5
+
6
+ from .protocol import (
7
+ MsgType,
8
+ build_ack,
9
+ format_mac,
10
+ parse_acc_batch,
11
+ parse_pps,
12
+ parse_sd_chunk,
13
+ parse_sd_done,
14
+ parse_status,
15
+ )
16
+
17
+
18
+ @dataclass
19
+ class SocketResponse:
20
+ payload: bytes
21
+
22
+
23
+ async def send_message(host: str, port: int, payload: bytes, timeout: float = 5.0) -> SocketResponse:
24
+ reader: asyncio.StreamReader
25
+ writer: asyncio.StreamWriter
26
+
27
+ try:
28
+ reader, writer = await asyncio.wait_for(
29
+ asyncio.open_connection(host, port), timeout=timeout
30
+ )
31
+ except asyncio.TimeoutError as exc:
32
+ raise TimeoutError(f"Timed out connecting to {host}:{port}") from exc
33
+
34
+ try:
35
+ writer.write(payload)
36
+ await writer.drain()
37
+ data = await asyncio.wait_for(reader.read(4096), timeout=timeout)
38
+ return SocketResponse(payload=data)
39
+ finally:
40
+ writer.close()
41
+ await writer.wait_closed()
42
+
43
+
44
+ def run_client(host: str, port: int, message: str, timeout: float) -> int:
45
+ payload = message.encode("utf-8")
46
+ response = asyncio.run(send_message(host, port, payload, timeout))
47
+ if response.payload:
48
+ print(response.payload.decode("utf-8", errors="replace"))
49
+ return 0
50
+
51
+
52
+ async def read_frame(reader: asyncio.StreamReader) -> Optional[tuple[int, bytes]]:
53
+ header = await reader.readexactly(3)
54
+ msg_type, length = struct.unpack(">BH", header)
55
+ if length == 0:
56
+ return msg_type, b""
57
+ payload = await reader.readexactly(length)
58
+ return msg_type, payload
59
+
60
+
61
+ async def handle_client(reader: asyncio.StreamReader, writer: asyncio.StreamWriter, clients: Dict[str, asyncio.StreamWriter]) -> None:
62
+ peer = writer.get_extra_info("peername")
63
+ peer_id = f"{peer[0]}:{peer[1]}" if peer else "unknown"
64
+ clients[peer_id] = writer
65
+ print(f"[server] connected {peer_id} (clients={len(clients)})")
66
+
67
+ try:
68
+ while True:
69
+ msg_type, payload = await read_frame(reader)
70
+ if msg_type == MsgType.STATUS:
71
+ status = parse_status(payload)
72
+ print(
73
+ "[status] "
74
+ f"node={status.node_type}:{status.node_number} "
75
+ f"level={status.level} "
76
+ f"parent={format_mac(status.parent_mac)} "
77
+ f"self={format_mac(status.self_mac)} "
78
+ f"rssi={status.rssi}"
79
+ )
80
+ writer.write(build_ack(MsgType.STATUS, 0, "ok"))
81
+ await writer.drain()
82
+ elif msg_type == MsgType.DATA:
83
+ batch = parse_acc_batch(payload)
84
+ print(f"[data] node={batch.node_type}:{batch.node_number} samples={len(batch.samples)}")
85
+ writer.write(build_ack(MsgType.DATA, 0, "ok"))
86
+ await writer.drain()
87
+ elif msg_type == MsgType.PPS:
88
+ pps = parse_pps(payload)
89
+ print(f"[pps] node={pps.node_type}:{pps.node_number} cc={pps.cc} epoch={pps.epoch}")
90
+ writer.write(build_ack(MsgType.PPS, 0, "ok"))
91
+ await writer.drain()
92
+ elif msg_type == MsgType.SD_STREAM:
93
+ chunk = parse_sd_chunk(payload)
94
+ print(
95
+ f"[sd] node={chunk.node_type}:{chunk.node_number} "
96
+ f"file_time={chunk.file_time} offset={chunk.offset} size={len(chunk.data)}"
97
+ )
98
+ writer.write(build_ack(MsgType.SD_STREAM, 0, "ok"))
99
+ await writer.drain()
100
+ elif msg_type == MsgType.SD_DONE:
101
+ done = parse_sd_done(payload)
102
+ print(
103
+ f"[sd] node={done.node_type}:{done.node_number} "
104
+ f"file_time={done.file_time} status={done.status}"
105
+ )
106
+ writer.write(build_ack(MsgType.SD_DONE, 0, "ok"))
107
+ await writer.drain()
108
+ else:
109
+ print(f"[server] msg_type=0x{msg_type:02X} len={len(payload)}")
110
+ writer.write(build_ack(msg_type, 0, "ok"))
111
+ await writer.drain()
112
+ except asyncio.IncompleteReadError:
113
+ pass
114
+ finally:
115
+ clients.pop(peer_id, None)
116
+ writer.close()
117
+ await writer.wait_closed()
118
+ print(f"[server] disconnected {peer_id} (clients={len(clients)})")
119
+
120
+
121
+ async def broadcast_messages(
122
+ queue: asyncio.Queue[bytes],
123
+ clients: Dict[str, asyncio.StreamWriter],
124
+ ) -> None:
125
+ while True:
126
+ payload = await queue.get()
127
+ if not clients:
128
+ print("[server] no clients to broadcast to")
129
+ continue
130
+ for peer_id, writer in list(clients.items()):
131
+ try:
132
+ writer.write(payload)
133
+ await writer.drain()
134
+ except ConnectionError:
135
+ clients.pop(peer_id, None)
136
+ print(f"[server] broadcast to {len(clients)} clients")
137
+
138
+
139
+ async def run_server(
140
+ host: str,
141
+ port: int,
142
+ on_connect_payload: Optional[bytes],
143
+ command_queue: Optional[asyncio.Queue[bytes]] = None,
144
+ ) -> None:
145
+ clients: Dict[str, asyncio.StreamWriter] = {}
146
+
147
+ async def _client_handler(reader: asyncio.StreamReader, writer: asyncio.StreamWriter) -> None:
148
+ if on_connect_payload:
149
+ writer.write(on_connect_payload)
150
+ await writer.drain()
151
+ await handle_client(reader, writer, clients)
152
+
153
+ server = await asyncio.start_server(_client_handler, host=host, port=port)
154
+ addrs = ", ".join(str(sock.getsockname()) for sock in server.sockets or [])
155
+ print(f"[server] listening on {addrs}")
156
+
157
+ async with server:
158
+ if command_queue is None:
159
+ await server.serve_forever()
160
+ else:
161
+ broadcaster = asyncio.create_task(broadcast_messages(command_queue, clients))
162
+ try:
163
+ await server.serve_forever()
164
+ finally:
165
+ broadcaster.cancel()
@@ -0,0 +1,226 @@
1
+ #!/usr/local/bin/python3
2
+
3
+ #----------------------------------------------
4
+ # NOTE
5
+ # 1. Ask Ki about the definition of local axes for M352, or see the line # 397 of model.py
6
+ # when you look at the screen of the node,
7
+ # the direction to the left hand-side is the X-axis
8
+ # the downward direction is the Y-axis
9
+ # the direction perpendicular to the screen and coming towards yourself is Z-axis
10
+ #
11
+ # this is the right-hand rule:
12
+ # the direction of you index finger is the x-axis,
13
+ # that of the middle finger is the y-axis
14
+ # that of the thumb is the z-axis
15
+ #
16
+ #---------------------------------------------
17
+ # HOW TO USE THE SYSTEM
18
+ #
19
+ # 1. please execute this file first, so that the server is ready to receive data from ndoes
20
+ # 2. turn on the node(s)
21
+ # - the PPS LED on the display can be believed
22
+ # - please don't believe RSSI, Lv, BAT %, as they are not completed yet.
23
+ # 3. Files are saved under data2 folder in HDF
24
+ # 4. Please read example.ipynb for how to load data file and display it
25
+ # - Please notice the time is in UTC to avoid any issues regarding British Summer Time
26
+ # 5. For time-sync, never reset the acc node, but power-cycle it.
27
+ # - there are two buttons on the sensor node:
28
+ # - one for power next to the USB-c port
29
+ # - the other for reset next to the SD slot
30
+ # - pressing the pwr button for 5 sec will shutdown the node, and pressing it for 1 sec will start the node
31
+
32
+
33
+
34
+ import wx
35
+ import view
36
+ import model
37
+ import importlib
38
+ importlib.reload(view)
39
+ importlib.reload(model)
40
+
41
+ import logging
42
+ import threading
43
+ import queues
44
+ from numpy import array
45
+ import shm_sigproc
46
+ import glob
47
+ import os
48
+ import esp_mesh
49
+ import pandas as pd
50
+ from model import CmdType, ChannelType
51
+ from enum import IntEnum
52
+
53
+ os.remove('log/my_log_file.log')
54
+
55
+ logging.basicConfig(level=logging.INFO, # Set the minimum log level
56
+ #format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
57
+ format='%(name)s - %(levelname)s - %(message)s',
58
+ handlers=[logging.FileHandler('log/my_log_file.log'), logging.StreamHandler()])
59
+ logger = logging.getLogger(__name__)
60
+
61
+
62
+ os.makedirs("raw-data", exist_ok = True)
63
+
64
+
65
+ class CMD_TYPE(IntEnum):
66
+ SET_MODE = 0
67
+ CLEAR_STORAGE = 1
68
+ NOTIFY_PARENT = 2
69
+ NOTIFY_CHILDREN = 3
70
+ SHUTDOWN = 4
71
+
72
+ class OPERATION_MODE(IntEnum):
73
+ ONLINE_DAQ = 0
74
+ STANDALONE_DATA_PEEKING = 1
75
+ POST_DAQ_DATA_STREAMING = 2
76
+ MAINTENANCE = 3
77
+
78
+ class Controller:
79
+
80
+ def __init__(self):
81
+
82
+ self.model = model.Model(self)
83
+ self.view = view.View(self)
84
+ self.view.Show()
85
+ self.mesh = esp_mesh.Esp_Mesh(self.model)
86
+
87
+ # mesh.begin()
88
+ # shm_sigproc.begin()
89
+
90
+ #
91
+ # BINDINGS
92
+ #
93
+
94
+ # node_num_txt
95
+ self.view.m_textCtrl2.Bind(wx.EVT_TEXT, self.on_change_node_nums)
96
+
97
+ # Menu File>Exit
98
+ self.view.Bind(wx.EVT_MENU, self.on_exit, self.view.m_menu_file_quit)
99
+
100
+ # Menu Data>Export
101
+ self.view.Bind(wx.EVT_MENU, self.on_data_export, self.view.m_menu_data_export)
102
+
103
+ # Menu CMD>SD clear
104
+ self.view.Bind(wx.EVT_MENU, self.on_cmd_sdclear, self.view.m_menu_cmd_sdclear)
105
+
106
+ # Menu CMD>Shutdown
107
+ self.view.Bind(wx.EVT_MENU, self.on_cmd_shutdown, self.view.m_menu_cmd_shutdown)
108
+
109
+ # Menu Tool>clf
110
+ self.view.Bind(wx.EVT_MENU, self.on_view_clf, self.view.m_menu_view_clf)
111
+
112
+ # Start DAQ Button
113
+ self.view.m_button1.Bind(wx.EVT_BUTTON, self.Start_Button_onclick)
114
+
115
+ # Stop DAQ Button
116
+ self.view.m_button2.Bind(wx.EVT_BUTTON, self.Stop_Button_onclick)
117
+
118
+ #
119
+ self.view.m_choice_OperationMode.Bind(wx.EVT_CHOICE, self.choice_OperationMode_onchange)
120
+
121
+ def on_change_node_nums(self, event):
122
+
123
+ self.model.options['node_nums_txt'] = self.view.m_textCtrl2.GetValue()
124
+ self.model.parse_node_nums_txt()
125
+ self.model.save_config()
126
+ self.model.init_mesh_status_data()
127
+ self.model.init_other_data()
128
+ self.view.mesh_status_data_view()
129
+ self.view.m_grid2.ForceRefresh()
130
+ # Init the time history and PSD plots
131
+ self.view.init_plot()
132
+
133
+ def on_exit(self, event):
134
+
135
+ self.view.Close()
136
+
137
+ def on_data_export(self, event):
138
+
139
+ self.model.export()
140
+
141
+ def Start_Button_onclick(self, event):
142
+
143
+ map = {
144
+ OPERATION_MODE.ONLINE_DAQ: 1,
145
+ OPERATION_MODE.STANDALONE_DATA_PEEKING: 5,
146
+ OPERATION_MODE.POST_DAQ_DATA_STREAMING: 7,
147
+ }
148
+ operation_Mode = self.view.m_choice_OperationMode.GetSelection()
149
+
150
+ self.model.init_other_data()
151
+ self.view.init_plot()
152
+ self.view.figure_update()
153
+ for inode in self.mesh.sockets.keys():
154
+ self.mesh.send_cmd(inode, CMD_TYPE.SET_MODE, data0 = map[operation_Mode])
155
+ self.model.update_mesh_status_data(inode, 'CMD', "sent")
156
+ self.view.table_update()
157
+ logger.info('command sent: {} start'.format(OPERATION_MODE(operation_Mode).name))
158
+
159
+ def Stop_Button_onclick(self, event):
160
+
161
+ map = {
162
+ OPERATION_MODE.ONLINE_DAQ: 0,
163
+ OPERATION_MODE.STANDALONE_DATA_PEEKING: 4,
164
+ OPERATION_MODE.POST_DAQ_DATA_STREAMING: 2,
165
+ }
166
+
167
+ operation_Mode = self.view.m_choice_OperationMode.GetSelection()
168
+
169
+ for inode in self.mesh.sockets.keys():
170
+ self.mesh.send_cmd(inode, CMD_TYPE.SET_MODE, data0 = map[operation_Mode])
171
+ self.model.update_mesh_status_data(inode, 'CMD', "sent")
172
+ self.view.table_update()
173
+
174
+ logger.info('command sent: {} stop'.format(OPERATION_MODE(operation_Mode).name))
175
+ # self.view.gui_update(1)
176
+
177
+ def choice_OperationMode_onchange(self, event):
178
+ operation_Mode = self.view.m_choice_OperationMode.GetSelection()
179
+ if operation_Mode == OPERATION_MODE.POST_DAQ_DATA_STREAMING:
180
+ for inode in self.mesh.sockets.keys():
181
+ self.mesh.send_cmd(inode, CMD_TYPE.SET_MODE, data0 = 2)
182
+ self.model.update_mesh_status_data(inode, 'CMD', "sent")
183
+ self.view.table_update()
184
+
185
+ if operation_Mode == OPERATION_MODE.ONLINE_DAQ:
186
+ self.PPS_outdate_check = True
187
+ else:
188
+ self.PPS_outdate_check = False
189
+
190
+
191
+ def on_view_clf(self, event):
192
+ self.model.init_other_data()
193
+ self.view.init_plot()
194
+ self.view.figure_update()
195
+ return
196
+
197
+ def on_cmd_sdclear(self, event):
198
+
199
+ for inode in self.mesh.sockets.keys():
200
+ self.mesh.send_cmd(inode, CMD_TYPE.CLEAR_STORAGE)
201
+ self.model.update_mesh_status_data(inode, 'CMD', "sent")
202
+ self.view.table_update()
203
+ logger.info('command sent: SD Clear sent')
204
+
205
+ def on_cmd_shutdown(self, event):
206
+
207
+ for inode in self.mesh.sockets.keys():
208
+ self.mesh.send_cmd(inode, CMD_TYPE.SHUTDOWN)
209
+ self.model.update_mesh_status_data(inode, 'CMD', "sent")
210
+ self.view.table_update()
211
+ logger.info('command sent: SD Clear sent')
212
+
213
+ return
214
+
215
+
216
+
217
+ if __name__ == '__main__':
218
+ app = wx.App()
219
+ controller = Controller()
220
+ # controller.view.gui_update(1)
221
+ app.MainLoop()
222
+
223
+
224
+
225
+
226
+