Compare commits
94 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0cd0fd7027 | |||
| fa8c219f76 | |||
| f233c019fd | |||
| ced466f3aa | |||
| f36906c034 | |||
| 0b5c62e525 | |||
| abe86238ca | |||
| f9ab0bc59b | |||
| 5dbe231c73 | |||
| c721950bf7 | |||
| 70c0271771 | |||
| 13825fe9ff | |||
| dd2e31d01f | |||
| 455fa1f86b | |||
| 71850b31a8 | |||
| 8d52fef4c1 | |||
| e091f220fa | |||
| 6049154fae | |||
| 3502472021 | |||
| 5e48c8ae0a | |||
| cb2a4c9d56 | |||
| b253aca73f | |||
| 2fd05d18ed | |||
| 03011ebd5f | |||
| 4b9bc30e28 | |||
| 4966113393 | |||
| 3371c21bbd | |||
| afc87829d9 | |||
| 952403cbf4 | |||
| 1cdd04901c | |||
| cd60e14cbe | |||
| ae55e6c789 | |||
| b8addb7686 | |||
| da581ae225 | |||
| a941f7c060 | |||
| 4b0472ecf4 | |||
| de51f53657 | |||
| 6974950d31 | |||
| 0887c48ddc | |||
| 184c7536a6 | |||
| 1a3a833680 | |||
| df3c7db8bc | |||
| 7287f4c19b | |||
| 7d3f7a47ff | |||
| 81c699e830 | |||
| 71e469ec2f | |||
| e4bef30be2 | |||
| 96ec0a983f | |||
| 2dd19a575f | |||
| affacfddeb | |||
| de8a6e58e4 | |||
| 390da7b004 | |||
| f8e41e9247 | |||
| 81ef9740c5 | |||
| 1d96f49f63 | |||
| 23a04d06c9 | |||
| 7c3bc2d20b | |||
| 01d1bd989c | |||
| 1dffa29658 | |||
| a0e8f9c6c4 | |||
| 9ad1f394be | |||
| 416503f7fb | |||
| d3af9e79bc | |||
| 4aa6634f1e | |||
| be36bb785c | |||
| 31b6a60046 | |||
| 12e0ec7c69 | |||
| 7087ded6d4 | |||
| cdb4ddfe04 | |||
| 9560b9e0ef | |||
| 8d68d15023 | |||
| 3ebf283c89 | |||
| a70d20c4b8 | |||
| 8be3e1fa0e | |||
| e33b4d9a21 | |||
| a38fe5066f | |||
| b6abf0885a | |||
| a3c0f1e4a3 | |||
| 6446204013 | |||
| 3b60d74c47 | |||
| d1c4b0a29f | |||
| 0034681e55 | |||
| 07a1e0f5bc | |||
| a96837a462 | |||
| 6b29f1f08e | |||
| 6b3649c8a0 | |||
| 3f1ba0971c | |||
| 95d27aa6f2 | |||
| 651e34d6e0 | |||
| d3621e0c9c | |||
| 0d1b1f4825 | |||
| ec0fe2ec9f | |||
| 67b645dac6 | |||
| b9dc607ac0 |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -18,9 +18,10 @@ class ControllerAPI():
|
||||
@staticmethod
|
||||
def getByMac(mac_address):
|
||||
try:
|
||||
ret = requests.get(API_URL + 'api/controller/get_by_mac/' + mac_address, headers= AuthAPI.get_key())
|
||||
if ret.status_code == 200:
|
||||
return ret.json()
|
||||
if mac_address != None:
|
||||
ret = requests.get(API_URL + 'api/controller/get_by_mac/' + mac_address, headers= AuthAPI.get_key())
|
||||
if ret.status_code == 200:
|
||||
return ret.json()
|
||||
except (requests.exceptions.ConnectionError, json.decoder.JSONDecodeError) as e:
|
||||
print('get controller fail', e)
|
||||
return []
|
||||
|
||||
@@ -1576,6 +1576,11 @@ class ControlAPI(metaclass=Router):
|
||||
should handle this exit code and re-run server process.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def run_project(self, project) -> bool:
|
||||
print('create_project', project)
|
||||
self._project_manager.create(project)
|
||||
return False
|
||||
|
||||
|
||||
# noinspection PyAbstractClass
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -315,14 +315,6 @@ class CC2650MasterDevice(MasterDevice, metaclass=abc.ABCMeta):
|
||||
|
||||
return cls.CC2650_RESET_PIN
|
||||
|
||||
@classmethod
|
||||
def get_uart_irq_pin(cls) -> OutputPin:
|
||||
if cls.CC2650_UART_IRQ is None:
|
||||
cls.CC2650_UART_IRQ = OutputPin.get_used(P3Pin.MEM_RST, initial=True)
|
||||
|
||||
return cls.CC2650_UART_IRQ
|
||||
|
||||
|
||||
class CC2650Device(Device):
|
||||
|
||||
def __init__(self,
|
||||
@@ -544,7 +536,7 @@ class CC2650Device(Device):
|
||||
self._master.log_warn('device', self.device_id, 'update_battery_info no response')
|
||||
|
||||
else:
|
||||
if data is not None and len(data) == 4 :
|
||||
if data is not None and len(data) > 2 :
|
||||
battery = struct.unpack('<H', data[1:3])[0]
|
||||
if battery is not None:
|
||||
self._battery = battery
|
||||
@@ -955,9 +947,6 @@ class CC2650SingleMasterDevice(CC2650MasterDevice, Synchronized):
|
||||
|
||||
self._cc2650.recv_util(..., when=self._cond, timeout=timeout)
|
||||
|
||||
def available_device(self) -> List[int]:
|
||||
return [0]
|
||||
|
||||
@synchronized
|
||||
def scan_callback(self, callback: Callable[[DeviceResponseInfo], None], timeout=5, all_device=False) -> bool:
|
||||
if self._scan_max_time != timeout:
|
||||
@@ -1442,11 +1431,6 @@ class CC2650MultiMasterDevice(CC2650MasterDevice, Synchronized):
|
||||
super().shutdown()
|
||||
self._selector.close()
|
||||
|
||||
def available_device(self) -> List[int]:
|
||||
return list(map(lambda it: it[0],
|
||||
filter(lambda it: it[1] is not None,
|
||||
enumerate(self._cc2650))))
|
||||
|
||||
def get_device(self, device: int) -> Optional[Device]:
|
||||
return self._device[device]
|
||||
|
||||
@@ -1942,10 +1926,8 @@ class CC2650SingleMasterCentralDevice(CC2650MasterDevice, Synchronized):
|
||||
self.log_verbose('reset (hardware)')
|
||||
|
||||
pin.output(False)
|
||||
sleep(0.1)
|
||||
|
||||
# sleep(0.001)
|
||||
pin.output(True)
|
||||
sleep(0.1)
|
||||
|
||||
@synchronized
|
||||
def reset_software(self):
|
||||
@@ -1968,9 +1950,6 @@ class CC2650SingleMasterCentralDevice(CC2650MasterDevice, Synchronized):
|
||||
"""initialize cc2650 (master)"""
|
||||
pass
|
||||
|
||||
def available_device(self) -> List[int]:
|
||||
return [0]
|
||||
|
||||
def scan_send_ins(self):
|
||||
# send scan command
|
||||
try:
|
||||
@@ -1986,21 +1965,16 @@ class CC2650SingleMasterCentralDevice(CC2650MasterDevice, Synchronized):
|
||||
clean_buf = self._cc2650.receive_timeout("20B", timeout=3)
|
||||
print("clean_buf = ", clean_buf)
|
||||
|
||||
def cc2650_uart_irq(self):
|
||||
uart_irq = self.get_uart_irq_pin()
|
||||
uart_irq.output(False)
|
||||
sleep(0.001)
|
||||
uart_irq.output(True)
|
||||
# def cc2650_uart_irq(self):
|
||||
# uart_irq = self.get_uart_irq_pin()
|
||||
# uart_irq.output(False)
|
||||
# sleep(0.001)
|
||||
# uart_irq.output(True)
|
||||
|
||||
@synchronized
|
||||
def scan_callback(self, callback: Callable[[DeviceResponseInfo], None], timeout=5, all_device=False) -> bool:
|
||||
# if self._scan_max_time != timeout:
|
||||
# self.log_info('set max scan limit time', timeout)
|
||||
# self._scan_max_time = timeout
|
||||
|
||||
self._found = found = []
|
||||
self._found_with_id = []
|
||||
number_of_device = 0
|
||||
hdr_BPHS = [66, 80, 72, 83]
|
||||
scan_response: Union[Optional[tuple], Any] = None
|
||||
|
||||
@@ -2013,39 +1987,13 @@ class CC2650SingleMasterCentralDevice(CC2650MasterDevice, Synchronized):
|
||||
# print('send_scan', bytes(scan_ins))
|
||||
self._cc2650.send("bytes", bytes(scan_ins))
|
||||
|
||||
# for wait_scan_response in range(5):
|
||||
# try:
|
||||
# scan_response = self._cc2650.recv_uart(0.2)
|
||||
# except RecvTimeout:
|
||||
# if wait_scan_response == 4:
|
||||
# self.reset_internal()
|
||||
# self.reset_hardware()
|
||||
# self._interface.flush()
|
||||
# return True
|
||||
# else:
|
||||
# self.log_info("wait for scan response")
|
||||
# continue
|
||||
|
||||
# # check if response is valid
|
||||
# if scan_response is None:
|
||||
# if wait_scan_response == 4:
|
||||
# self.reset_internal()
|
||||
# self.reset_hardware()
|
||||
# self._interface.flush()
|
||||
# else:
|
||||
# self.log_info("wait for scan response")
|
||||
# continue
|
||||
# else:
|
||||
# break
|
||||
|
||||
try:
|
||||
scan_response = self._cc2650.recv_uart(0.2)
|
||||
scan_response = self._cc2650.recv_uart(timeout)
|
||||
except RecvTimeout:
|
||||
self.reset_internal()
|
||||
self.reset_hardware()
|
||||
self._interface.flush()
|
||||
return True
|
||||
|
||||
# self.reset_internal()
|
||||
# self.reset_hardware()
|
||||
# self._interface.flush()
|
||||
return False
|
||||
|
||||
# instruction format:
|
||||
# ins[0]: get_scan_response = 0x04
|
||||
@@ -2087,6 +2035,7 @@ class CC2650SingleMasterCentralDevice(CC2650MasterDevice, Synchronized):
|
||||
# print("local_name = ", local_name)
|
||||
|
||||
# addr type is don't care in BMD380
|
||||
print('scan_response:', list(scan_response))
|
||||
local_addr_type = int(scan_response[index:index + 1][0])
|
||||
# local_addr_type = 0xFF
|
||||
index = index + 1
|
||||
@@ -2140,6 +2089,35 @@ class CC2650SingleMasterCentralDevice(CC2650MasterDevice, Synchronized):
|
||||
def found(self) -> List[DeviceResponseInfo]:
|
||||
return self._found
|
||||
|
||||
def check_mem_survive(self) -> Optional[CC2650Device]:
|
||||
ack = []
|
||||
ins = bytearray()
|
||||
ins.append(10)
|
||||
ins.append(1) #length
|
||||
ins.append(0xF1)
|
||||
# print('ins', list(ins))
|
||||
|
||||
try:
|
||||
self._cc2650.send("bytes", bytes(ins))
|
||||
|
||||
except SerialTimeoutException as e:
|
||||
raise RecvTimeout('device CC2650 check_mem_survive timeout') from e
|
||||
|
||||
else:
|
||||
try:
|
||||
ack = self._cc2650.recv_uart(0.001)
|
||||
|
||||
except RecvTimeout:
|
||||
self.log_info("no memory board")
|
||||
|
||||
# else:
|
||||
# print('ack=', ack)
|
||||
|
||||
if ack == [3]:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
@synchronized
|
||||
def connect(self, response: DeviceResponseInfo, direct_connect: bool = False) -> Optional[CC2650Device]:
|
||||
if self._handle is not None:
|
||||
@@ -2555,11 +2533,10 @@ class CC2650MultiMasterCentralDevice(CC2650MasterDevice, Synchronized):
|
||||
|
||||
if m is None:
|
||||
m = CC2650SingleMasterCentralDevice(self._master, self._interface, self._options)
|
||||
# m.set_log_level(self._cc2650_log_level)
|
||||
self._cc2650[i] = m
|
||||
|
||||
self._interface.flush()
|
||||
self._selector.select(i)
|
||||
# self._mem_selector.select(i)
|
||||
|
||||
try:
|
||||
self.log_info('reset device', i)
|
||||
@@ -2567,10 +2544,7 @@ class CC2650MultiMasterCentralDevice(CC2650MasterDevice, Synchronized):
|
||||
with m:
|
||||
m.reset_internal()
|
||||
m.reset_hardware()
|
||||
|
||||
if software_reset:
|
||||
m.reset_software()
|
||||
self._cc2650[i] = m
|
||||
m.reset_software()
|
||||
|
||||
except RecvTimeout:
|
||||
self.log_warn('reset device', i, 'fail')
|
||||
@@ -2579,83 +2553,11 @@ class CC2650MultiMasterCentralDevice(CC2650MasterDevice, Synchronized):
|
||||
if not software_reset:
|
||||
return
|
||||
|
||||
# check reset result
|
||||
available_device_id = list(map(lambda it: it[0],
|
||||
filter(lambda it: it[1] is not None,
|
||||
enumerate(self._cc2650))))
|
||||
|
||||
if len(available_device_id) == 0:
|
||||
raise RuntimeError("reset fail, no device found")
|
||||
|
||||
self.log_verbose('available device', ' '.join(map(str, available_device_id)))
|
||||
|
||||
# initial hardware
|
||||
for i in range(len(self._cc2650)):
|
||||
m = self._cc2650[i]
|
||||
|
||||
if m is not None:
|
||||
self._interface.flush()
|
||||
self._selector.select(i)
|
||||
# self._mem_selector.select(i)
|
||||
|
||||
try:
|
||||
self.log_info('init device', i)
|
||||
|
||||
except RecvTimeout:
|
||||
self.log_warn('init device', i, 'fail')
|
||||
self._cc2650[i] = None
|
||||
|
||||
# check init result, again
|
||||
available_device_id = list(map(lambda it: it[0],
|
||||
filter(lambda it: it[1] is not None,
|
||||
enumerate(self._cc2650))))
|
||||
|
||||
if len(available_device_id) == 0:
|
||||
raise RuntimeError("init fail, no device success")
|
||||
|
||||
def reset_empty_master(self, device: Optional[List[int]] = None, software_reset=True):
|
||||
self.log_verbose('reset')
|
||||
|
||||
# reset hardware
|
||||
# print("reset device = ", device)
|
||||
for i in range(len(self._cc2650)):
|
||||
# print(i)
|
||||
|
||||
m = self._cc2650[i]
|
||||
d = self._device[i]
|
||||
|
||||
# print(m, d)
|
||||
|
||||
if m is not None and d is None:
|
||||
m = CC2650SingleMasterCentralDevice(self._master, self._interface, self._options)
|
||||
# m.set_log_level(self._cc2650_log_level)
|
||||
|
||||
self._interface.flush()
|
||||
self._selector.select(i)
|
||||
self._mem_selector.select(i)
|
||||
|
||||
try:
|
||||
self.log_info('reset device', i)
|
||||
|
||||
with m:
|
||||
m.reset_internal()
|
||||
m.reset_hardware()
|
||||
|
||||
except RecvTimeout:
|
||||
self.log_warn('reset device', i, 'fail')
|
||||
self._cc2650[i] = None
|
||||
|
||||
def available_device(self) -> List[int]:
|
||||
return list(map(lambda it: it[0],
|
||||
filter(lambda it: it[1] is not None,
|
||||
enumerate(self._cc2650))))
|
||||
|
||||
def _foreach_empty_master(self) -> Iterable[int]:
|
||||
for i in range(len(self._cc2650)):
|
||||
m = self._cc2650[i]
|
||||
for i in range(len(self._device)):
|
||||
d = self._device[i]
|
||||
|
||||
if m is not None and d is None:
|
||||
if d is None:
|
||||
yield i
|
||||
|
||||
def scan_callback(self, callback: Callable[[DeviceResponseInfo], None], timeout=5, all_device=False) -> bool:
|
||||
@@ -2663,28 +2565,35 @@ class CC2650MultiMasterCentralDevice(CC2650MasterDevice, Synchronized):
|
||||
|
||||
all_result = False
|
||||
|
||||
for device in self._foreach_empty_master():
|
||||
for device in range(len(self._cc2650)):
|
||||
self.log_verbose('use', device)
|
||||
|
||||
m = self._cc2650[device]
|
||||
d = self._device[device]
|
||||
|
||||
if m is not None and d is None:
|
||||
if d is None:
|
||||
error = None
|
||||
|
||||
with self:
|
||||
self._interface.flush()
|
||||
self._selector.select(device)
|
||||
# self._mem_selector.select(device)
|
||||
|
||||
try:
|
||||
sleep(0.0001)
|
||||
result = m.scan_callback(callback, timeout=timeout)
|
||||
if m.check_mem_survive() == False:
|
||||
continue
|
||||
|
||||
result = m.scan_callback(callback, timeout=0.001)
|
||||
|
||||
except RuntimeError as e:
|
||||
error = e
|
||||
|
||||
else:
|
||||
|
||||
if result == False:
|
||||
result = True
|
||||
all_result = all_result or result
|
||||
continue
|
||||
|
||||
all_result = all_result or result
|
||||
|
||||
if result and not all_device:
|
||||
@@ -2692,8 +2601,7 @@ class CC2650MultiMasterCentralDevice(CC2650MasterDevice, Synchronized):
|
||||
|
||||
if error is not None:
|
||||
self.log_warn('suppressed error : ' + str(error))
|
||||
# self.reset(device)
|
||||
sleep(1)
|
||||
|
||||
return all_result
|
||||
|
||||
def found(self) -> List[DeviceResponseInfo]:
|
||||
@@ -2746,7 +2654,6 @@ class CC2650MultiMasterCentralDevice(CC2650MasterDevice, Synchronized):
|
||||
with self:
|
||||
self._interface.flush()
|
||||
self._selector.select(master)
|
||||
# self._mem_selector.select(device)
|
||||
|
||||
sleep(0.0001)
|
||||
d = m.connect(response, direct_connect)
|
||||
|
||||
@@ -253,6 +253,7 @@ class DeviceInternalCommandHandler:
|
||||
return True
|
||||
|
||||
|
||||
# why inherit MasterDevice ?
|
||||
class DeviceManager(MasterDevice, Synchronized):
|
||||
"""device manager. It manager the device libraries, found device, connected device
|
||||
and the control of the master device.
|
||||
@@ -267,7 +268,6 @@ class DeviceManager(MasterDevice, Synchronized):
|
||||
options: DeviceManagerOptions,
|
||||
handler: Optional[DeviceInternalCommandHandler] = None):
|
||||
"""
|
||||
|
||||
:param options: manager options.
|
||||
:param handler: device internal command handler
|
||||
"""
|
||||
@@ -277,6 +277,7 @@ class DeviceManager(MasterDevice, Synchronized):
|
||||
if handler is None:
|
||||
handler = DeviceInternalCommandHandler()
|
||||
|
||||
# control server api
|
||||
self._handler: DeviceInternalCommandHandler = handler
|
||||
self._options: DeviceManagerOptions = options
|
||||
|
||||
@@ -286,7 +287,9 @@ class DeviceManager(MasterDevice, Synchronized):
|
||||
# hardware
|
||||
self._interface = options.interface
|
||||
self._master: Optional[MasterDevice] = None
|
||||
# memory board
|
||||
self._centralMaster: Optional[MasterDevice] = None
|
||||
# connected device
|
||||
self._device: List[CompletedDevice] = []
|
||||
|
||||
# demo device
|
||||
@@ -336,6 +339,10 @@ class DeviceManager(MasterDevice, Synchronized):
|
||||
def library_path(self) -> List[Path]:
|
||||
return self._repository.library_path
|
||||
|
||||
def get_device_status(self, mac_address) -> Optional[DeviceLibrary]:
|
||||
device = self.get_device(mac_address)
|
||||
return device.status
|
||||
|
||||
@logging_info
|
||||
def reload_library(self):
|
||||
"""reload device library"""
|
||||
@@ -383,9 +390,6 @@ class DeviceManager(MasterDevice, Synchronized):
|
||||
self._demo.clear()
|
||||
self._centralMaster.reset(device, software_reset)
|
||||
|
||||
def available_device(self) -> List[int]:
|
||||
return self._centralMaster.available_device()
|
||||
|
||||
@logging_info
|
||||
def shutdown(self, release_resource=True):
|
||||
# shutdown reset memeryboard
|
||||
@@ -577,7 +581,7 @@ class DeviceManager(MasterDevice, Synchronized):
|
||||
|
||||
elif isinstance(device, str):
|
||||
for slave in self._device:
|
||||
if ':'.join(format(b, 'x') for b in slave.mac_address) == device:
|
||||
if ':'.join('{:02x}'.format(b) for b in slave.mac_address) == device.lower():
|
||||
return slave
|
||||
|
||||
elif isinstance(device, DeviceInfo):
|
||||
@@ -1026,15 +1030,9 @@ class DeviceManager(MasterDevice, Synchronized):
|
||||
raise RuntimeError(DEVICE_NOT_FOUND, device)
|
||||
|
||||
if DeviceCommonInstruction(instruction) is not None:
|
||||
# print('deviceCommonInstr')
|
||||
# print(instruction)
|
||||
device.call_instruction(instruction)
|
||||
|
||||
elif instruction in device.library.instruction_table:
|
||||
# print('instruction')
|
||||
# print(instruction)
|
||||
device.call_instruction(instruction)
|
||||
|
||||
else:
|
||||
raise RuntimeError(INSTRUCTION_UNKNOWN, instruction)
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -882,19 +882,18 @@ class I4V4Z4T4DataDecoder(RecDataDecoder):
|
||||
if len(data) < 18:
|
||||
return None
|
||||
|
||||
current = struct.unpack('>i', data[1:5])[0] # unit: 1/1000 nA
|
||||
voltage = struct.unpack('>i', data[5:9])[0] # unit: mV
|
||||
impedance = struct.unpack('>i', data[9:13])[0] # unit: kOm
|
||||
time_stamp: float = struct.unpack('<I', data[13:17])[0] # unit: ms
|
||||
cycle_number = struct.unpack('>H', data[17:19])[0]
|
||||
finish_mode_falg = data[19]
|
||||
mem_cnt = data[1]
|
||||
time_stamp: float = struct.unpack('<I', data[4:8])[0] # unit: ms 0x18030000
|
||||
current = struct.unpack('<i', data[8:12])[0] # unit: nA
|
||||
voltage = struct.unpack('<i', data[12:16])[0] # unit: uV
|
||||
impedance = struct.unpack('<i', data[16:20])[0] # unit: mOm
|
||||
cycle_number = struct.unpack('<H', data[20:22])[0]
|
||||
finish_mode_falg = data[22]
|
||||
battery = struct.unpack('<i', data[23:27])[0]
|
||||
elite_notify_times = data[27]
|
||||
|
||||
# print('decode', list(data[20:]))
|
||||
mem_wrong = data[20]
|
||||
mem_retry_cnt = data[21]
|
||||
mem_green_wrong = data[22]
|
||||
mem_green_retry_cnt = data[23]
|
||||
ram_num = data[24]
|
||||
mem_wrong_information = struct.unpack('<i', data[43:47])[0] # mem_wrong_information = green retry, green wrong, red retry, red wrong
|
||||
ram_num = data[47]
|
||||
broken_flag = data[-1]
|
||||
|
||||
if (finish_mode_falg & 0b11110000 == 0b10100000):
|
||||
@@ -915,10 +914,13 @@ class I4V4Z4T4DataDecoder(RecDataDecoder):
|
||||
print("error timeStamp full data:", list(data), datetime.now(), '\n')
|
||||
return None
|
||||
else:
|
||||
# print('|', time_stamp, '|', delta, '|', current, '|', voltage, '|', impedance,
|
||||
# print('|', time_stamp, '|', delta, '|', int(time_stamp * 1000 / 2),
|
||||
# '|', current, '|', voltage, '|', impedance,
|
||||
# '|', cycle_number, '|', finishMode, '@', str(self.device))
|
||||
|
||||
# print('|', '{:10}'.format(time_stamp),
|
||||
# '|', '{:10}'.format(delta),
|
||||
# '|', '{:4}'.format(delta),
|
||||
# '|', '{:10}'.format(int(time_stamp * 1000 / 2)),
|
||||
# '|', '{:10}'.format(current),
|
||||
# '|', '{:10}'.format(voltage),
|
||||
# '|', '{:10}'.format(impedance),
|
||||
@@ -926,12 +928,9 @@ class I4V4Z4T4DataDecoder(RecDataDecoder):
|
||||
# '|', '{:1}'.format(finishMode),
|
||||
# '@', str(self.device), '|')
|
||||
|
||||
# print('|', '{:5}'.format(mem_wrong),
|
||||
# '|', '{:5}'.format(mem_retry_cnt),
|
||||
# '|', '{:5}'.format(mem_green_wrong),
|
||||
# '|', '{:5}'.format(mem_green_retry_cnt),
|
||||
# '|', '{:5}'.format(ram_num),
|
||||
# '|', '{:5}'.format(broken_flag),
|
||||
# print('|', '{:5}'.format(mem_wrong_information),
|
||||
# '|', '{:2}'.format(ram_num),
|
||||
# '|', '{:2}'.format(broken_flag),
|
||||
# '@', str(self.device), '|')
|
||||
pass
|
||||
|
||||
@@ -946,14 +945,20 @@ class I4V4Z4T4DataDecoder(RecDataDecoder):
|
||||
ret.append_data(1, voltage)
|
||||
ret.append_data(2, impedance)
|
||||
ret.append_data(3, cycle_number)
|
||||
ret.append_data(4, battery)
|
||||
ret.append_data(5, elite_notify_times)
|
||||
ret.append_data(6, mem_cnt)
|
||||
|
||||
# memoryboard information
|
||||
ret.append_data(4, mem_wrong)
|
||||
ret.append_data(5, mem_retry_cnt)
|
||||
ret.append_data(6, mem_green_wrong)
|
||||
ret.append_data(7, mem_green_retry_cnt)
|
||||
ret.append_data(8, ram_num)
|
||||
ret.append_data(9, broken_flag)
|
||||
ret.append_data(7, ram_num)
|
||||
ret.append_data(8, broken_flag)
|
||||
try:
|
||||
ret.append_data(9, mem_wrong_information)
|
||||
# print('append_data success, mem_wrong_information:', mem_wrong_information, hex(mem_wrong_information))
|
||||
except:
|
||||
print('append_data fail, mem_wrong_information:', mem_wrong_information, hex(mem_wrong_information))
|
||||
|
||||
|
||||
|
||||
if cycle_number != self._cycle_number:
|
||||
# notify cycle_number change
|
||||
@@ -1451,12 +1456,12 @@ class EISZeroOneDataDecoder(RecDataDecoder):
|
||||
if len(data) < 18:
|
||||
return None
|
||||
|
||||
ch1 = struct.unpack('>i', data[1:5])[0] # unit: 1/1000 nA
|
||||
ch2 = struct.unpack('>i', data[5:9])[0] # unit: mV
|
||||
ch3 = struct.unpack('>i', data[9:13])[0] # unit: kOm
|
||||
time_stamp: float = struct.unpack('<I', data[13:17])[0] # unit: ms
|
||||
cycle_number = struct.unpack('>H', data[17:19])[0]
|
||||
d19 = data[19]
|
||||
ch1 = struct.unpack('>i', data[1+3:5+3])[0] # unit: 1/1000 nA
|
||||
ch2 = struct.unpack('>i', data[5+3:9+3])[0] # unit: mV
|
||||
ch3 = struct.unpack('>i', data[9+3:13+3])[0] # unit: kOm
|
||||
time_stamp: float = struct.unpack('<I', data[13+3:17+3])[0] # unit: ms
|
||||
cycle_number = struct.unpack('>H', data[17+3:19+3])[0]
|
||||
d19 = data[19+3]
|
||||
gain = (d19 & 0x0F)
|
||||
finishMode = (d19 & 0x80) >> 7
|
||||
|
||||
|
||||
@@ -963,10 +963,6 @@ class MasterDevice(LoggerFlag, metaclass=abc.ABCMeta):
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def available_device(self) -> List[int]:
|
||||
pass
|
||||
|
||||
def scan(self, timeout=5, all_device=False) -> List[DeviceResponseInfo]:
|
||||
"""scan the nearby device.
|
||||
|
||||
@@ -1101,9 +1097,6 @@ class NullMasterDevice(MasterDevice):
|
||||
def shutdown(self, release_resource=True):
|
||||
pass
|
||||
|
||||
def available_device(self) -> List[int]:
|
||||
return []
|
||||
|
||||
def scan(self, timeout=5, all_device=False) -> List[DeviceResponseInfo]:
|
||||
return []
|
||||
|
||||
|
||||
@@ -1268,14 +1268,15 @@ class InstructionTable(DictNode['Instruction']):
|
||||
instruction: str):
|
||||
"""call instruction. chain context with :class:`DeviceInternalInstructionScope`
|
||||
|
||||
:param master: master device
|
||||
:param device: device
|
||||
:param master: DeviceManager
|
||||
:param device: CompletedDevice
|
||||
:param context: scope
|
||||
:param instruction: instruction name
|
||||
:raises InstructionNotFound: If instruction not found.
|
||||
"""
|
||||
|
||||
try:
|
||||
# ex. start
|
||||
ins = self[instruction]
|
||||
|
||||
except KeyError as e:
|
||||
@@ -1284,6 +1285,7 @@ class InstructionTable(DictNode['Instruction']):
|
||||
else:
|
||||
context = context.chain(InstructionTableScope(self))
|
||||
|
||||
# ex. _data_format, _sync, _notify
|
||||
for single in ins.eval_instruction(context):
|
||||
if isinstance(single, InternalInstruction):
|
||||
if not single.handle_internal_instruction(master, device, context):
|
||||
|
||||
@@ -966,7 +966,7 @@ class CompletedDevice(Device):
|
||||
"""
|
||||
__slots__ = ('_master', '_device_id', '_device', '_library', '_context',
|
||||
'_parameter', '_configuration', '_lock', '_feature_mask',
|
||||
'_cache_battery', '_cache_battery_timestamp', '_coeff')
|
||||
'_cache_battery', '_cache_battery_timestamp', '_coeff', '_status')
|
||||
|
||||
def __init__(self, master: MasterDevice, library: DeviceLibrary, device_id: int, device: Device):
|
||||
"""
|
||||
@@ -976,11 +976,15 @@ class CompletedDevice(Device):
|
||||
:param device_id: device id
|
||||
:param device: slave device implementation
|
||||
"""
|
||||
# DeviceManager
|
||||
self._master = master
|
||||
self._device = device
|
||||
self._device_id = device_id
|
||||
self._library = library
|
||||
|
||||
# device status ( 0: idle, 1: working, 2: error, 3: power off)
|
||||
self._status = 0
|
||||
|
||||
# context
|
||||
s1 = library.constant
|
||||
s2 = DeviceScope(self)
|
||||
@@ -1020,6 +1024,10 @@ class CompletedDevice(Device):
|
||||
def mac_address(self) -> ADDRESS:
|
||||
return self._device.mac_address
|
||||
|
||||
@property
|
||||
def mac_address_in_str(self) -> str:
|
||||
return ':'.join('{:02x}'.format(b) for b in self._device.mac_address)
|
||||
|
||||
@property
|
||||
def device(self) -> Device:
|
||||
return self._device
|
||||
@@ -1056,11 +1064,18 @@ class CompletedDevice(Device):
|
||||
return self._library
|
||||
|
||||
# device lock
|
||||
|
||||
@property
|
||||
def lock(self) -> DeviceLock:
|
||||
return self._lock
|
||||
|
||||
@property
|
||||
def status(self) -> int:
|
||||
return self._status
|
||||
|
||||
@status.setter
|
||||
def status(self, new_status):
|
||||
self._status = new_status
|
||||
|
||||
# device parameter getter/setter
|
||||
|
||||
def parameters(self) -> List[str]:
|
||||
@@ -1082,6 +1097,11 @@ class CompletedDevice(Device):
|
||||
:return: parameter V value
|
||||
"""
|
||||
return self._configuration.get_parameter(name, False)
|
||||
|
||||
def set_multi_parameters(self, parameter):
|
||||
for (name, value) in parameter[0].items():
|
||||
if name != 'target':
|
||||
self.set_parameter(name, value)
|
||||
|
||||
def set_parameter(self, name: str, value: Union[int, str]):
|
||||
"""replace parameter value with *value*
|
||||
@@ -1256,6 +1276,7 @@ class CompletedDevice(Device):
|
||||
'device_id': self.device_id,
|
||||
'device_name': self.device_name,
|
||||
'device_address': list(self.mac_address),
|
||||
'device_status': self._status,
|
||||
'battery': self.battery,
|
||||
'parent': self.parent,
|
||||
'recording_file_name': self.recording_file_name,
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -3720,12 +3720,9 @@ class CC2650Central(LoggerFlag):
|
||||
if ret is not None and len(ret) > 0:
|
||||
return ret
|
||||
|
||||
elif _time() - start > 1:
|
||||
elif _time() - start > 0.01: # read timeout
|
||||
return None
|
||||
|
||||
else:
|
||||
sleep(0.01)
|
||||
|
||||
def _recv_event(self, timeout: Optional[float] = 1) -> Optional[list]:
|
||||
code = self._recv_byte()
|
||||
# print("code = ", code)
|
||||
|
||||
+200
-381
@@ -16,8 +16,6 @@ MEM_REG_READ = 0x05
|
||||
DEFAULT_REGISTER_VALUE = 0b0100_0011 # 67
|
||||
MEM_SIZE = 0x1000
|
||||
|
||||
_RUNTIME_COMPILE = False
|
||||
|
||||
_SLEEP_TIME_ = 0.001
|
||||
|
||||
|
||||
@@ -25,73 +23,96 @@ _SLEEP_TIME_ = 0.001
|
||||
def zero_buffer(size: int) -> List[int]:
|
||||
return [0] * size
|
||||
|
||||
class MultiExtMemSpiInterface(LowLevelHardwareInterface):
|
||||
MEM_INS_MARKED1 = [MEM_INS_WRITE, 0, 2, 0x5A, 0xA5]
|
||||
MEM_INS_MARKED2 = [MEM_INS_WRITE, 0, 6, 0x5A, 0xA5]
|
||||
MEM_INS_MARKED3 = [MEM_INS_WRITE, 0, 10, 0x5A, 0xA5]
|
||||
# MEM_INS_RESET = [MEM_INS_WRITE, 0, 2, 1, 1, 0, 0xFF]
|
||||
|
||||
class ExtMemSpiInterface(LowLevelHardwareInterface):
|
||||
MEM_INS_MARKED = [MEM_INS_WRITE, 0, 2, 1, 1]
|
||||
MEM_INS_RESET = [MEM_INS_WRITE, 0, 2, 1, 1, 0, 0xFF]
|
||||
|
||||
__slots__ = ('_spi', '_tx_buffer', '_tx_buffer_header', '_tx_buffer_data',
|
||||
'pin_busy', 'pin_request', 'pin_reset', 'pin_sel',
|
||||
__slots__ = ('_selector', '_wait_for_first_data', '_spi', '_tx_buffer_header', '_tx_buffer_data',
|
||||
'pin_busy', 'pin_mem_req', 'pin_mem_sel', 'pin_ram_sel',
|
||||
'_pin_sel_val',
|
||||
'_pin_ram_sel_value', '_pin_mem_sel_value', '_pin_mem_req_value',
|
||||
'_read_green_times','_read_red_times',
|
||||
'_elite_data_len', '_mem_header_len', '_mem_tailer_len', '_single_data_len',
|
||||
'_head_wrong_cnt')
|
||||
|
||||
def __init__(self, device: Tuple[int, int] = None):
|
||||
super().__init__()
|
||||
self._spi = HardwareImplSpiInterface(device,
|
||||
spi_speed=12_000_000 # XXX temp parameter
|
||||
)
|
||||
def __init__(self,
|
||||
select: Selector,
|
||||
device: Tuple[int, int] = None):
|
||||
|
||||
self._elite_data_len = 20
|
||||
self._spi = HardwareImplSpiInterface(device,
|
||||
spi_speed=12_000_000)
|
||||
|
||||
self._elite_data_len = 40
|
||||
self._mem_header_len = 3
|
||||
self._mem_tailer_len = 8
|
||||
self._mem_tailer_len = 6
|
||||
self._single_data_len = self._elite_data_len + self._mem_header_len + self._mem_tailer_len
|
||||
|
||||
# buffer
|
||||
self._tx_buffer = [0] * 512
|
||||
self._tx_buffer_header = [0] * 11
|
||||
self._tx_buffer_header = [0] * 19
|
||||
self._tx_buffer_data = [0] * (self._single_data_len * 10 + 3)
|
||||
|
||||
# memory control pin
|
||||
self.pin_busy = OutputPin.get_used(P3Pin.MEM_BZY, True)
|
||||
self.pin_request = OutputPin.get_used(P3Pin.MEM_REQ, True)
|
||||
self.pin_reset = OutputPin.get_used(P3Pin.MEM_RST, True)
|
||||
self.pin_sel: Optional[InputPin] = InputPin.get_used(P3Pin.MEM_SEL)
|
||||
self.pin_mem_req = OutputPin.get_used(P3Pin.MEM_REQ, False)
|
||||
self.pin_mem_sel = OutputPin.get_used(P3Pin.MEM_RST, True) # MEM_RST -> actually which memory board is assign
|
||||
self.pin_ram_sel: Optional[InputPin] = InputPin.get_used(P3Pin.MEM_SEL) # MEM_SEL -> actually is RAM_SEL, which RAM is assign
|
||||
|
||||
self._pin_sel_val = False
|
||||
self._pin_ram_sel_value = [bool(self.pin_ram_sel) for _ in range(Selector.SIZE)]
|
||||
self._pin_mem_sel_value = [bool(self.pin_mem_sel) for _ in range(Selector.SIZE)]
|
||||
self._pin_mem_req_value = [bool(self.pin_mem_req) for _ in range(Selector.SIZE)]
|
||||
|
||||
self._read_green_times = 0
|
||||
self._read_red_times = 0
|
||||
|
||||
self._head_wrong_cnt = [0, 0, 0, 0, 0, 0, 0, 0]
|
||||
|
||||
def reset(self):
|
||||
self._spi.reset()
|
||||
|
||||
def close(self):
|
||||
self._spi.close()
|
||||
self._selector = select
|
||||
|
||||
def flush(self):
|
||||
self.pin_reset.output(False)
|
||||
self.pin_reset.output(True)
|
||||
self._pin_sel_val = [False for _ in range(Selector.SIZE)]
|
||||
self._wait_for_first_data = [True for _ in range(Selector.SIZE)]
|
||||
|
||||
def set_pin_mem_req(self, value: bool):
|
||||
channel = self.select
|
||||
self.pin_mem_req.output(value)
|
||||
self._pin_mem_req_value[channel] = value
|
||||
|
||||
def set_pin_mem_sel(self, value: bool):
|
||||
channel = self.select
|
||||
self.pin_mem_sel.output(value)
|
||||
self._pin_mem_sel_value[channel] = value
|
||||
|
||||
def get_pin_mem_req(self):
|
||||
channel = self.select
|
||||
return self._pin_mem_req_value[channel]
|
||||
|
||||
def get_pin_ram_sel(self):
|
||||
channel = self.select
|
||||
if self.pin_ram_sel.input() == 0:
|
||||
self._pin_ram_sel_value[channel] = False
|
||||
else:
|
||||
self._pin_ram_sel_value[channel] = True
|
||||
return self._pin_ram_sel_value[channel]
|
||||
|
||||
@property
|
||||
def select(self) -> int:
|
||||
return 0
|
||||
return self._selector.channel
|
||||
|
||||
@select.setter
|
||||
def select(self, value: int):
|
||||
self._selector.select(value)
|
||||
|
||||
def reset(self):
|
||||
self._spi.reset()
|
||||
|
||||
def flush(self):
|
||||
pass
|
||||
|
||||
def changed(self, flip=False) -> bool:
|
||||
old = self._pin_sel_val
|
||||
value = self.pin_sel.input()
|
||||
|
||||
if flip:
|
||||
self._pin_sel_val = value
|
||||
|
||||
return value != old
|
||||
def close(self):
|
||||
self._selector.close()
|
||||
self._spi.close()
|
||||
|
||||
def send_byte(self, data: bytes):
|
||||
raise RuntimeError()
|
||||
@@ -99,25 +120,18 @@ class ExtMemSpiInterface(LowLevelHardwareInterface):
|
||||
def recv_byte(self, size: int) -> Optional[bytes]:
|
||||
raise RuntimeError()
|
||||
|
||||
def request_data(self):
|
||||
self.pin_request.output(False)
|
||||
sleep(0.001)
|
||||
def foreach(self) -> Iterable[int]:
|
||||
for channel in self._selector.foreach():
|
||||
yield channel
|
||||
|
||||
# count = 0
|
||||
# for i in range(300):
|
||||
# count = count + 1
|
||||
def set_wait_flag(self, spi_idx:int = None, value:bool = None):
|
||||
self._wait_for_first_data[spi_idx] = value
|
||||
|
||||
self.pin_request.output(True)
|
||||
|
||||
# sleep(0.001) -> 1.2ms
|
||||
# no sleep -> 5us ~ 12us (central can't receive)
|
||||
|
||||
# for i in range
|
||||
# (1000) -> 500us ~ 1ms
|
||||
# (500) -> 200us ~ 500us
|
||||
# (300) -> 120us ~ 270us (seldom)
|
||||
# (200) -> 70us ~ 160us (skip req about every 64 time) x
|
||||
# (100) -> 40us ~ 100us (skip req sometimes) x
|
||||
def get_wait_flag(self, spi_idx:int = None) -> Optional[bool]:
|
||||
if spi_idx < Selector.SIZE:
|
||||
return self._wait_for_first_data[spi_idx]
|
||||
else:
|
||||
return None
|
||||
|
||||
def compare_green_data(self, data_first: Union[bytes, List[int]], data_second: Union[bytes, List[int]], data_third: Union[bytes, List[int]], length: int):
|
||||
data = []
|
||||
@@ -153,6 +167,52 @@ class ExtMemSpiInterface(LowLevelHardwareInterface):
|
||||
print("read red data times", self._read_red_times)
|
||||
return data
|
||||
|
||||
def _compare_green_data_addr_and_flag(self, data: Union[bytes, List[int]], device: int):
|
||||
|
||||
green_data_section1 = data[3:7]
|
||||
green_data_section2 = data[7:11]
|
||||
green_data_section3 = data[11:15]
|
||||
green_data_section = []
|
||||
|
||||
if green_data_section1 == green_data_section2:
|
||||
green_data_section = green_data_section1
|
||||
|
||||
elif(green_data_section2 == green_data_section3 or green_data_section1 == green_data_section3):
|
||||
print("green data not equal: = ", data[3:15])
|
||||
print("green data print:", data, device, datetime.now())
|
||||
green_data_section = green_data_section3
|
||||
|
||||
else:
|
||||
print("green data not equal: = ", data[3:15])
|
||||
print("green data print:", data, device, datetime.now())
|
||||
green_data_section = green_data_section3 # use last data
|
||||
|
||||
|
||||
return green_data_section
|
||||
|
||||
def _print_ram_all_data(self):
|
||||
addr = 0
|
||||
red_length = int(7000 / 2)
|
||||
tx_temp = [0] * (red_length + 3)
|
||||
|
||||
while True:
|
||||
tx_temp[0] = MEM_INS_READ
|
||||
tx_temp[1] = ((addr >> 8) & 0xFF)
|
||||
tx_temp[2] = (addr & 0xFF)
|
||||
|
||||
ram_data = []
|
||||
ram_data = self._spi.send_byte(tx_temp)
|
||||
ram_data[0:3] = [255, 255, 255]
|
||||
print(list(ram_data), len(ram_data), addr)
|
||||
addr += len(ram_data) - 3
|
||||
|
||||
if (7000 < addr + len(ram_data)):
|
||||
del ram_data
|
||||
break
|
||||
print()
|
||||
|
||||
return
|
||||
|
||||
def recv_memory(self, device: int) -> Optional[bytes]:
|
||||
self.pin_busy.output(False)
|
||||
|
||||
@@ -162,7 +222,6 @@ class ExtMemSpiInterface(LowLevelHardwareInterface):
|
||||
address = 0
|
||||
|
||||
# first read to get data length
|
||||
tx = self._tx_buffer
|
||||
tx_h = self._tx_buffer_header
|
||||
|
||||
tx_h[0] = MEM_INS_READ
|
||||
@@ -178,9 +237,9 @@ class ExtMemSpiInterface(LowLevelHardwareInterface):
|
||||
|
||||
if (data[0] != 255 or data[1] != 255 or data[2] != 255):
|
||||
self._head_wrong_cnt[device] = self._head_wrong_cnt[device] + 1
|
||||
if (self._head_wrong_cnt[device] < 6):
|
||||
print('data_first[0:3] != [255, 255, 255]', device)
|
||||
print(list(data[0:7]))
|
||||
if (self._head_wrong_cnt[device] <= 5): # print 5 times
|
||||
print('data_first[0:3] != [255, 255, 255], device:', device, ',', self._head_wrong_cnt[device], 'times')
|
||||
print(list(data))
|
||||
|
||||
data[0:3] = [255, 255, 255]
|
||||
# ----------------------------------------------------------------------------------------------
|
||||
@@ -198,14 +257,14 @@ class ExtMemSpiInterface(LowLevelHardwareInterface):
|
||||
# if (data_first[0] != 255 or data_first[1] != 255 or data_first[2] != 255):
|
||||
# self._head_wrong_cnt[device] = self._head_wrong_cnt[device] + 1
|
||||
# if (self._head_wrong_cnt[device] < 10):
|
||||
# print('data_first[0:3] != [255, 255, 255]', device)
|
||||
# print(list(data_first[0:7]))
|
||||
# print('data_first[0:3] != [255, 255, 255], device:', device, ',', self._head_wrong_cnt[device], 'times')
|
||||
# print(list(data_first))
|
||||
|
||||
# if (data_second[0] != 255 or data_second[1] != 255 or data_second[2] != 255):
|
||||
# self._head_wrong_cnt[device] = self._head_wrong_cnt[device] + 1
|
||||
# if (self._head_wrong_cnt[device] < 10):
|
||||
# print('data_second[0:3] != [255, 255, 255]', device)
|
||||
# print(list(data_second[0:7]))
|
||||
# print('data_second[0:3] != [255, 255, 255], device:', device, ',', self._head_wrong_cnt[device], 'times')
|
||||
# print(list(data_second))
|
||||
|
||||
# if (data_first[3:] == data_second[3:]):
|
||||
# data = data_first
|
||||
@@ -217,59 +276,47 @@ class ExtMemSpiInterface(LowLevelHardwareInterface):
|
||||
# data = self.compare_green_data(data_first, data_second, data_third, len(tx_h))
|
||||
# ----------------------------------------------------------------------------------------------
|
||||
|
||||
# debug use
|
||||
# green_data = []
|
||||
# green_data = data
|
||||
# print("_[Debug] @ spi green data = ", green_data)
|
||||
green_data_section = self._compare_green_data_addr_and_flag(data, device)
|
||||
|
||||
length = (data[3] << 8) | data[4]
|
||||
header = data[7]
|
||||
elite_data_len = data[9]
|
||||
length = (green_data_section[0] << 8) | green_data_section[1]
|
||||
header = data[15]
|
||||
elite_data_len = data[17]
|
||||
|
||||
if length <= 12:
|
||||
if length < 12:
|
||||
print("length < 12")
|
||||
print("green data print:", data, device, datetime.now())
|
||||
|
||||
# if length == 0:
|
||||
# self._print_ram_all_data()
|
||||
|
||||
if length <= 4:
|
||||
# print("length <= 4")
|
||||
# print("green data print:", data, device, datetime.now())
|
||||
return None
|
||||
|
||||
if data[5] != 0 or data[6] != 0:
|
||||
if green_data_section[2] != 0xA5 or green_data_section[3] != 0x5A:
|
||||
# give a default length if the data header did not update
|
||||
length = 7000
|
||||
print("green data: is not [0,0], = ", data[5:7])
|
||||
print("green data: is not [0xA5, 0x5A], = ", data[5:7])
|
||||
print("green data print:", data, device, datetime.now())
|
||||
return None
|
||||
|
||||
if (length >= 7000):
|
||||
if (length >= 4000):
|
||||
flag_print = True
|
||||
print("green data: big length:", length)
|
||||
|
||||
if (header != 255):
|
||||
flag_print = True
|
||||
print("green data: header is not 255: ", header)
|
||||
# self._print_ram_all_data()
|
||||
|
||||
if (elite_data_len != self._elite_data_len):
|
||||
flag_print = True
|
||||
print("green data: length is not", self._elite_data_len, ": ", elite_data_len)
|
||||
|
||||
if (flag_print):
|
||||
print("green data print:", data, device, datetime.now())
|
||||
print("green data print:", data, device, datetime.now(), '\n')
|
||||
|
||||
# neulive
|
||||
# address += len(data) - 11
|
||||
# tx_d = self._tx_buffer_data
|
||||
# red_length = len(tx_d)
|
||||
|
||||
# elite read all data of ram
|
||||
# address = 4
|
||||
# red_length = length - 1
|
||||
# tx_d = [0] * red_length
|
||||
|
||||
address = 4
|
||||
address = 12
|
||||
red_length = int(length / 2)
|
||||
tx_d = [0] * red_length
|
||||
|
||||
# elite read len(_tx_buffer_data) byte
|
||||
# address = 4
|
||||
# tx_d = self._tx_buffer_data
|
||||
tx_d = [0] * (red_length + 3)
|
||||
|
||||
while True:
|
||||
tx_d[0] = MEM_INS_READ
|
||||
@@ -308,22 +355,60 @@ class ExtMemSpiInterface(LowLevelHardwareInterface):
|
||||
address += len(data) - 3
|
||||
del data
|
||||
|
||||
# print("_[Debug] @ spi recv data rx = ")
|
||||
# last_index = 0
|
||||
# print("_[Debug] @ spi recv data rx, ram_select:", self._pin_ram_sel_value[device], ",", datetime.now())
|
||||
# for i in range(0, len(rx), self._single_data_len):
|
||||
# print(rx[i:i+self._single_data_len])
|
||||
# last_index = i
|
||||
# # print(rx[i:i+self._single_data_len])
|
||||
# if i == 0:
|
||||
# print(rx[0:8], 'ram:', rx[47])
|
||||
|
||||
# if last_index != 0:
|
||||
# print(rx[last_index:last_index+8], 'ram:', rx[last_index+47])
|
||||
# print()
|
||||
|
||||
# /*
|
||||
# * red data formate:
|
||||
# * ramHdr, ramHdr, ramHdr, (3B)
|
||||
# * 255, #, data_length, (3B)
|
||||
# * data, (20B)
|
||||
# * data, (40B)
|
||||
# * red_wrong, red_retry_cnt, green_wrong, green_retry_cnt, (4B)
|
||||
# * 255, #, data_length, (3B)
|
||||
# * check_num, (1B)
|
||||
# * */
|
||||
|
||||
# read again if check num is wrong
|
||||
index = 0
|
||||
check_number_print = False
|
||||
for i in range(0, len(rx), self._single_data_len):
|
||||
check_sum = sum(rx[i : i + self._single_data_len - 1]) & 0b11111111
|
||||
# print(check_sum, rx[i + self._single_data_len - 1])
|
||||
|
||||
if (check_sum != rx[i + self._single_data_len - 1]):
|
||||
# print('check_sum wrong, origin value:', 'check_sum =', check_sum, rx[i : i + self._single_data_len])
|
||||
tx_d = [0] * (self._single_data_len + 3)
|
||||
address = 12 + self._single_data_len * index
|
||||
tx_d[0] = MEM_INS_READ
|
||||
tx_d[1] = ((address >> 8) & 0xFF)
|
||||
tx_d[2] = (address & 0xFF)
|
||||
|
||||
data = []
|
||||
data = self._spi.send_byte(tx_d)
|
||||
data[0:3] = [255, 255, 255]
|
||||
rx[i : i + self._single_data_len] = data[3:]
|
||||
print('check_sum wrong, read again:', 'check_sum =', check_sum, rx[i : i + self._single_data_len])
|
||||
check_number_print = True
|
||||
index = index + 1
|
||||
|
||||
if check_number_print:
|
||||
print('check_sum wrong:', device, datetime.now())
|
||||
for i in range(0, len(rx), self._single_data_len):
|
||||
print(rx[i:i+self._single_data_len])
|
||||
print()
|
||||
|
||||
# mark read
|
||||
self._spi.send_byte(self.MEM_INS_MARKED)
|
||||
self._spi.send_byte(self.MEM_INS_MARKED1)
|
||||
self._spi.send_byte(self.MEM_INS_MARKED2)
|
||||
self._spi.send_byte(self.MEM_INS_MARKED3)
|
||||
|
||||
except BaseException as e:
|
||||
print(e)
|
||||
@@ -356,108 +441,39 @@ class ExtMemSpiInterface(LowLevelHardwareInterface):
|
||||
|
||||
self._spi.send_byte(tx)
|
||||
|
||||
def flush_all(self):
|
||||
self.flush()
|
||||
|
||||
def foreach(self) -> Iterable[int]:
|
||||
yield 0
|
||||
|
||||
|
||||
class MultiExtMemSpiInterface(ExtMemSpiInterface):
|
||||
__slots__ = ('_selector', '_wait_for_first_data')
|
||||
|
||||
def __init__(self,
|
||||
select: Selector,
|
||||
device: Tuple[int, int] = None):
|
||||
super().__init__(device)
|
||||
|
||||
self._selector = select
|
||||
|
||||
self._pin_sel_val = [False for _ in range(Selector.SIZE)]
|
||||
self._wait_for_first_data = [True for _ in range(Selector.SIZE)]
|
||||
|
||||
@property
|
||||
def select(self) -> int:
|
||||
return self._selector.channel
|
||||
|
||||
@select.setter
|
||||
def select(self, value: int):
|
||||
self._selector.select(value)
|
||||
|
||||
def changed(self, flip=False) -> bool:
|
||||
channel = self._selector.channel
|
||||
old = self._pin_sel_val[channel]
|
||||
value = bool(self.pin_sel)
|
||||
|
||||
if flip:
|
||||
self._pin_sel_val[channel] = value
|
||||
|
||||
return value != old
|
||||
|
||||
def reset(self):
|
||||
self._spi.reset()
|
||||
|
||||
def close(self):
|
||||
self._selector.close()
|
||||
super().close()
|
||||
|
||||
def flush_all(self):
|
||||
for _ in self._selector.foreach():
|
||||
self.pin_reset.output(False)
|
||||
self.pin_reset.output(True)
|
||||
|
||||
def foreach(self) -> Iterable[int]:
|
||||
for channel in self._selector.foreach():
|
||||
yield channel
|
||||
|
||||
def set_wait_flag(self, spi_idx:int = None, value:bool = None):
|
||||
self._wait_for_first_data[spi_idx] = value
|
||||
|
||||
def get_wait_flag(self, spi_idx:int = None) -> Optional[bool]:
|
||||
if spi_idx < Selector.SIZE:
|
||||
return self._wait_for_first_data[spi_idx]
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
class ExtMemManager:
|
||||
def __init__(self, ext_mem: ExtMemSpiInterface):
|
||||
self._mem_sel = InputPin.get_used(P3Pin.MEM_SEL, pull_up_down=True)
|
||||
self._mem_req = OutputPin.get_used(P3Pin.MEM_REQ, initial=True)
|
||||
|
||||
def __init__(self, ext_mem: MultiExtMemSpiInterface):
|
||||
self._ext_mem = ext_mem
|
||||
|
||||
@property
|
||||
def mem_sel(self) -> int:
|
||||
return int(self._mem_sel)
|
||||
|
||||
@property
|
||||
def mem_req(self) -> int:
|
||||
return int(self._mem_req)
|
||||
|
||||
def mem_request(self):
|
||||
self._mem_req.pulse()
|
||||
sleep(_SLEEP_TIME_)
|
||||
|
||||
def get_ext_mem_register(self) -> List[Tuple[Optional[int], Optional[int]]]:
|
||||
ret = [(None, None) for _ in range(Selector.SIZE)]
|
||||
|
||||
for channel in self._ext_mem.foreach():
|
||||
r = [None, None]
|
||||
|
||||
self.mem_request()
|
||||
sleep(0.01)
|
||||
m1 = int(self._mem_sel)
|
||||
self._ext_mem.set_pin_mem_sel(False)
|
||||
pin_value = self._ext_mem.get_pin_mem_req()
|
||||
self._ext_mem.set_pin_mem_req(not pin_value)
|
||||
|
||||
m1 = int(self._ext_mem.get_pin_ram_sel())
|
||||
# print("m1 = ", m1)
|
||||
self._ext_mem.write_register(DEFAULT_REGISTER_VALUE)
|
||||
r[m1] = self._ext_mem.read_register()
|
||||
sleep(0.040)
|
||||
self._ext_mem.set_pin_mem_sel(True)
|
||||
sleep(0.200)
|
||||
|
||||
self.mem_request()
|
||||
sleep(0.01)
|
||||
m2 = int(self._mem_sel)
|
||||
self._ext_mem.set_pin_mem_sel(False)
|
||||
pin_value = self._ext_mem.get_pin_mem_req()
|
||||
self._ext_mem.set_pin_mem_req(not pin_value)
|
||||
|
||||
m2 = int(self._ext_mem.get_pin_ram_sel())
|
||||
# print("m2 = ", m2)
|
||||
self._ext_mem.write_register(DEFAULT_REGISTER_VALUE)
|
||||
r[m2] = self._ext_mem.read_register()
|
||||
sleep(0.040)
|
||||
self._ext_mem.set_pin_mem_sel(True)
|
||||
sleep(0.200)
|
||||
|
||||
ret[channel] = tuple(r)
|
||||
|
||||
@@ -483,33 +499,6 @@ class ExtMemManager:
|
||||
|
||||
return 0
|
||||
|
||||
def get_no_device_channel(self, result: List[Tuple[Optional[int], Optional[int]]] = None) -> List[int]:
|
||||
if result is None:
|
||||
result = self.get_ext_mem_register()
|
||||
|
||||
ret = []
|
||||
|
||||
for channel, result in enumerate(result):
|
||||
if self.is_no_device(result):
|
||||
ret.append(channel)
|
||||
|
||||
return ret
|
||||
|
||||
def get_memory_test_fail(self, result: List[Tuple[Optional[int], Optional[int]]] = None) -> List[int]:
|
||||
if result is None:
|
||||
result = self.get_ext_mem_register()
|
||||
|
||||
ret = []
|
||||
|
||||
for channel, result in enumerate(result):
|
||||
if self.is_no_device(result):
|
||||
continue
|
||||
|
||||
if self.is_memory_test_fail(result) != 0:
|
||||
ret.append(channel)
|
||||
|
||||
return ret
|
||||
|
||||
def get_available_channel(self, result: List[Tuple[Optional[int], Optional[int]]] = None) -> List[int]:
|
||||
if result is None:
|
||||
result = self.get_ext_mem_register()
|
||||
@@ -526,173 +515,3 @@ class ExtMemManager:
|
||||
ret.append(channel)
|
||||
|
||||
return ret
|
||||
|
||||
def test_available_channel(self, result: List[Tuple[Optional[int], Optional[int]]] = None) -> List[int]:
|
||||
if result is None:
|
||||
result = self.get_ext_mem_register()
|
||||
|
||||
available_channel = []
|
||||
|
||||
for channel, result in enumerate(result):
|
||||
r1, r2 = result
|
||||
|
||||
if self.is_no_device(result):
|
||||
print('channel', channel, 'no device')
|
||||
continue
|
||||
|
||||
test_pass = True
|
||||
|
||||
if r1 is None or r2 is None:
|
||||
test_pass = False
|
||||
print('channel', channel, 'mem_sel', 'x', 'not change')
|
||||
|
||||
if r1 is not None and r1 > 0 and r1 != DEFAULT_REGISTER_VALUE:
|
||||
test_pass = False
|
||||
print('channel', channel, 'mem_sel', 0, 'register', r1)
|
||||
|
||||
if r2 is not None and r2 > 0 and r2 != DEFAULT_REGISTER_VALUE:
|
||||
test_pass = False
|
||||
print('channel', channel, 'mem_sel', 1, 'register', r2)
|
||||
|
||||
if test_pass:
|
||||
print('channel', channel, 'mem_sel', 0, 'register', r1)
|
||||
print('channel', channel, 'mem_sel', 1, 'register', r2)
|
||||
available_channel.append(channel)
|
||||
|
||||
return available_channel
|
||||
|
||||
def test_memory_read_write(self, channel: int, print_result=False) -> bool:
|
||||
self._ext_mem.select = channel
|
||||
|
||||
addr = 4
|
||||
size = 100
|
||||
test_pass = True
|
||||
|
||||
while addr < MEM_SIZE:
|
||||
d1 = [randint(10, 99) for _ in range(size)]
|
||||
d2 = [randint(10, 99) for _ in range(size)]
|
||||
|
||||
self.mem_request()
|
||||
m1 = int(self._mem_sel)
|
||||
self._ext_mem.write_memory(addr, d1)
|
||||
|
||||
self.mem_request()
|
||||
m2 = int(self._mem_sel)
|
||||
self._ext_mem.write_memory(addr, d2)
|
||||
|
||||
self.mem_request()
|
||||
m11 = int(self._mem_sel)
|
||||
r1 = self._ext_mem.read_memory(addr, size)
|
||||
|
||||
if m1 != m11:
|
||||
test_pass = False
|
||||
if print_result:
|
||||
print('channel', channel, 'mem_sel not change')
|
||||
|
||||
if d1 != r1:
|
||||
test_pass = False
|
||||
if print_result:
|
||||
self.print_bytes_diff(d1, r1)
|
||||
|
||||
self.mem_request()
|
||||
m22 = int(self._mem_sel)
|
||||
r2 = self._ext_mem.read_memory(addr, size)
|
||||
|
||||
if m2 != m22:
|
||||
test_pass = False
|
||||
if print_result:
|
||||
print('channel', channel, 'mem_sel not change')
|
||||
|
||||
if d2 != r2:
|
||||
test_pass = False
|
||||
if print_result:
|
||||
self.print_bytes_diff(d2, r2)
|
||||
|
||||
addr += size
|
||||
|
||||
return test_pass
|
||||
|
||||
@staticmethod
|
||||
def print_bytes_diff(_1: List[int], _2: List[int]):
|
||||
s1 = ''
|
||||
s2 = ''
|
||||
|
||||
l1 = len(_1)
|
||||
l2 = len(_2)
|
||||
|
||||
for i in range(min(l1, l2)):
|
||||
v1 = _1[i]
|
||||
v2 = _2[i]
|
||||
|
||||
if v1 == v2:
|
||||
s1 += '%02X ' % v1
|
||||
s2 += '%02X ' % v2
|
||||
else:
|
||||
s1 += '%02X ' % v1
|
||||
s2 += pc('%02X' % v2, RED) + ' '
|
||||
|
||||
if l1 == l2:
|
||||
pass
|
||||
|
||||
elif l1 < l2:
|
||||
for i in range(l1, l2):
|
||||
s2 += pc('%02X' % _2[i], GREEN) + ' '
|
||||
else:
|
||||
for i in range(l2, l1):
|
||||
s1 += pc('%02X' % _1[i], RED) + ' '
|
||||
|
||||
print(s1)
|
||||
print(s2)
|
||||
|
||||
|
||||
def hardware_test():
|
||||
ext_mem = MultiExtMemSpiInterface(Selector.get(Selector.MEM_SELECTOR))
|
||||
|
||||
fake_mode = False
|
||||
|
||||
try:
|
||||
ext_mem.reset()
|
||||
except FileNotFoundError:
|
||||
fake_mode = True
|
||||
|
||||
ret = {
|
||||
'channel_count': Selector.SIZE,
|
||||
'memory_size': MEM_SIZE,
|
||||
'pin_mem_req': P3Pin.MEM_REQ,
|
||||
'pin_mem_sel': P3Pin.MEM_SEL,
|
||||
}
|
||||
|
||||
if not fake_mode:
|
||||
tester = ExtMemManager(ext_mem)
|
||||
|
||||
result = tester.get_ext_mem_register()
|
||||
no_device = tester.get_no_device_channel(result)
|
||||
reg_fail = tester.get_memory_test_fail(result)
|
||||
available = tester.get_available_channel(result)
|
||||
|
||||
channel = ['unknown' for _ in range(Selector.SIZE)]
|
||||
|
||||
for ch in range(len(channel)):
|
||||
if ch in no_device:
|
||||
channel[ch] = 'no_device'
|
||||
|
||||
elif ch in reg_fail:
|
||||
channel[ch] = 'reg_fail'
|
||||
|
||||
elif not tester.test_memory_read_write(ch):
|
||||
channel[ch] = 'mem_fail'
|
||||
|
||||
else:
|
||||
channel[ch] = 'available'
|
||||
|
||||
ret['register'] = result
|
||||
ret['available'] = available
|
||||
ret['channel'] = channel
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from pprint import pprint
|
||||
|
||||
pprint(hardware_test())
|
||||
|
||||
@@ -53,7 +53,7 @@ class HardwareImplSpiInterface(LowLevelHardwareInterface):
|
||||
*MISO*, *SCLK*, *GE0_N*
|
||||
"""
|
||||
|
||||
__slots__ = ('_device', '_spi', '_spi_mode', 'pin_request', '_spi_speed')
|
||||
__slots__ = ('_device', '_spi', '_spi_mode', '_spi_speed')
|
||||
|
||||
def __init__(self,
|
||||
device: Tuple[int, int] = None,
|
||||
|
||||
@@ -28,7 +28,7 @@ class UARTInterface(LowLevelHardwareInterface):
|
||||
self._serial = serial.Serial(self._port,
|
||||
baudrate=self._baudrate,
|
||||
timeout=0,
|
||||
writeTimeout=1)
|
||||
writeTimeout=0.01)
|
||||
# deprecate function name which change at version 3.0
|
||||
self._serial.flushInput()
|
||||
self._serial.flushOutput()
|
||||
|
||||
@@ -117,14 +117,14 @@ class Selector:
|
||||
self._p1.output(p[1])
|
||||
self._p2.output(p[2])
|
||||
|
||||
if (value == 4 and self._last_sel != 6):
|
||||
print('mem_sel is not use gray code, value:', value, ', last value:', self._last_sel)
|
||||
elif (value == 5 and self._last_sel != 4):
|
||||
print('mem_sel is not use gray code, value:', value, ', last value:', self._last_sel)
|
||||
elif (value == 7 and self._last_sel != 5):
|
||||
print('mem_sel is not use gray code, value:', value, ', last value:', self._last_sel)
|
||||
elif (value == 6 and self._last_sel != 7):
|
||||
print('mem_sel is not use gray code, value:', value, ', last value:', self._last_sel)
|
||||
# if (value == 4 and self._last_sel != 6):
|
||||
# print('mem_sel is not use gray code, value:', value, ', last value:', self._last_sel)
|
||||
# elif (value == 5 and self._last_sel != 4):
|
||||
# print('mem_sel is not use gray code, value:', value, ', last value:', self._last_sel)
|
||||
# elif (value == 7 and self._last_sel != 5):
|
||||
# print('mem_sel is not use gray code, value:', value, ', last value:', self._last_sel)
|
||||
# elif (value == 6 and self._last_sel != 7):
|
||||
# print('mem_sel is not use gray code, value:', value, ', last value:', self._last_sel)
|
||||
|
||||
self._last_sel = value
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,26 @@
|
||||
|
||||
class Action():
|
||||
def __init__(self, action_id, action):
|
||||
self._id: str = action_id
|
||||
self._type: str = action['type']
|
||||
self._target: str = action['target']
|
||||
self._condition : list[str] = action['condition']
|
||||
# self._duration = action.get('duration', None)
|
||||
# self._goto = action.get('goto', None)
|
||||
# self._cycle = action.get('cycle', None)
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
return self._id
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return self._type
|
||||
|
||||
@property
|
||||
def target(self):
|
||||
return self._target
|
||||
|
||||
@property
|
||||
def condition(self):
|
||||
return self._condition
|
||||
@@ -0,0 +1,96 @@
|
||||
from datetime import datetime
|
||||
from time import time
|
||||
|
||||
class Condition():
|
||||
def __init__(self, id, condition):
|
||||
self._id = id
|
||||
self._type = condition['type']
|
||||
self._comparsion = condition['comparsion']
|
||||
self._value = condition['value']
|
||||
self._active = False
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
return self._id
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return self._type
|
||||
|
||||
@property
|
||||
def comparsion(self):
|
||||
return self._comparsion
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
return self._value
|
||||
|
||||
@id.setter
|
||||
def id(self, new_id):
|
||||
self._id = new_id
|
||||
|
||||
@type.setter
|
||||
def type(self, new_type):
|
||||
self._type = new_type
|
||||
|
||||
@comparsion.setter
|
||||
def comparsion(self, new_comparsion):
|
||||
self._comparsion = new_comparsion
|
||||
|
||||
@value.setter
|
||||
def value(self, new_value):
|
||||
self._value = new_value
|
||||
|
||||
def compareWith(self, operator, x, y) -> bool:
|
||||
# print(operator, x, y)
|
||||
cases = {
|
||||
"equal": lambda a, b: a == b,
|
||||
"bigger": lambda a, b: a > b,
|
||||
"smaller": lambda a, b: a < b,
|
||||
}
|
||||
|
||||
return cases[operator](x, y)
|
||||
|
||||
def match_or_not(self, **kwargs):
|
||||
# print(self._type, self._comparsion, self._value)
|
||||
return getattr(self, self.type)(**kwargs)
|
||||
|
||||
def absolute_time(self, **kwargs):
|
||||
now = int(time())
|
||||
time_condition = round(self.datetime_to_timestamp(self.str_to_datetime(self._value)))
|
||||
|
||||
return self.compareWith(self.comparsion, now, time_condition)
|
||||
|
||||
def after_project_run(self, **kwargs):
|
||||
project_start_time = kwargs['project_start_time']
|
||||
delay_time = kwargs['delay_time']
|
||||
|
||||
time_diff = int(time() - project_start_time - delay_time)
|
||||
return self.compareWith(self.comparsion, time_diff, int(self._value))
|
||||
|
||||
def after_task_run(self, **kwargs):
|
||||
# print('relative_time_from_task', kwargs,kwargs['task_start_time'],kwargs['delay_time'])
|
||||
if len(kwargs['task_start_time']) == 0:
|
||||
return False
|
||||
task_start_time = kwargs['task_start_time'][-1]
|
||||
delay_time = kwargs['delay_time']
|
||||
|
||||
time_diff = int(time() - task_start_time - delay_time)
|
||||
# print('time_diff', time_diff)
|
||||
return self.compareWith(self.comparsion, time_diff, int(self._value))
|
||||
|
||||
def device(self, **kwargs):
|
||||
print('device')
|
||||
|
||||
def previous_task_done(self, **kwargs):
|
||||
running_task = kwargs['running_task']
|
||||
if running_task.status == 2 and self._active == False:
|
||||
self._active = True
|
||||
return True
|
||||
return False
|
||||
|
||||
def str_to_datetime(self, time_str):
|
||||
return datetime.strptime(time_str,'%Y-%m-%dT%H:%M')
|
||||
|
||||
def datetime_to_timestamp(self, date):
|
||||
return datetime.timestamp(date)
|
||||
@@ -0,0 +1,32 @@
|
||||
|
||||
class Instruction():
|
||||
def __init__(self):
|
||||
self._instruction_set = {
|
||||
'set_file_name': {
|
||||
'method': 'update_recording_file_name_info',
|
||||
'arguments': ['file_name']
|
||||
},
|
||||
'set_parent': {
|
||||
'method': 'update_parent_info',
|
||||
'arguments': ['parent']
|
||||
},
|
||||
'set_parameter':{
|
||||
'method': 'set_multi_parameters',
|
||||
'arguments': ['parameter']
|
||||
},
|
||||
'call_instruction': {
|
||||
'method': 'call_instruction',
|
||||
'arguments': ['instruction']
|
||||
},
|
||||
}
|
||||
|
||||
self._start_instruction = list(map(lambda ins: self._instruction_set[ins] ,['set_file_name', 'set_parent', 'set_parameter', 'call_instruction']))
|
||||
self._stop_instruction = list(map(lambda ins: self._instruction_set[ins] ,['call_instruction']))
|
||||
|
||||
@property
|
||||
def start(self) -> list:
|
||||
return self._start_instruction
|
||||
|
||||
@property
|
||||
def stop(self) -> list:
|
||||
return self._stop_instruction
|
||||
@@ -0,0 +1,209 @@
|
||||
import sys
|
||||
import json
|
||||
import threading
|
||||
|
||||
from time import time, sleep
|
||||
from datetime import datetime
|
||||
from collections import deque
|
||||
from copy import copy
|
||||
from uuid import uuid4
|
||||
|
||||
from .task import Task
|
||||
from .task_manager import TaskManager
|
||||
from .instruction import Instruction
|
||||
from biopro.device.manager import DeviceManager
|
||||
from biopro.text import *
|
||||
|
||||
key_list = {
|
||||
'deviceList': 'device',
|
||||
}
|
||||
|
||||
class Project(threading.Thread):
|
||||
def __init__(self, project, device_manager: DeviceManager, mqttThread = None, name="project"):
|
||||
super(Project, self).__init__(name = name)
|
||||
self._project = project
|
||||
self._device_manager = device_manager
|
||||
self._mqtt_thread = mqttThread
|
||||
self._time_interval = 1
|
||||
self._start_time = None
|
||||
self._end_time = None
|
||||
|
||||
self._id = None
|
||||
self._uuid = uuid4()
|
||||
self._name = None
|
||||
self._desc = None
|
||||
self._device = None
|
||||
self._complete_device = []
|
||||
self._status = None
|
||||
|
||||
self._instruction_set = Instruction()
|
||||
self._stop_flag = False
|
||||
|
||||
self.setup_project(project)
|
||||
self.setup_device(self._device)
|
||||
|
||||
def setup_project(self, project):
|
||||
for (key, value) in project.items():
|
||||
if key in key_list.keys():
|
||||
key = key_list[key]
|
||||
|
||||
if key == 'task':
|
||||
self._task_manager = TaskManager(project['task'])
|
||||
else:
|
||||
setattr(self, key, value)
|
||||
|
||||
def setup_device(self, device_list):
|
||||
for device in device_list:
|
||||
complete_device = self._device_manager.get_device(device['connectDevice']['device_address'])
|
||||
self._complete_device.append(complete_device)
|
||||
|
||||
@property
|
||||
def id(self) -> int:
|
||||
return self._id
|
||||
|
||||
@id.setter
|
||||
def id(self, new_id):
|
||||
self._id = new_id
|
||||
|
||||
@property
|
||||
def uuid(self) -> str:
|
||||
return self._uuid
|
||||
|
||||
@uuid.setter
|
||||
def uuid(self, new_uuid):
|
||||
self._uuid = new_uuid
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return self._name
|
||||
|
||||
@name.setter
|
||||
def name(self, new_name):
|
||||
self._name = new_name
|
||||
|
||||
@property
|
||||
def desc(self) -> str:
|
||||
return self._desc
|
||||
|
||||
@desc.setter
|
||||
def desc(self, new_desc):
|
||||
self._desc = new_desc
|
||||
|
||||
@property
|
||||
def status(self) -> str:
|
||||
return self._status
|
||||
|
||||
@status.setter
|
||||
def status(self, new_status):
|
||||
self._status = new_status
|
||||
|
||||
@property
|
||||
def device(self) -> list:
|
||||
return self._device
|
||||
|
||||
@device.setter
|
||||
def device(self, new_device):
|
||||
self._device = new_device
|
||||
|
||||
@property
|
||||
def task_list(self):
|
||||
return self.task_manager.task_list
|
||||
|
||||
|
||||
@property
|
||||
def mqtt_thread(self):
|
||||
return self._mqtt_thread
|
||||
|
||||
def run(self):
|
||||
self._start_time = time()
|
||||
|
||||
self.mqtt_thread.broadcast_command('project:' + self._name + ' start_at ' + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
|
||||
while not self._stop_flag :
|
||||
# check running task first
|
||||
delay_time = 0
|
||||
check_list = copy(self._task_manager.check_list)
|
||||
|
||||
for task in check_list:
|
||||
if task != None:
|
||||
now = time()
|
||||
# print('round task', task.name)
|
||||
# print('running task', self._task_manager.running_task.name, self._task_manager.running_task.status)
|
||||
# if self._task_manager.prev_task != None:
|
||||
# print('previous_task', self._task_manager.prev_task.name, self._task_manager.prev_task.status)
|
||||
|
||||
match_condition_list = task.check_condition(
|
||||
project_start_time = self._start_time,
|
||||
delay_time = delay_time,
|
||||
running_task= self._task_manager.running_task,
|
||||
previous_task = self._task_manager.prev_task
|
||||
)
|
||||
# print('match_condition_list', match_condition_list)
|
||||
for condition in match_condition_list:
|
||||
match_action_list = task.get_match_action(condition.id)
|
||||
for action in match_action_list:
|
||||
# print('match_action', action.type, action.target)
|
||||
if action.type == 'start' and task.status != 1:
|
||||
self._task_manager.set_running_task(task)
|
||||
self.mqtt_thread.broadcast_command('project:task ' + task.name + ' start at ' + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
|
||||
|
||||
device = self._complete_device[action.target]
|
||||
task_info = task.get_task_info(action)
|
||||
instruction_set = getattr(self._instruction_set, action.type, None)
|
||||
# print('instruction_set',instruction_set)
|
||||
|
||||
if instruction_set != None:
|
||||
for instruction in instruction_set:
|
||||
args = list(map(lambda arg: task_info[arg], instruction['arguments']))
|
||||
threading.Thread(target=getattr(device, instruction['method'])(*args))
|
||||
|
||||
delay_time += (time() - now)
|
||||
|
||||
# check task not running then stop
|
||||
if self.check_running_task_not_run() == True:
|
||||
self.mqtt_thread.broadcast_command('project:task ' + str(self._task_manager.running_task.name) + ' stop at ' + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
|
||||
self._task_manager.running_task.stop()
|
||||
|
||||
# check project done then close project
|
||||
if self.check_project_done() == True:
|
||||
self.mqtt_thread.broadcast_command('project:project ' + str(self._name) + ' stop at ' + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
|
||||
print('project stop at', datetime.now())
|
||||
self.close()
|
||||
|
||||
if self._time_interval - delay_time > 0:
|
||||
sleep(self._time_interval - delay_time)
|
||||
|
||||
def pause(self):
|
||||
# TODO
|
||||
pass
|
||||
|
||||
def close(self):
|
||||
self._end_time = time()
|
||||
self._stop_flag = True
|
||||
|
||||
def check_project_done(self):
|
||||
for task in self._task_manager.task_list:
|
||||
# if task never start or still task is running then reject
|
||||
if task.status == 1 or task.status == -1:
|
||||
return False
|
||||
return True
|
||||
|
||||
def check_running_task_not_run(self):
|
||||
# if no running task
|
||||
if self._task_manager.running_task == None:
|
||||
return False
|
||||
device_list = self._task_manager.running_task.device
|
||||
for device in device_list:
|
||||
if self._complete_device[device].status == 1:
|
||||
return False
|
||||
return True
|
||||
|
||||
def as_json(self):
|
||||
return {
|
||||
'id': self._id,
|
||||
'name': self._name,
|
||||
'uuid': self._uuid,
|
||||
'desc': self._desc,
|
||||
'status': self._status,
|
||||
'device': self._device,
|
||||
'task_list': self.task_list,
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
from io import StringIO
|
||||
from json import loads as json_parse, dumps as _json_stringify
|
||||
from typing import Dict, Optional, Any
|
||||
import paho.mqtt.client as mqtt
|
||||
from .project import Project
|
||||
from biopro.device.manager import DeviceManager
|
||||
|
||||
def json_stringify(o: Any) -> str:
|
||||
return _json_stringify(o, separators=(',', ':'))
|
||||
|
||||
class ProjectManager():
|
||||
def __init__(self, device_manager: DeviceManager, mqtt_thread=None) :
|
||||
self._project_list = []
|
||||
self._mqtt_thread = mqtt_thread
|
||||
self._device_manager = device_manager
|
||||
|
||||
def create(self, project):
|
||||
new_project = Project(project, self._device_manager, self._mqtt_thread)
|
||||
self._project_list.append(new_project)
|
||||
return new_project
|
||||
|
||||
def remove(self, index):
|
||||
self._project_list[index].stop()
|
||||
del self._project_list[index]
|
||||
|
||||
def get(self):
|
||||
return self._project_list
|
||||
|
||||
def run(self, project):
|
||||
project.start()
|
||||
|
||||
def stop(self, project):
|
||||
project.stop()
|
||||
@@ -0,0 +1,252 @@
|
||||
from typing import List
|
||||
from .condition import Condition
|
||||
from .action import Action
|
||||
from time import time
|
||||
from datetime import datetime
|
||||
|
||||
key_list = {
|
||||
'deviceList': 'device',
|
||||
'parameterSet': 'parameter_set'
|
||||
}
|
||||
|
||||
class Task:
|
||||
def __init__(self, task):
|
||||
self._id = None
|
||||
self._name = None
|
||||
self._parent = None
|
||||
self._cycle = None
|
||||
self._device = None
|
||||
self._event = None
|
||||
self._trigger = None
|
||||
self._parameter_set = None
|
||||
self._condition = None
|
||||
self._action = None
|
||||
# -1: initial 0: start(idle), 1: running, 2: close(idle)
|
||||
self._status = 0
|
||||
self._next = None
|
||||
|
||||
self._condition_list: List[Condition] = []
|
||||
self._action_list: List[Action] = []
|
||||
self._instruction_list = []
|
||||
self._record_list = []
|
||||
|
||||
self._start_time = []
|
||||
self._idle_time = []
|
||||
self._end_time = []
|
||||
self._period = None
|
||||
|
||||
self.load_task(task)
|
||||
|
||||
def load_task(self, task) -> None:
|
||||
# update task attribute
|
||||
for key, value in task.items():
|
||||
if key in key_list.keys():
|
||||
key = key_list[key]
|
||||
if key == 'condition':
|
||||
self.update_condition_list(value)
|
||||
if key == 'action':
|
||||
self.update_action_list(value)
|
||||
# print(key, value)
|
||||
setattr(self, key, value)
|
||||
|
||||
def update_condition_list(self, condition_dict):
|
||||
self._condition_list.clear()
|
||||
for key, condition in condition_dict.items():
|
||||
self._condition_list.append(Condition(key, condition))
|
||||
|
||||
def update_action_list(self, action_dict):
|
||||
self._action_list.clear()
|
||||
for key, action in action_dict.items():
|
||||
self._action_list.append(Action(key, action))
|
||||
|
||||
@property
|
||||
def id(self) -> str:
|
||||
return self._id
|
||||
|
||||
@id.setter
|
||||
def id(self, new_id):
|
||||
self._id = new_id
|
||||
|
||||
@property
|
||||
def uuid(self) -> str:
|
||||
return self._uuid
|
||||
|
||||
@uuid.setter
|
||||
def uuid(self, new_uuid):
|
||||
self._uuid = new_uuid
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
@name.setter
|
||||
def name(self, new_name):
|
||||
self._name = new_name
|
||||
|
||||
@property
|
||||
def parent(self):
|
||||
if self._parent == None:
|
||||
return {"folder": [2]}
|
||||
return self._parent
|
||||
|
||||
@parent.setter
|
||||
def parent(self, new_parent):
|
||||
self._parent = new_parent
|
||||
|
||||
@property
|
||||
def cycle(self) -> int:
|
||||
return self._cycle
|
||||
|
||||
@cycle.setter
|
||||
def cycle(self, new_cycle):
|
||||
self._cycle = new_cycle
|
||||
|
||||
@property
|
||||
def device(self) -> dict:
|
||||
return self._device
|
||||
|
||||
@device.setter
|
||||
def device(self, new_device):
|
||||
self._device = new_device
|
||||
|
||||
@property
|
||||
def event(self) -> list:
|
||||
return self._event
|
||||
|
||||
@event.setter
|
||||
def event(self, new_event):
|
||||
self._event = new_event
|
||||
|
||||
@property
|
||||
def trigger(self) -> list:
|
||||
return self._trigger
|
||||
|
||||
@trigger.setter
|
||||
def trigger(self, new_trigger):
|
||||
self._trigger = new_trigger
|
||||
|
||||
@property
|
||||
def parameter_set(self) -> list:
|
||||
return self._parameter_set
|
||||
|
||||
@parameter_set.setter
|
||||
def parameter_set(self, new_parameter_set):
|
||||
self._parameter_set = new_parameter_set
|
||||
|
||||
@property
|
||||
def condition(self) -> list:
|
||||
return self._condition
|
||||
|
||||
@condition.setter
|
||||
def condition(self, new_condition):
|
||||
self._condition = new_condition
|
||||
|
||||
@property
|
||||
def action(self) -> list:
|
||||
return self._action
|
||||
|
||||
@action.setter
|
||||
def action(self, new_action):
|
||||
self._action = new_action
|
||||
|
||||
@property
|
||||
def status(self) -> str:
|
||||
return self._status
|
||||
|
||||
@status.setter
|
||||
def status(self, new_status):
|
||||
self._status = new_status
|
||||
|
||||
@property
|
||||
def next(self) -> str:
|
||||
return self._next
|
||||
|
||||
@next.setter
|
||||
def next(self, new_next):
|
||||
self._next = new_next
|
||||
|
||||
@property
|
||||
def instruction_list(self) -> List:
|
||||
return self._instruction_list
|
||||
|
||||
@property
|
||||
def start_time(self) -> List:
|
||||
return self._start_time
|
||||
|
||||
@property
|
||||
def end_time(self) -> List:
|
||||
return self._end_time
|
||||
|
||||
def new_start_time(self):
|
||||
self._start_time.append(time())
|
||||
|
||||
def new_end_time(self):
|
||||
self._end_time.append(time())
|
||||
|
||||
def get_parameter_set_by_device(self, device):
|
||||
return [parameter_set for parameter_set in self.parameter_set.values() if device == parameter_set['target']]
|
||||
|
||||
def get_parameter(self, name_or_value, device):
|
||||
name_list = []
|
||||
value_list = []
|
||||
for parameter in self.get_parameter_set_by_device(device):
|
||||
for key, value in parameter.items():
|
||||
if key != 'target':
|
||||
name_list.append(key)
|
||||
value_list.append(str(value))
|
||||
|
||||
return '|'.join(name_list) if name_or_value == 'name' else '|'.join(value_list)
|
||||
|
||||
def run(self):
|
||||
print(self._name, 'run at', datetime.now())
|
||||
self._status = 1
|
||||
self._start_time.append(time())
|
||||
|
||||
def start(self):
|
||||
self.status = 1
|
||||
|
||||
def stop(self):
|
||||
self.status = 2
|
||||
|
||||
def get_match_action_list(self, match_condition_list):
|
||||
return map(lambda condition: [x for x in self._action_list if condition.id in x.get_condition_list()], match_condition_list)
|
||||
|
||||
def get_match_action(self, condition_id):
|
||||
return [action for action in self._action_list if condition_id in action.condition]
|
||||
|
||||
def do_action(self, action):
|
||||
for instruction in action.get_instruction_list():
|
||||
self._instruction_list.append(instruction)
|
||||
|
||||
def check_condition(self, **kwargs):
|
||||
kwargs['task_start_time'] = self._start_time
|
||||
return [condition for condition in self._condition_list if condition.match_or_not(**kwargs)]
|
||||
|
||||
def get_task_info(self, action):
|
||||
_type = action.type
|
||||
if _type == 'stop':
|
||||
_type = 'interrupt'
|
||||
|
||||
return {
|
||||
'device': action.target,
|
||||
'parameter': self.get_parameter_set_by_device(action.target),
|
||||
'file_name': self._name + '-' + str(action.target),
|
||||
'parent': self.parent,
|
||||
'instruction': _type
|
||||
}
|
||||
|
||||
def as_json(self):
|
||||
return {
|
||||
'id': self.id,
|
||||
'name': self.name,
|
||||
'parent': self.parent,
|
||||
'cycle': self.cycle,
|
||||
'device': self.device,
|
||||
'event': self.event,
|
||||
'trigger': self.trigger,
|
||||
'parameter_set': self.parameter_set,
|
||||
'condition': self.condition,
|
||||
'action': self.action,
|
||||
'status': self.status,
|
||||
'next': self.next,
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
from json import loads as json_parse, dumps as _json_stringify
|
||||
from socket import if_nametoindex
|
||||
from typing import Dict, List, Optional, Any
|
||||
from xml.dom.expatbuilder import parseString
|
||||
import paho.mqtt.client as mqtt
|
||||
from biopro.text import *
|
||||
from .task import Task
|
||||
|
||||
_RUNTIME_COMPILE = False
|
||||
|
||||
def json_stringify(o: Any) -> str:
|
||||
return _json_stringify(o, separators=(',', ':'))
|
||||
|
||||
class TaskManager():
|
||||
def __init__(self, task_list):
|
||||
self._task_list = []
|
||||
self._next_task = []
|
||||
self._prev_task = None
|
||||
self._running_task = None
|
||||
|
||||
self.load_task_list(task_list)
|
||||
|
||||
# self.set_running_task(self._task_list[0])
|
||||
# self._running_task.run()
|
||||
self._next_task.append(self._task_list[0])
|
||||
|
||||
@property
|
||||
def task_list(self):
|
||||
return self._task_list
|
||||
|
||||
@property
|
||||
def prev_task(self):
|
||||
return self._prev_task
|
||||
|
||||
@property
|
||||
def running_task(self):
|
||||
return self._running_task
|
||||
|
||||
@property
|
||||
def next_task(self):
|
||||
return self._next_task
|
||||
|
||||
@property
|
||||
def check_list(self):
|
||||
return [self._running_task, *self._next_task]
|
||||
|
||||
@property
|
||||
def check_list(self):
|
||||
return [self._running_task, *self._next_task]
|
||||
|
||||
def load_task_list(self, task_list):
|
||||
for task in task_list:
|
||||
task = Task(task)
|
||||
self._task_list.append(task)
|
||||
|
||||
def set_running_task(self, task):
|
||||
try:
|
||||
# if there is task running & same task active ,then reject
|
||||
if self._running_task != None and self._running_task.uuid == task.uuid:
|
||||
return False
|
||||
|
||||
# save running task
|
||||
self._prev_task = self._running_task
|
||||
# clear next task list
|
||||
self._next_task.clear()
|
||||
self._running_task = task
|
||||
self._running_task.run()
|
||||
|
||||
if self._prev_task != None:
|
||||
# if previous task is still running, then need to close
|
||||
if self._prev_task.status == 1:
|
||||
self._prev_task.stop()
|
||||
print('prev', 'run', self._prev_task.name, self._running_task.name)
|
||||
|
||||
for task_uuid in self._running_task.next:
|
||||
_task = next((task for task in self._task_list if task.uuid == task_uuid), None)
|
||||
if _task != None:
|
||||
self._next_task.append(_task)
|
||||
except RuntimeError as e:
|
||||
print(e)
|
||||
|
||||
def get_task(self, task_id):
|
||||
return self._task_list[task_id]
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -8,6 +8,7 @@ import gc
|
||||
|
||||
from biopro.util.json import JSON
|
||||
from biopro.util.stack import print_exception
|
||||
from biopro.util.logger import calculate_time
|
||||
from .data import RecordingData
|
||||
from .loader import *
|
||||
|
||||
@@ -19,6 +20,8 @@ from statistics import mean
|
||||
import random
|
||||
# from numba import jit
|
||||
|
||||
from copy import copy
|
||||
|
||||
def json_stringify(o) -> str:
|
||||
return _json_stringify(o, separators=(',', ':'))
|
||||
|
||||
@@ -370,6 +373,45 @@ class RecordingMetaFile(JsonSerialize):
|
||||
self._database.put_queue(['data_meta_write', meta_data, self._device_id, str(self._file_uuid), self._id_db])
|
||||
# database.put_queue(['data_meta_write', self, meta_data, _path, self._id_db])
|
||||
return None
|
||||
|
||||
def update_subfile_time_size(self, database = None):
|
||||
meta_data = {
|
||||
'channels': str(self._channel_mask.channels()),
|
||||
'size': str(self._size),
|
||||
'time_duration': str(self._last_time),
|
||||
'uuid': str(self._file_uuid),
|
||||
}
|
||||
_path = str(self._filepath).replace('/', '^')
|
||||
|
||||
if database is not None :
|
||||
self._database = database
|
||||
self._database.put_queue(['data_meta_write', meta_data, self._device_id, str(self._file_uuid), self._id_db])
|
||||
# database.put_queue(['data_meta_write', self, meta_data, _path, self._id_db])
|
||||
return None
|
||||
|
||||
def update_subfile_raw(self, database = None):
|
||||
meta_data = {
|
||||
'raw_data': self._recording_sub_file,
|
||||
}
|
||||
_path = str(self._filepath).replace('/', '^')
|
||||
|
||||
if database is not None :
|
||||
self._database = database
|
||||
self._database.put_queue(['data_meta_write', meta_data, self._device_id, str(self._file_uuid), self._id_db])
|
||||
# database.put_queue(['data_meta_write', self, meta_data, _path, self._id_db])
|
||||
return None
|
||||
|
||||
def update_subfile_mini(self, database = None):
|
||||
meta_data = {
|
||||
'mini_data': self._recording_sub_mini,
|
||||
}
|
||||
_path = str(self._filepath).replace('/', '^')
|
||||
|
||||
if database is not None :
|
||||
self._database = database
|
||||
self._database.put_queue(['data_meta_write', meta_data, self._device_id, str(self._file_uuid), self._id_db])
|
||||
# database.put_queue(['data_meta_write', self, meta_data, _path, self._id_db])
|
||||
return None
|
||||
|
||||
@property
|
||||
def filename(self) -> str:
|
||||
@@ -517,11 +559,6 @@ class RecordingMetaFile(JsonSerialize):
|
||||
'start_time': str(_start_time),
|
||||
}
|
||||
|
||||
# if database is not None:
|
||||
# database.data_raw_create(self, f, raw_data, _channel)
|
||||
|
||||
# self._recording_file_ch[_channel]
|
||||
|
||||
return f, raw_data
|
||||
|
||||
def new_recording_mini(self, _channel: int, _start_time, scale, database = None) -> 'RecordingMini':
|
||||
@@ -567,9 +604,6 @@ class RecordingMetaFile(JsonSerialize):
|
||||
'start_time': str(_start_time),
|
||||
}
|
||||
|
||||
# if database is not None:
|
||||
# database.data_mini_create(self, f, mini_data, _channel, scale)
|
||||
|
||||
return f, mini_data
|
||||
|
||||
def clear_recording_file(self):
|
||||
@@ -628,15 +662,6 @@ class RecordingMetaFile(JsonSerialize):
|
||||
'device': self._device,
|
||||
}
|
||||
|
||||
# d = self._device
|
||||
|
||||
# if d is not None:
|
||||
# ret['device'] = {
|
||||
# 'device_name': d.device_name,
|
||||
# 'device_address': list(d.mac_address),
|
||||
# 'serial_number': d.serial_number.as_json(),
|
||||
# }
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
@@ -792,14 +817,10 @@ class RecordingFile:
|
||||
'end_time': str(_end_time),
|
||||
'size': str(self._size)
|
||||
}
|
||||
# if self._meta_file._id_db == 0:
|
||||
# _path = str(self._meta_file.filepath).replace('/', '^')
|
||||
# self._database.put_queue(['data_meta_id_get_by_path', _path])
|
||||
# # self._meta_file._id_db = self._database.put_queue(['data_meta_id_get_by_path', _path])
|
||||
|
||||
if self._meta_file._id_db != 0:
|
||||
_data['parent'] = self._meta_file._id_db
|
||||
self._database.put_queue(['data_raw_update', self._id_db, self._channel, _data])
|
||||
# self._database.put_queue(['data_raw_update', self._id_db, self._channel, _data])
|
||||
self._status = False
|
||||
return None
|
||||
|
||||
@@ -965,10 +986,7 @@ class RecordingMini:
|
||||
'end_time': str(_end_time),
|
||||
'size': str(self._size)
|
||||
}
|
||||
# if self._meta_file._id_db == 0:
|
||||
# _path = str(self._meta_file.filepath).replace('/', '^')
|
||||
# self._database.put_queue(['data_meta_id_get_by_path', _path])
|
||||
# # self._meta_file._id_db = self._database.put_queue(['data_meta_id_get_by_path', _path])
|
||||
|
||||
if self._meta_file._id_db != 0:
|
||||
_data['parent'] = self._meta_file._id_db
|
||||
self._database.put_queue(['data_mini_update', self._id_db, self._channel, _data])
|
||||
@@ -996,7 +1014,8 @@ class RecordingFileWriter:
|
||||
'_data_value_ch', '_close', '_data_mini_ch',
|
||||
'_mini_scale_list', '_time_real_time', '_data_rl', '_data_db',
|
||||
'_raw_save', '_mini_save', '_data_time_ch', '_data_value_ch_for_rl',
|
||||
'_data_time_ch_for_rl', '_device_id', '_send_data', '_data_mqtt_ch')
|
||||
'_data_time_ch_for_rl', '_device_id', '_send_data', '_data_mqtt_ch', '_id_db_save', '_raw_create_not_done',
|
||||
'_mini_create_not_done')
|
||||
|
||||
def __init__(self, meta: RecordingMetaFile, device_id, database = None):
|
||||
self._meta = meta
|
||||
@@ -1017,7 +1036,9 @@ class RecordingFileWriter:
|
||||
|
||||
self._raw_save = {
|
||||
'id': {},
|
||||
'data': {}
|
||||
'data': {},
|
||||
'end_time': {},
|
||||
'size': {}
|
||||
}
|
||||
self._mini_save = {
|
||||
'10': {
|
||||
@@ -1052,6 +1073,7 @@ class RecordingFileWriter:
|
||||
self._data_value_ch_for_rl = {}
|
||||
self._data_time_ch_for_rl = {}
|
||||
self._data_time_ch = {}
|
||||
self._id_db_save = {}
|
||||
|
||||
# mini data
|
||||
self._data_mini_ch = {}
|
||||
@@ -1068,12 +1090,15 @@ class RecordingFileWriter:
|
||||
|
||||
# splitting
|
||||
self.splitting_threshold_time = 30 * 60 * 1000 # one minute
|
||||
self.splitting_threshold_size = 16 * 16 * 1024 # 16 * 16KB
|
||||
self.splitting_threshold_size = 16 * 1024 # 16 * 16KB
|
||||
|
||||
self._writer_batch_size = 8192
|
||||
|
||||
self._splitting_size = None
|
||||
|
||||
self._raw_create_not_done = True
|
||||
self._mini_create_not_done = True
|
||||
|
||||
|
||||
@property
|
||||
def meta_file(self) -> RecordingMetaFile:
|
||||
@@ -1123,7 +1148,7 @@ class RecordingFileWriter:
|
||||
self._meta._size += self._recording_file_dict[ch]._size
|
||||
# self._data_db.clear()
|
||||
if self._database is not None:
|
||||
self._database.put_queue(['data_raw_recording', self._raw_save['id'], self._channel_list, self._raw_save['data']])
|
||||
self._database.put_queue(['data_raw_recording', self._raw_save['id'], self._channel_list, self._raw_save['data'], self._id_db_save])
|
||||
# self._database.put_queue(['data_raw_recording', self._raw_save['id'], self._channel_list, self._raw_save['data']])
|
||||
self._recording_file_dict.clear()
|
||||
for scale in self._mini_scale_list:
|
||||
@@ -1289,7 +1314,8 @@ class RecordingFileWriter:
|
||||
self._data_db[c].append(str(v))
|
||||
self._time_now = int(t)
|
||||
return
|
||||
|
||||
|
||||
# @calculate_time(1)
|
||||
def write(self, data: Union[bytes, RecordingData, List[bytes], List[RecordingData]], mqtt_thread) -> int:
|
||||
# check size
|
||||
ths = self.splitting_threshold_size
|
||||
@@ -1348,42 +1374,54 @@ class RecordingFileWriter:
|
||||
|
||||
self.get_data_iter(d, mqtt_thread)
|
||||
|
||||
data_save = False
|
||||
mini_save = False
|
||||
if len(self._recording_file_dict) > 0:
|
||||
for ch in self._data_db.keys():
|
||||
if self._time_now - self._time_real_time[ch] > 1000000:
|
||||
self._send_data[ch] = True
|
||||
self._time_real_time[ch] = self._time_now
|
||||
# # if self._time_now - self._time_real_time[ch] > 500000:
|
||||
# self._data_rl[ch].append(str(self._time_now))
|
||||
# mes = ' '.join(self._data_rl[ch])
|
||||
# # print(mes)
|
||||
# # if mqtt_thread is not None:
|
||||
# # mqtt_thread.publish('data_server/device_data_stream/' + str(self._device_id) + '/' + str(ch), mes)
|
||||
# # mqtt_queue.put([self._device_id, ch, mes])
|
||||
# mqtt_thread[ch].on_message(mes)
|
||||
# self._data_rl[ch].clear()
|
||||
# # self._time_real_time[ch] = self._time_now
|
||||
|
||||
for ch in self._recording_file_dict:
|
||||
if self._recording_file_dict[ch]._id_db == 0:
|
||||
return None
|
||||
|
||||
for ch in self._data_db.keys():
|
||||
for scale in self._mini_scale_list:
|
||||
if self._recording_mini_dict[str(scale)][ch]._id_db == 0:
|
||||
return None
|
||||
|
||||
if self._raw_create_not_done :
|
||||
self._raw_create_not_done = False
|
||||
self._meta.update_subfile_raw(database = self._database)
|
||||
|
||||
if self._mini_create_not_done :
|
||||
self._mini_create_not_done = False
|
||||
self._meta.update_subfile_mini(database = self._database)
|
||||
|
||||
data_save = False
|
||||
mini_save = False
|
||||
if len(self._recording_file_dict) > 0:
|
||||
for ch in self._data_db.keys():
|
||||
if self._time_now - self._time[ch] > 5000000:
|
||||
if self._recording_file_dict[ch]._status:
|
||||
_data = ' '.join(self._data_db[ch])
|
||||
write_sz = self._recording_file_dict[ch].write(_data, self._channel_list)
|
||||
sz = sz + write_sz
|
||||
self._raw_save['data'][ch] = _data
|
||||
self._raw_save['id'][ch] = self._recording_file_dict[ch]._id_db
|
||||
data_save = True
|
||||
self._raw_save['end_time'][ch] = self._time_now
|
||||
self._raw_save['size'][ch] = self._recording_file_dict[ch]._size
|
||||
self._data_db[ch].clear()
|
||||
self._time[ch] = self._time_now
|
||||
self._splitting_size += sz
|
||||
self._meta._last_time = self._time_now
|
||||
self._recording_file_dict[ch].update_endtime(self._time_now)
|
||||
self._splitting_size += write_sz
|
||||
data_save = True
|
||||
if len(self._data_mini_ch[ch]['1000']['mean']) >= 10:
|
||||
mini_save = True
|
||||
for scale in self._mini_scale_list:
|
||||
str_mean = [str(int) for int in self._data_mini_ch[ch][str(scale)]['mean']]
|
||||
data_mean = str(self._data_mini_ch[ch][str(scale)]['start_time']) + ' ' + ' '.join(str_mean) + '"***"'
|
||||
self._mini_save[str(scale)]['id'][ch] = self._recording_mini_dict[str(scale)][ch]._id_db
|
||||
self._mini_save[str(scale)]['start_time'][ch] = str(self._data_mini_ch[ch][str(scale)]['start_time'])
|
||||
self._mini_save[str(scale)]['data_mean'][ch] = self._data_mini_ch[ch][str(scale)]['mean'].copy()
|
||||
self._mini_save[str(scale)]['data_mean'][ch] = data_mean
|
||||
# self._mini_save[str(scale)]['data_random'][ch] = self._data_mini_ch[ch][str(scale)]['random'].copy()
|
||||
# self._mini_save[str(scale)]['data_bar'][ch] = self._data_mini_ch[ch][str(scale)]['bar'].copy()
|
||||
self._recording_mini_dict[str(scale)][ch].write(self._mini_save[str(scale)]['data_mean'][ch])
|
||||
@@ -1394,26 +1432,25 @@ class RecordingFileWriter:
|
||||
|
||||
if data_save is True:
|
||||
if self._database is not None:
|
||||
self._database.put_queue(['data_raw_recording', self._raw_save['id'], self._channel_list, self._raw_save['data']])
|
||||
self._meta.update_subfile(database = self._database)
|
||||
recording_input = ['data_raw_recording_new', copy(self._raw_save['id']), copy(self._channel_list), copy(self._raw_save['data']), copy(self._raw_save['end_time']), copy(self._raw_save['size'])]
|
||||
self._database.put_queue(recording_input)
|
||||
self._meta.update_subfile_time_size(database = self._database)
|
||||
if mini_save is True:
|
||||
if self._database is not None:
|
||||
for scale in self._mini_scale_list:
|
||||
self._database.put_queue(['data_mini_recording', self._mini_save[str(scale)]['id'], self._channel_list, self._mini_save[str(scale)]['start_time'], self._mini_save[str(scale)]['data_mean']])
|
||||
self._meta.update_subfile(database = self._database)
|
||||
|
||||
|
||||
self._database.put_queue(['data_mini_recording_new', copy(self._mini_save[str(scale)]['id']), self._channel_list, copy(self._mini_save[str(scale)]['data_mean'])])
|
||||
self._meta.update_subfile_time_size(database = self._database)
|
||||
del data
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def _switch_recording_file(self):
|
||||
# if self._recording_file is not None:
|
||||
# self._recording_file.close()
|
||||
|
||||
self._raw_create_not_done = True
|
||||
|
||||
if len(self._recording_file_dict) > 0:
|
||||
for ch in self._recording_file_dict.keys():
|
||||
self._id_db_save[ch] = self._recording_file_dict[ch]._id_db
|
||||
self._recording_file_dict[ch].close(self._time_now)
|
||||
self._meta._size += self._recording_file_dict[ch]._size
|
||||
|
||||
@@ -1429,16 +1466,16 @@ class RecordingFileWriter:
|
||||
|
||||
if self._database is not None:
|
||||
self._database.put_queue(['data_raw_create', raw_data_dict, self._channel_list, self._device_id])
|
||||
# self._database.put_queue(['data_raw_create', self._meta, self._recording_file_dict, raw_data_dict, self._channel_list])
|
||||
|
||||
self._meta._last_time = self._time_now
|
||||
self._meta.update_subfile(database = self._database)
|
||||
# self._meta.update_subfile(database = self._database)
|
||||
|
||||
self._splitting_size = 0
|
||||
|
||||
return None
|
||||
|
||||
def _switch_recording_mini(self, scale):
|
||||
self._mini_create_not_done = True
|
||||
|
||||
if len(self._recording_mini_dict[str(scale)]) > 0:
|
||||
for ch in self._recording_mini_dict[str(scale)].keys():
|
||||
@@ -1456,14 +1493,12 @@ class RecordingFileWriter:
|
||||
|
||||
if self._database is not None:
|
||||
self._database.put_queue(['data_mini_create', mini_data_dict, self._channel_list, scale, self._device_id])
|
||||
# self._database.put_queue(['data_mini_create', self._meta, self._recording_mini_dict[str(scale)], mini_data_dict, self._channel_list, scale])
|
||||
|
||||
self._meta._last_time = self._time_now
|
||||
self._meta.update_subfile(database = self._database)
|
||||
# self._meta.update_subfile(database = self._database)
|
||||
return None
|
||||
|
||||
def update_meta_id(self, _id):
|
||||
# print('update meta')
|
||||
self._meta._id_db = _id
|
||||
return None
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user