Compare commits

..

54 Commits

Author SHA1 Message Date
peterlu14 13825fe9ff [update] hide print 2022-04-08 18:22:44 +08:00
peterlu14 dd2e31d01f [update] fix index problem 2022-04-08 18:16:31 +08:00
peterlu14 455fa1f86b [update] fix stop error & relative_time 2022-04-08 11:17:07 +08:00
Roy 71850b31a8 [update] fix recording error 2022-04-07 12:33:02 +08:00
peterlu14 8d52fef4c1 [update] hide print message 2022-04-07 12:29:18 +08:00
peterlu14 e091f220fa Merge branch 'test/update_data_server' into rel/v1.4.0_schedule/channel_lost_data 2022-03-28 18:19:29 +08:00
peterlu14 6049154fae [update] change check time to 1 2022-03-28 18:18:35 +08:00
peterlu14 3502472021 [update] recover update mini file 2022-03-28 17:27:04 +08:00
peterlu14 5e48c8ae0a [update] update_subfile change 2022-03-28 17:17:07 +08:00
peterlu14 cb2a4c9d56 Revert "[update] solve meta raw&mini id grwon up problem"
This reverts commit cd60e14cbe.
2022-03-28 16:14:23 +08:00
peterlu14 b253aca73f [update] meta_id & mini_id update 2022-03-28 16:12:15 +08:00
Roy 2fd05d18ed [update] fix battery value 2022-03-25 13:41:48 +08:00
Roy 03011ebd5f Merge branch 'dev/check_sum/battery' into rel/v1.4.0_schedule/channel_lost_data 2022-03-25 12:11:05 +08:00
Roy 4b9bc30e28 [update] get battery value 2022-03-25 11:46:40 +08:00
Roy 4966113393 [update] use check sum 2022-03-25 11:44:52 +08:00
Roy 3371c21bbd [update] update log message 2022-03-25 11:34:30 +08:00
Roy afc87829d9 [update] head != tailer, delete data 2022-03-24 17:12:06 +08:00
peterlu14 952403cbf4 [update] subfile 64kB -> 16kB 2022-03-21 14:20:29 +08:00
peterlu14 1cdd04901c [update] fix size count error & close error & remove comments 2022-03-21 14:13:33 +08:00
peterlu14 cd60e14cbe [update] solve meta raw&mini id grwon up problem 2022-03-21 12:01:38 +08:00
peterlu14 ae55e6c789 [update] remove print message 2022-03-18 17:21:53 +08:00
peterlu14 b8addb7686 [update] prevent data loss 2022-03-18 17:12:40 +08:00
Roy da581ae225 [update] update log message 2022-03-18 15:12:37 +08:00
peterlu14 a941f7c060 [update] prevent duplicate address data 2022-03-17 11:34:36 +08:00
Roy 4b0472ecf4 [update] fix error for real_run_time 2022-03-17 09:56:16 +08:00
Roy de51f53657 [update] update log message 2022-03-16 11:50:00 +08:00
Roy 6974950d31 Merge remote-tracking branch 'origin/dev/elite_channel_position_and_skip_ram' into rel/v1.4.0_schedule/channel_lost_data 2022-03-15 15:38:53 +08:00
peterlu14 0887c48ddc [remove] pyc file untracked 2022-03-15 15:33:02 +08:00
Roy 184c7536a6 [update] fix error for reading spi(7000bytes) 2022-03-15 15:18:52 +08:00
Roy 1a3a833680 [update] green data has 12 byte, if ram read done, MEM_INS_MARKED = [5A,A5] 2022-03-15 15:17:38 +08:00
Roy df3c7db8bc [update] fix spi routine code and print log message when run_time >= 0.030 2022-03-15 15:01:55 +08:00
Roy 7287f4c19b [update] update print message 2022-03-15 15:00:34 +08:00
Roy 7d3f7a47ff [update] change position of elite channel 2022-03-15 14:55:11 +08:00
peterlu14 81c699e830 [update] recover previous way to execute data 2022-03-14 16:45:27 +08:00
peterlu14 71e469ec2f Merge branch 'dev/merge_channel_lost_data' into rel/v1.4.0_schedule/channel_lost_data 2022-03-11 10:58:14 +08:00
peterlu14 e4bef30be2 [update] 256K -> 64K, 5s -> 2s, save id_db 2022-03-11 10:34:44 +08:00
peterlu14 96ec0a983f Merge branch 'test/project' into dev/merge_channel_lost_data 2022-03-07 16:57:53 +08:00
peterlu14 2dd19a575f [update] fix import path 2022-03-07 16:57:32 +08:00
Roy affacfddeb Merge remote-tracking branch 'origin/bug/channel_lost_data' into dev/merge_channel_lost_data 2022-03-07 11:59:19 +08:00
peterlu14 de8a6e58e4 [update] remove deleting data when commit 2022-03-07 10:48:44 +08:00
peterlu14 390da7b004 [update] improve mini recording 2022-03-04 18:02:24 +08:00
peterlu14 f8e41e9247 [update] data_dict remove last 2022-03-04 16:36:03 +08:00
peterlu14 1d96f49f63 [update] change commit transaction way 2022-03-04 14:06:44 +08:00
peterlu14 23a04d06c9 [update] temp save 2022-03-02 18:13:02 +08:00
peterlu14 7c3bc2d20b Merge remote-tracking branch 'origin/rel/v1.3.3' into test/project 2022-03-01 18:36:44 +08:00
peterlu14 01d1bd989c [update] temp push 2022-02-25 20:54:58 +08:00
peterlu14 1dffa29658 Merge remote-tracking branch 'origin/feature/project' into test/project 2022-02-21 14:29:22 +08:00
peterlu14 a0e8f9c6c4 [update] import path change & folder 2022-02-21 14:08:22 +08:00
peterlu14 416503f7fb [update] project first done push 2022-02-17 20:35:36 +08:00
peterlu14 be36bb785c [update] temp push 2022-02-14 19:19:54 +08:00
peterlu14 9560b9e0ef [update] temp save 2022-02-12 00:21:27 +08:00
peterlu14 07a1e0f5bc [update] temp push 2022-02-10 00:49:49 +08:00
peterlu14 a96837a462 [update] push 2022-02-08 20:12:44 +08:00
peterlu14 6b29f1f08e [update] add project 2022-02-07 20:27:30 +08:00
21 changed files with 1050 additions and 310 deletions
+4 -3
View File
@@ -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 []
+5
View File
@@ -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
+2 -1
View File
@@ -536,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
@@ -2035,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
+2 -1
View File
@@ -562,6 +562,7 @@ class DeviceManager(MasterDevice, Synchronized):
@logging_verbose
def get_device(self, device: Union[int, DeviceInfo]) -> Optional[CompletedDevice]:
print('get_device', device)
"""get connected device
:param device: device ID or response info
@@ -574,7 +575,7 @@ class DeviceManager(MasterDevice, Synchronized):
elif isinstance(device, str):
for slave in self._device:
if ':'.join('{:02x}'.format(b) 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):
+37 -37
View File
@@ -882,21 +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]
mem_wrong_information = struct.unpack('>i', data[40:40+4])[0]
# print('decode', list(data[20:]))
mem_wrong = data[40]
mem_retry_cnt = data[41]
mem_green_wrong = data[42]
mem_green_retry_cnt = data[43]
ram_num = data[44]
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):
@@ -917,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),
@@ -928,13 +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(mem_wrong_information),
# '|', '{: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
@@ -949,16 +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(4, ram_num)
ret.append_data(5, broken_flag)
ret.append_data(6, mem_wrong_information)
# ret.append_data(4, ram_num)
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
@@ -1456,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
+5
View File
@@ -1082,6 +1082,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*
+117 -43
View File
@@ -24,8 +24,10 @@ def zero_buffer(size: int) -> List[int]:
return [0] * size
class MultiExtMemSpiInterface(LowLevelHardwareInterface):
MEM_INS_MARKED = [MEM_INS_WRITE, 0, 2, 1, 1]
MEM_INS_RESET = [MEM_INS_WRITE, 0, 2, 1, 1, 0, 0xFF]
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]
__slots__ = ('_selector', '_wait_for_first_data', '_spi', '_tx_buffer_header', '_tx_buffer_data',
'pin_busy', 'pin_mem_req', 'pin_mem_sel', 'pin_ram_sel',
@@ -44,11 +46,11 @@ class MultiExtMemSpiInterface(LowLevelHardwareInterface):
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_header = [0] * 11
self._tx_buffer_header = [0] * 19
self._tx_buffer_data = [0] * (self._single_data_len * 10 + 3)
# memory control pin
@@ -165,6 +167,52 @@ class MultiExtMemSpiInterface(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)
@@ -191,7 +239,7 @@ class MultiExtMemSpiInterface(LowLevelHardwareInterface):
self._head_wrong_cnt[device] = self._head_wrong_cnt[device] + 1
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[0:7]))
print(list(data))
data[0:3] = [255, 255, 255]
# ----------------------------------------------------------------------------------------------
@@ -210,13 +258,13 @@ class MultiExtMemSpiInterface(LowLevelHardwareInterface):
# 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:', device, ',', self._head_wrong_cnt[device], 'times')
# print(list(data_first[0:7]))
# 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:', device, ',', self._head_wrong_cnt[device], 'times')
# print(list(data_second[0:7]))
# print(list(data_second))
# if (data_first[3:] == data_second[3:]):
# data = data_first
@@ -228,59 +276,47 @@ class MultiExtMemSpiInterface(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
@@ -319,22 +355,60 @@ class MultiExtMemSpiInterface(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)
View File
+68
View File
@@ -0,0 +1,68 @@
class Action():
def __init__(self, task, action_id, action):
self._task = task
self._id:str = action_id
self._type:str = action['type']
self._target:str = action['target']
self._condition_list:list[str] = action['condition']
self._duration = action.get('duration', None)
self._goto = action.get('goto', None)
self._cycle = action.get('cycle', None)
self._instruction = None
self.update_instruction()
@property
def type(self):
return self._type
def update_instruction(self):
instruction_type = self._type
if instruction_type == 'stop':
instruction_type = 'interrupt'
self._instruction = {
"device_instruction": {
"header": "call_instruction",
"device": self._target,
"arguments": {
"instruction": instruction_type,
}
},
"device_parameter": {
"header": "set_multi_parameters",
"device": self._target,
"arguments": {
"parameter": self._task.get_parameter_set_by_device(self._target),
}
},
"device_recording_file_name": {
"header": "update_recording_file_name_info",
"device": self._target,
"arguments": {
"content": self._task.file_name,
}
},
"device_parent": {
"header": "update_parent_info",
"device": self._target,
"arguments": {
"content": self._task.parent
}
}
}
def get_condition_list(self):
return self._condition_list
def get_instruction(self, value):
return self._instruction[value]
def get_instruction_list(self):
instruction_set = {
'start': ['device_parent', 'device_recording_file_name', 'device_parameter', 'device_instruction'],
'stop': ['device_instruction'],
}
return map(self.get_instruction, instruction_set[self._type])
+83
View File
@@ -0,0 +1,83 @@
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']
@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
def set_comparsion(self, comparsion):
self._comparsion = comparsion
def set_type(self, type):
self._type = type
def set_value(self, value):
self._value = value
def compareWith(self, operator:str, x, y) -> bool:
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 = time()
time_condition = self.datetime_to_timestamp(self.str_to_datetime(self._value))
return self.compareWith(self.comparsion, int(now), int(time_condition))
def relative_time(self, **kwargs):
project_start_time = kwargs['project_start_time']
task_start_time = kwargs['task_start_time']
delay_time = kwargs['delay_time']
now = time()
time_diff = int(now - project_start_time - delay_time)
return self.compareWith(self.comparsion, time_diff, int(self._value))
def device(self, **kwargs):
print('device')
def task_status(self, **kwargs):
print('task_status')
def method_mapping(self, method_name):
methods = {
"relative_time": self.relative_time,
"absolute_time": self.absolute_time,
"device": self.device,
"task_status": self.task_status,
}
return methods[method_name]
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)
+82
View File
@@ -0,0 +1,82 @@
from .task import Task
from .task_manager import TaskManager
import sys
import json
import threading
import time
from datetime import datetime
from collections import deque
from biopro.device.manager import DeviceManager
from biopro.text import *
from copy import copy
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._task_manager = TaskManager(self._project['taskList'])
self._stop = False
@property
def desc(self) -> str:
return self._project['desc']
@property
def status(self) -> str:
return self._project['status']
@property
def device(self) -> list:
return self._project['deviceList']
@property
def task(self) -> list:
return self._task_manager.get()
@property
def get_current_task(self) -> str:
return self._task_manager.get_current_task()
def run(self):
self._start_time = time.time()
while not self._stop:
# current task
task_check_list = copy(self._task_manager.get_check_task_list())
delay_time = 0
for task in task_check_list:
# [<match_condition>, ...]
match_condition_list = task.check_condition(project_start_time = self._start_time, delay_time = delay_time)
# [[<match_action>, ...], ...]
match_action_list = task.get_match_action_list(match_condition_list)
for action_list in match_action_list:
for action in action_list:
if action.type == 'start':
task.reset_start_time()
self._task_manager.set_current_task(task)
task.do_action(action)
now = time.time()
while len(task.instruction_list) > 0:
instruction = task.instruction_list.pop(0)
if instruction.get('device', None) != None:
device = self._device_manager.get_device(self.device[instruction['device']]['connectDevice']['device_address'])
if device is None:
raise RuntimeError(DEVICE_NOT_FOUND, device)
getattr(device, instruction['header'])(*instruction['arguments'].values())
delay_time += (time.time() - now)
time.sleep(self._time_interval)
def stop(self):
self._stop = True
def close(self):
self._stop = True
+33
View File
@@ -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()
+169
View File
@@ -0,0 +1,169 @@
from typing import List
from .condition import Condition
from .action import Action
from time import time
class Task:
def __init__(self, task):
self._task = task
self._condition_list:List[Condition] = []
self._action_list:List[Action] = []
self._start_time = time()
self._idle_time = []
self._period = None
self._next_time = None
self._last_time = None
self._instruction_list = []
self.setup()
def setup(self) -> None:
# add condition
for key, condition in self._task['condition'].items():
new_condition = Condition(key, condition)
self._condition_list.append(new_condition)
# add action
for key, action in self._task['action'].items():
new_action = Action(self, key, action)
self._action_list.append(new_action)
@property
def id(self) -> str:
return self._task['id']
@property
def file_name(self):
return self._task['name']
@property
def parent(self):
return self._task.get('parent', {"folder": [2]})
@property
def instruction_list(self):
return self._instruction_list
@property
def cycle(self) -> int:
return self._task['cycle']
@property
def order(self) -> int:
return self._task['order']
@property
def max_cycle(self) -> int:
return self._task['max_cycle']
@property
def devices(self) -> dict:
return self._task['devices']
@property
def devices_id(self) -> list:
return [device_id for device_id in self.devices]
@property
def events(self) -> list:
return self._task['events']
@property
def triggers(self) -> list:
return self._task['triggers']
@property
def parameter_set(self) -> list:
return self._task['parameterSet']
@property
def instructions(self) -> list:
return self._task['instructions']
@property
def conditions(self) -> list:
return self._task['conditions']
@property
def actions(self) -> list:
return self._task['actions']
@property
def condition_list(self) -> list:
return self._condition_list
@property
def status(self) -> str:
return self._task['status']
@property
def uuid(self) -> str:
return self._task['uuid']
@property
def next(self) -> str:
return self._task['next']
def reset_start_time(self):
self._start_time = 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):
self._status = 'running'
self._start_time = time()
def pause(self):
self._status = 'pause'
def set_cycle(self, cycle):
self._cycle = cycle
def set_status(self, status):
self._status = status
def start(self):
self.set_status('running')
def stop(self):
if self.status == 'running':
self.do_action('stop')
self.set_status('idle')
def done(self):
self.set_status('done')
def end(self):
self.set_status('end')
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 do_action(self, action):
for instruction in action.get_instruction_list():
self._instruction_list.append(instruction)
def status_mapping(self, status):
statuses = {
"start": self.task_start,
"done": self.task_done,
}
return statuses[status]
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)]
+56
View File
@@ -0,0 +1,56 @@
from json import loads as json_parse, dumps as _json_stringify
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._current_task = None
self._task_list = []
self._need_to_check_task_list = []
for task in task_list:
task = Task(task)
self._task_list.append(task)
self.set_current_task(self._task_list[0])
self._current_task.run()
def remove(self, index):
pass
def get_task(self, task_id):
return self._task_list[task_id]
def get_check_task_list(self) -> List[Task]:
return self._need_to_check_task_list
def get_current_task(self) -> Task:
return self._current_task
def get_next_task(self):
return self._current_task.next
def set_current_task(self, task):
try:
if self._current_task != None and self._current_task.id != task.id:
self._current_task.stop()
self._current_task = task
self._need_to_check_task_list = []
# append current task
self._need_to_check_task_list.append(self._current_task)
# append next task
for task_uuid in self._current_task.next:
task = next((task for task in self._task_list if task.uuid == task_uuid), None)
self._need_to_check_task_list.append(task)
except Exception as e:
print(e)
+97 -62
View File
@@ -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
+3
View File
@@ -1335,3 +1335,6 @@ def to_device_info(content: Union[str, ADDRESS, JSON_OBJECT]) -> DeviceResponseI
return DeviceResponseInfo(None,
serial_number=serial,
mac_address=address)
def run_project(self, project) -> bool:
return False
+11 -11
View File
@@ -1179,20 +1179,20 @@ class SpiRuntimeThread(ServerThread):
run_time = time() - self._timer
real_run_time = run_time
if run_time > 0.045:
print('time, recv_data_form_spi_routine_time', time(), run_time)
# print('time, recv_data_form_spi_routine_time', time(), run_time)
run_time = 0.045
if server.sync_started:
event.wait(self._interval - run_time)
sync.set_pin_mem_sel(True)
sleep(0.005)
return
else:
event.wait(self._interval - run_time)
sync.set_pin_mem_sel(True)
self.close()
return
if run_time >= 0.030:
print('time, recv_data_form_spi_routine_time >= 0.030', 'device:', c, datetime.now(), time(), real_run_time)
event.wait(self._interval - run_time)
sync.set_pin_mem_sel(True)
sleep(0.005)
return
class RecRuntimeThread(ServerThread):
def __init__(self, server: DataServer):
+162 -81
View File
@@ -15,13 +15,15 @@ from biopro.util.json import JSON_OBJECT
from .socket import ServerThread
import psycopg2
# from psycopg2.pool import ThreadedConnectionPool
from psycopg2.extras import execute_batch
from multiprocessing import Process, Queue
import biopro.server._identify
from time import time
from concurrent.futures import ThreadPoolExecutor, as_completed
from biopro.util.logger import calculate_time
_RUNTIME_COMPILE = False
@@ -50,7 +52,7 @@ class DataBaseProcess(Process):
self._api_token = None
self._api_header = None
self.log_verbose = log_verbose
self._executor = ThreadPoolExecutor(max_workers=4)
self._executor = ThreadPoolExecutor(max_workers=8)
self._psql_multi_thread = None
self._psql_conn_pool = None
@@ -62,6 +64,14 @@ class DataBaseProcess(Process):
self._is_close = False
self._meta_write_sql_str = None
self._data_raw_create_sql_str = None
self._data_raw_update_sql_str = None
self._data_raw_recording_sql_str = 'UPDATE "public"."%s_recording_data_raws" SET data = concat(data, %s), end_time=%s, size=%s where id = %s'
self._data_mini_recording_sql_str = 'UPDATE "public"."%s_recording_data_minis" SET data_mean = concat(data_mean, %s) where id = %s'
@property
def db_host(self) -> str:
return self._db_host
@@ -149,7 +159,8 @@ class DataBaseProcess(Process):
if callable(getattr(self, do)):
getattr(self, do)(*args)
return None
# @calculate_time(1)
def data_meta_write(self, _data: JSON_OBJECT, device_id, _uuid = None, _id = None):
if _id > 0:
sql_str = 'UPDATE "public"."recording_data_metas" SET '
@@ -252,6 +263,7 @@ class DataBaseProcess(Process):
# _conn.close()
return None
# @calculate_time()
def data_meta_get(self, _path = None, _id = None):
if _id is not None:
sql_str = 'SELECT * FROM "public"."recording_data_metas" WHERE id = %s'
@@ -286,6 +298,7 @@ class DataBaseProcess(Process):
# _conn.close()
return None
# @calculate_time()
def data_meta_id_get_by_path(self, _path = None):
ret = None
if _path is not None:
@@ -307,39 +320,29 @@ class DataBaseProcess(Process):
# _conn.close()
return None
# @calculate_time()
def data_raw_create(self, _data_dict, _channel_list, device_id):
for _channel in _channel_list:
sql_str = 'INSERT INTO "public"."' + str(_channel) + '_recording_data_raws" ('
sql_set = []
for item in _data_dict[_channel].keys():
sql_str = sql_str + str(item) + ', '
if isinstance(_data_dict[_channel][item], dict):
sql_set.append(json_stringify(_data_dict[_channel][item]))
else:
sql_set.append(str(_data_dict[_channel][item]))
sql_str = sql_str[0:-2] + ') VALUES ('
for item in _data_dict[_channel].keys():
sql_str = sql_str + '%s, '
sql_str = sql_str[0:-2] + ') RETURNING id'
sql_cursor = self._psql_conn.cursor()
try:
sql_cursor.execute(sql_str, sql_set)
except RuntimeError as e:
print('data_raw_create error', e)
self._psql_conn.commit()
sql_cursor.close()
self._queue_error.put(device_id)
finally:
self._queue_ds[int(device_id)].put(['update_raw_dict_id', _data_dict[_channel]['uuid'], _channel, int(sql_cursor.fetchone()[0])])
self._psql_conn.commit()
sql_cursor.close()
if self._data_raw_create_sql_str == None:
sql_str_list = []
key_list = _data_dict[_channel_list[0]].keys()
key_str = ','.join(key_list)
values = ','.join(['%s'] * len(key_list))
sql_str_list = ['INSERT INTO "public"."{channel}_recording_data_raws" (', key_str, ') VALUES (', values, ') RETURNING id']
self._data_raw_create_sql_str = ''.join(sql_str_list)
try:
with self._psql_conn as conn:
with conn.cursor() as sql_cursor:
for _channel in _channel_list:
sql_set = list(map(lambda x: str(x), _data_dict[_channel].values()))
sql_cursor.execute(self._data_raw_create_sql_str.format(channel = _channel), sql_set)
self._queue_ds[int(device_id)].put(['update_raw_dict_id', _data_dict[_channel]['uuid'], _channel, int(sql_cursor.fetchone()[0])])
except (psycopg2.Error, RuntimeError) as e:
print('data_raw_create error', e)
self._queue_error.put(device_id)
return True
# @calculate_time()
def data_raw_update(self, _id, _channel, _data: JSON_OBJECT):
sql_str = 'UPDATE "public"."' + str(_channel) + '_recording_data_raws" SET '
sql_set = []
@@ -357,30 +360,36 @@ class DataBaseProcess(Process):
sql_cursor.execute(sql_str, sql_set)
self._psql_conn.commit()
sql_cursor.close()
return None
def data_raw_recording(self, _id_dict, _channel_list, _data_dict):
for _channel in _channel_list:
compressed_value = _data_dict[_channel] + '"***"'
# compressed_value = bytes(_data_dict[_channel],'utf-8')
# compressed_value = zlib.compress(compressed_value)
# compressed_value = base64.b64encode(compressed_value).decode() + '"***"'
# compressed_value = _data + '"***"'
sql_str = 'UPDATE "public"."' + str(_channel) + '_recording_data_raws" SET data = concat(data, %s) where id = %s'
sql_set = [compressed_value, _id_dict[_channel]]
sql_cursor = self._psql_conn.cursor()
sql_cursor.execute(sql_str, sql_set)
self._psql_conn.commit()
sql_cursor.close()
del _data_dict[_channel]
del compressed_value
gc.collect()
# _conn.close()
# @calculate_time()
def data_raw_recording(self, _id_dict, _channel_list, _data_dict, _id_db_save):
try:
with self._psql_conn as conn:
with conn.cursor() as sql_cursor:
para_list = []
for _channel in _channel_list:
temp_id = _id_dict[_channel] if _id_dict[_channel] != 0 else _id_db_save[_channel]
para_list.append([_channel, _data_dict[_channel] + '"***"', temp_id])
execute_batch(sql_cursor, self._data_raw_recording_sql_str, para_list)
except psycopg2.Error as e:
print('recording error', e)
return None
# @calculate_time(1)
def data_raw_recording_new(self, _id_dict, _channel_list, _data_dict, _end_time_dict, _size_dict):
try:
para_list = []
for _channel in _channel_list:
para_list.append([_channel, _data_dict[_channel] + '"***"', _end_time_dict[_channel], _size_dict[_channel], _id_dict[_channel]])
with self._psql_conn as conn:
with conn.cursor() as sql_cursor:
execute_batch(sql_cursor, self._data_raw_recording_sql_str, para_list)
except psycopg2.Error as e:
print('recording error', e)
return None
# @calculate_time()
def data_mini_create(self, _data_dict, _channel_list, _scale, device_id):
for _channel in _channel_list:
sql_str = 'INSERT INTO "public"."' + str(_channel) + '_recording_data_minis" ('
@@ -414,42 +423,43 @@ class DataBaseProcess(Process):
# _conn.close()
return True
# @calculate_time()
def data_mini_recording(self, _id_dict, _channel_list, _start_time_dict, _data_mean_dict):
for _channel in _channel_list:
data = _data_mean_dict.get(_channel)
if data is not None:
if len(data) != 0:
str_mean = [str(int) for int in _data_mean_dict[_channel]]
data_mean = _start_time_dict[_channel] + ' ' + ' '.join(str_mean)
# data_random = _start_time_dict[_channel] + ' ' + ' '.join(_data_random_dict[_channel])
# data_bar = _start_time_dict[_channel] + ' ' + ' '.join(_data_bar_dict[_channel])
with self._psql_conn as conn:
with self._psql_conn.cursor() as sql_cursor:
for _channel in _channel_list:
data = _data_mean_dict.get(_channel)
if data is not None:
if len(data) != 0:
str_mean = [str(int) for int in _data_mean_dict[_channel]]
data_mean = _start_time_dict[_channel] + ' ' + ' '.join(str_mean)
compressed_mean = data_mean + '"***"'
# compressed_mean = bytes(data_mean,'utf-8')
# compressed_mean = zlib.compress(compressed_mean)
# compressed_mean = base64.b64encode(compressed_mean).decode() + '"***"'
# compressed_random = bytes(data_bar,'utf-8')
# compressed_random = zlib.compress(compressed_random)
# compressed_random = base64.b64encode(compressed_random).decode() + '"***"'
# compressed_random = bytes(data_random,'utf-8')
# compressed_random = zlib.compress(compressed_random)
# compressed_random = base64.b64encode(compressed_random).decode() + '"***"'
sql_str = 'UPDATE "public"."' + str(_channel) + '_recording_data_minis" SET data_mean = concat(data_mean, %s) where id = %s'
sql_set = [compressed_mean, _id_dict[_channel]]
sql_cursor = self._psql_conn.cursor()
sql_set = [data_mean + '"***"', _id_dict[_channel]]
sql_cursor.execute(sql_str, sql_set)
self._psql_conn.commit()
sql_cursor.close()
del str_mean, _start_time_dict[_channel], _data_mean_dict[_channel], data_mean, compressed_mean
gc.collect()
del str_mean, data_mean
for _channel in _channel_list:
del _start_time_dict[_channel], _data_mean_dict[_channel]
gc.collect()
return True
# @calculate_time(1)
def data_mini_recording_new(self, _id_dict, _channel_list, _data_mean_dict):
try:
para_list = []
for _channel in _channel_list:
para_list.append([_channel, _data_mean_dict[_channel], _id_dict[_channel]])
with self._psql_conn as conn:
with conn.cursor() as sql_cursor:
execute_batch(sql_cursor, self._data_mini_recording_sql_str, para_list)
except psycopg2.Error as e:
print('recording error', e)
return None
# @calculate_time()
def data_mini_update(self, _id, _channel, _data: JSON_OBJECT):
sql_str = 'UPDATE "public"."' + str(_channel) + '_recording_data_minis" SET '
sql_set = []
@@ -469,3 +479,74 @@ class DataBaseProcess(Process):
sql_cursor.close()
return True
def data_meta_update_raw_empty_channel(self, meta_id, channel_list):
try:
sql_str = "UPDATE recording_data_metas SET raw_data = jsonb_set(raw_data, '{%s}', '[]'), mini_data = jsonb_set(mini_data, '{%s}', '{\"10\": [], \"100\": [], \"1000\": []}') WHERE id = %s;"
sql_set = []
for channel in channel_list:
sql_set.append([channel, channel, meta_id])
with self._psql_conn as conn:
with conn.cursor() as sql_cursor:
execute_batch(sql_cursor, sql_str, sql_set)
except psycopg2.Error as e:
print('e', e)
return True
# @calculate_time()
def data_meta_update_channel_raw_id(self, meta_id, channel, raw_id):
try:
with self._psql_conn as conn:
with conn.cursor() as sql_cursor:
sql_str = "UPDATE recording_data_metas SET raw_data = jsonb_insert(raw_data, '{%s, -1}', '%s', TRUE) WHERE id = %s;"
sql_set = [channel, raw_id, 571]
sql_cursor.execute(sql_str, sql_set)
except psycopg2.Error as e:
print('e', e)
return True
# @calculate_time()
def data_meta_update_all_channel_raw_id(self, meta_id:str, raw_id_dict:dict):
try:
sql_str = "UPDATE recording_data_metas SET raw_data = jsonb_insert(raw_data, '{%s, -1}', '%s', TRUE) WHERE id = %s;"
sql_set = []
for ch in raw_id_dict.keys():
sql_set.append([ch, raw_id_dict[ch], meta_id])
with self._psql_conn as conn:
with conn.cursor() as sql_cursor:
execute_batch(sql_cursor, sql_str, sql_set)
except psycopg2.Error as e:
print('e', e)
return True
def data_meta_update_channel_mini_id(self, meta_id, channel, scale, mini_id):
try:
with self._psql_conn as conn:
with conn.cursor() as sql_cursor:
sql_str = "UPDATE recording_data_metas SET mini_data = jsonb_insert(mini_data, '{%s, %s, -1}', '%s', TRUE) WHERE id = %s;"
sql_set = [channel, scale, mini_id, meta_id]
sql_cursor.execute(sql_str, sql_set)
except psycopg2.Error as e:
print('e', e)
return True
# @calculate_time()
def data_meta_update_all_channel_mini_id(self, meta_id, mini_id_dict):
try:
sql_str = "UPDATE recording_data_metas SET mini_data = jsonb_insert(mini_data, '{%s, %s, -1}', '%s', TRUE) WHERE id = %s;"
sql_set = []
for ch in mini_id_dict.keys():
for scale in mini_id_dict[ch].keys():
sql_set.append([ch, scale, mini_id_dict[ch][scale], meta_id])
with self._psql_conn as conn:
with conn.cursor() as sql_cursor:
execute_batch(sql_cursor, sql_str, sql_set)
except psycopg2.Error as e:
print('e', e)
return True
+14 -1
View File
@@ -30,6 +30,7 @@ from .api import ApiRequests
from biopro.api.auth import AuthAPI
from biopro.api.controller import ControllerAPI
from biopro.api.device import DeviceAPI
from biopro.project.project_manager import ProjectManager
### do not import Websocket mode
###from .websocket import WebsocketThread
@@ -154,7 +155,8 @@ class ControlServer(SocketServer, ControlServerAPI, CacheAPI, CacheNotifyHandler
# _api request build
self._api = ApiRequests()
self._project_manager = ProjectManager(self.device_manager, self.mqtt_thread)
# init method
@@ -193,6 +195,11 @@ class ControlServer(SocketServer, ControlServerAPI, CacheAPI, CacheNotifyHandler
def device_manager(self) -> DeviceManager:
return self._device_manager
@property
def project_manager(self) -> ProjectManager:
return self._project_manager
# server setup
def setup(self) -> None:
@@ -1319,6 +1326,12 @@ class ControlServer(SocketServer, ControlServerAPI, CacheAPI, CacheNotifyHandler
# p = self.exp_manager.create_protocol(content, user_name)
return
@logging_info
def run_project(self, project) -> bool:
project = self._project_manager.create(project)
self._project_manager.run(project)
return False
# @logging_info
# def exp_pro_options(self, protocol: int) -> List[ExpOption]:
# return self.exp_manager.protocol_options(protocol)
+85 -70
View File
@@ -98,6 +98,11 @@ class RecordingProcess(Process):
self._last_cnt = [-1, -1, -1, -1, -1, -1, -1, -1]
self._wrong_cnt = 0
# elite data length
self._elite_data_len = 40
self._mem_header_len = 3
self._mem_tailer_len = 6
self._single_data_len = self._elite_data_len + self._mem_header_len + self._mem_tailer_len
def ensure_data_format(self) -> DataDecodeFormat:
if isinstance(self._data_format, (str, bytes)):
@@ -160,7 +165,11 @@ class RecordingProcess(Process):
"""
q = None
try:
# now = time()
q = self._queue_rec.get()
# get_queue_time_cost = time() - now
# if get_queue_time_cost > 2:
# print('get queue cost time', get_queue_time_cost)
except:
return False
finally:
@@ -186,7 +195,7 @@ class RecordingProcess(Process):
current_time = time()
if self._timer is not None:
if current_time - self._timer > 1.5:
print('time, sync_data routine_time', current_time, current_time - self._timer)
print('time, sync_data routine_time', 'device:', self._device, datetime.now(), current_time, current_time - self._timer)
self._isTimeOut = True
self._timer = current_time
@@ -286,6 +295,7 @@ class RecordingProcess(Process):
self._last_cnt[7] = head_counter - 1
last_data_cnt = self._last_cnt[7]
# dont save to section when head or id is wrong
if (head != 255 or device_id != device):
save = False
last_data_cnt = last_data_cnt + 1
@@ -328,61 +338,57 @@ class RecordingProcess(Process):
return save
def _check_jump_ram(self, raw_data: bytes, colum_now: int, colum_total: int, save: bool, device: int):
i = colum_now
def _check_jump_ram(self, raw_data: bytes, colum_now: int, colum_total: int, save: bool, device: int, data_len: int):
col = colum_now
save = False
if (raw_data[i][0] == 255 and raw_data[i][3] == device):
if colum_total < 3:
print('this ram data < 3 records, need to fix, colum_total = ', colum_total)
if colum_total == 1:
print('raw_data[0]', raw_data[0])
if raw_data[col][0] != 255 or raw_data[col][3] != device:
return save
elif colum_total == 2:
print('raw_data[0]', raw_data[0])
print('raw_data[1]', raw_data[1])
if colum_total == 1:
print('this ram data < 3 records, colum_total = ', colum_total)
print('raw_data[0]', raw_data[0])
return save
else:
elif colum_total == 2:
print('this ram data < 3 records, colum_total = ', colum_total)
print('raw_data[0]', raw_data[0])
print('raw_data[1]', raw_data[1])
if (raw_data[col + 1][1] - raw_data[col][1] == 1) or (raw_data[col][1] == 255 and raw_data[col + 1][1] == 0):
save = True
if((raw_data[i + 1][1] - raw_data[i][1] == 1 and raw_data[i + 2][1] - raw_data[i + 1][1] == 1) or
(raw_data[i][1] == 255 and raw_data[i + 1][1] == 0 and raw_data[i + 2][1] == 1) or
(raw_data[i][1] == 254 and raw_data[i + 1][1] == 255 and raw_data[i + 2][1] == 0)):
elif colum_total >= 3:
if (raw_data[col + 1][1] - raw_data[col][1] == 1 and raw_data[col + 2][1] - raw_data[col + 1][1] == 1) or\
(raw_data[col][1] == 255 and raw_data[col + 1][1] == 0 and raw_data[col + 2][1] == 1) or\
(raw_data[col][1] == 254 and raw_data[col + 1][1] == 255 and raw_data[col + 2][1] == 0):
save = True
if ((raw_data[i][1] == 255 and raw_data[i + 1][1] == 0 and raw_data[i + 2][1] == 1) or
(raw_data[i][1] == 254 and raw_data[i + 1][1] == 255 and raw_data[i + 2][1] == 0)):
print('cnt = [254, 255, 0] or [255, 0, 1]')
if save == True:
self._skip_ram_cnt += 1
last_data_cnt = raw_data[col][1]
if (device == 4):
print('self._last_cnt[4]:', self._last_cnt[4], ', last_data_cnt:', last_data_cnt)
if (device == 5):
print('self._last_cnt[5]:', self._last_cnt[5], ', last_data_cnt:', last_data_cnt)
if (device == 6):
print('self._last_cnt[6]:', self._last_cnt[6], ', last_data_cnt:', last_data_cnt)
if (device == 7):
print('self._last_cnt[7]:', self._last_cnt[7], ', last_data_cnt:', last_data_cnt)
print('skip RAM, but data is right, solve data', list(raw_data[col][0:3]),'|', list(raw_data[colum_total-1][0:3]), 'skip Ram', self._skip_ram_cnt, 'times \n')
save = True
self._skip_ram_cnt += 1
last_data_cnt = raw_data[i][1]
if (device == 4):
print('self._last_cnt[4]:', self._last_cnt[4], ', last_data_cnt:', last_data_cnt)
if (device == 5):
print('self._last_cnt[5]:', self._last_cnt[5], ', last_data_cnt:', last_data_cnt)
if (device == 6):
print('self._last_cnt[6]:', self._last_cnt[6], ', last_data_cnt:', last_data_cnt)
if (device == 7):
print('self._last_cnt[7]:', self._last_cnt[7], ', last_data_cnt:', last_data_cnt)
print('skip RAM, but data is right, solve data', list(raw_data[i][0:3]), 'skip Ram', self._skip_ram_cnt, 'times')
# print('data:')
# print('|', list(raw_data[0]))
# print('|', list(raw_data[1]))
# print('| ... ... ...')
# print('| ... ... ...')
# print('|', list(raw_data[colum_total-1]))
print()
if (device == 4):
self._last_cnt[4] = last_data_cnt
if (device == 4):
self._last_cnt[4] = last_data_cnt
elif (device == 5):
self._last_cnt[5] = last_data_cnt
elif (device == 5):
self._last_cnt[5] = last_data_cnt
elif (device == 6):
self._last_cnt[6] = last_data_cnt
elif (device == 6):
self._last_cnt[6] = last_data_cnt
elif (device == 7):
self._last_cnt[7] = last_data_cnt
elif (device == 7):
self._last_cnt[7] = last_data_cnt
return save
def _neu_foreach_data_section(self, data: bytes):
@@ -497,50 +503,59 @@ class RecordingProcess(Process):
:return:
"""
raw_data = []
index = 0
elite_data_len = 40
mem_header_len = 3
mem_tailer_len = 8
single_data_len = elite_data_len + mem_header_len + mem_tailer_len
device = self._device
records = 0
print_flag = False
device = self._device
single_data_len = self._single_data_len
mem_header_len = self._mem_header_len
# packet section data use two microarray
for i in range(0, len(data), single_data_len):
index = index + 1
for j in range(index, index + 1):
raw_data.append(data[i : i + single_data_len])
records = records + 1
raw_data.append(data[i : i + single_data_len])
if len(data[i : i + 10]) < 10:
print('data dont be package:', raw_data[records - 1], 'index:', records - 1)
del raw_data[records - 1]
records = records - 1
# check cnt
for i in range(index):
for i in range(records):
# if jump cnt, don't save data
save = self._check_cnt(raw_data[i], device)
# # if jump Ram, also can handle data
if save == False:
save = self._check_jump_ram(raw_data, i, index, save, device)
save = self._check_jump_ram(raw_data, i, records, save, device, single_data_len)
if (save == True):
section = raw_data[i]
if (section[0 : mem_header_len] == section[single_data_len - 3: single_data_len]):
section = section + b'\x00'
else:
check_sum = sum(section[0 : single_data_len - 1]) & 0b11111111
if (check_sum != section[single_data_len - 1]):
print('check number not match,',
list(section[0 : mem_header_len]), section[-1], '!=', check_sum, 'device:', device, ',', datetime.now())
if (i-1 >= 0):
print('check number not match', list(raw_data[i-1]), 'raw:', i-1)
print('check number not match', list(raw_data[i]), 'raw:', i)
if (i+1 <= records):
print('check number not match', list(raw_data[i+1]), 'raw:', i+1, '\n')
section = section + b'\x01'
print('header != tailer,',
list(section[0 : mem_header_len]),
list(section[single_data_len - 3: single_data_len]),
'device:', device, ',', datetime.now())
print('header != tailer', list(section), '\n')
section = section[3:]
print('delete data:', list(raw_data[i][0:3]), 'raw:', i, '\n')
continue
else:
section = section + b'\x00'
# section = section[3:]
yield None, section
else:
print_flag = True
print('delete data:', list(raw_data[i]))
print('delete data:', list(raw_data[i][0:3]), 'raw:', i, '\n')
# if print_flag:
# print('delete data context:')
+15
View File
@@ -3,6 +3,7 @@ import inspect
import os
import sys
import threading as _threading
from time import time
from datetime import datetime
from functools import wraps
from typing import Any, Optional, Tuple, Union
@@ -520,3 +521,17 @@ def logging_error(f):
return f(self, *args, **kwargs)
return _logger
def calculate_time(time_limit=None):
def actual_calculate_time(func):
def warp(*args, **kwargs):
now = time()
func(*args, **kwargs)
if time_limit == None:
print(func.__name__,'cost:', time() - now)
else:
if time() - now > time_limit:
print(func.__name__,'cost:', time() - now)
return warp
return actual_calculate_time