Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5531dcc0f0 | |||
| c0bb567bf7 | |||
| 58e09bfcda | |||
| 55780514b9 | |||
| 936514871f | |||
| f25d9221c6 | |||
| 2ee9fa6b19 | |||
| e2f7bba961 | |||
| bff75dc49e | |||
| 35912f614e | |||
| cfc4e39c8a | |||
| 8c4916d1e8 | |||
| e3c252f204 | |||
| c2164da48b | |||
| ab2d746afb | |||
| 4243a13536 | |||
| bbde653a8e | |||
| 6c0cef7925 | |||
| 3bbf0c912a | |||
| 4333958ebe | |||
| 3239a691e3 | |||
| 30183788d8 | |||
| 13df921b1c |
@@ -87,7 +87,8 @@ class DataAPI(metaclass=abc.ABCMeta):
|
||||
def update_device_configuration(self,
|
||||
device: Union[int, Device],
|
||||
meta_file: Union[str, Path, RecordingMetaFile],
|
||||
data_format: Union[AnyStr, DataDecodeFormat]):
|
||||
data_format: Union[AnyStr, DataDecodeFormat],
|
||||
project_info: str):
|
||||
"""set device configuration.
|
||||
|
||||
:param device: device ID
|
||||
@@ -154,7 +155,8 @@ class DataClient(SocketClient, DataAPI, metaclass=SocketClientMacro(DataAPI)):
|
||||
def update_device_configuration(self,
|
||||
device: Union[int, Device],
|
||||
meta_file: Union[str, Path, RecordingMetaFile],
|
||||
data_format: Union[AnyStr, DataDecodeFormat]):
|
||||
data_format: Union[AnyStr, DataDecodeFormat],
|
||||
project_info: str):
|
||||
|
||||
# meta file
|
||||
if isinstance(meta_file, str):
|
||||
@@ -186,7 +188,7 @@ class DataClient(SocketClient, DataAPI, metaclass=SocketClientMacro(DataAPI)):
|
||||
raise TypeError('not a data decode format : ' + data_format.__class__.__name__)
|
||||
|
||||
# send
|
||||
self.send_command('update_device_configuration', device, meta_file, data_format)
|
||||
self.send_command('update_device_configuration', device, meta_file, data_format, project_info)
|
||||
|
||||
def is_sync(self, device: Union[None, int, Device] = None) -> bool:
|
||||
if isinstance(device, Device):
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
from sqlalchemy import create_engine
|
||||
# from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.orm import sessionmaker, declarative_base
|
||||
|
||||
SQLALCHEMY_DATABASE_URL = "postgresql://biopro:BioProControlBox@127.0.0.1:5432/postgres"
|
||||
|
||||
engine = create_engine(SQLALCHEMY_DATABASE_URL)
|
||||
Session = sessionmaker(bind=engine)
|
||||
|
||||
Base = declarative_base()
|
||||
@@ -0,0 +1,21 @@
|
||||
from sqlalchemy import Table, Column, String, MetaData, ForeignKey, JSON
|
||||
from sqlalchemy.sql import select, func
|
||||
from sqlalchemy.types import Integer, BigInteger, String, Boolean, TIMESTAMP, Numeric
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
|
||||
from .base import Base
|
||||
|
||||
class MetaProjectInfo(Base):
|
||||
__tablename__ = "meta_project_info"
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
project = Column(String(36))
|
||||
cycle = Column(String)
|
||||
task = Column(JSONB)
|
||||
serial_number = Column(Integer)
|
||||
deleted = Column(Boolean, default = False)
|
||||
created_at = Column(TIMESTAMP(timezone=True), server_default=func.now())
|
||||
updated_at = Column(TIMESTAMP(timezone=True), onupdate=func.now())
|
||||
|
||||
# def __repr__(self):
|
||||
# return f"User(id={self.id!r}, name={self.name!r}, fullname={self.task!r})"
|
||||
@@ -0,0 +1,24 @@
|
||||
from sqlalchemy import Table, Column, String, MetaData, ForeignKey, JSON
|
||||
from sqlalchemy.sql import select, func
|
||||
from sqlalchemy.types import Integer, BigInteger, String, Boolean, TIMESTAMP, Numeric
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
|
||||
from .base import Base
|
||||
|
||||
class ProjectReport(Base):
|
||||
__tablename__ = "project_report"
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
name = Column(String)
|
||||
desc = Column(String)
|
||||
task = Column(JSONB)
|
||||
cycle = Column(JSONB)
|
||||
device = Column(JSONB)
|
||||
uuid = Column(String(36))
|
||||
user_auth = Column(JSONB)
|
||||
deleted = Column(Boolean, default = False)
|
||||
created_at = Column(TIMESTAMP(timezone=True), server_default=func.now())
|
||||
updated_at = Column(TIMESTAMP(timezone=True), onupdate=func.now())
|
||||
|
||||
# def __repr__(self):
|
||||
# return f"User(id={self.id!r}, name={self.name!r}, fullname={self.task!r})"
|
||||
@@ -662,7 +662,7 @@ class CC2650Device(Device):
|
||||
elif device_type == 'EISZeroOne':
|
||||
i = 0
|
||||
request_times = 0
|
||||
while i < 7:
|
||||
while i < 13:
|
||||
try:
|
||||
# send
|
||||
code = self._encode_instruction(DeviceInstruction.TYP_CIS, DeviceInstruction.CIS_CALI, i)
|
||||
|
||||
@@ -574,20 +574,23 @@ class DeviceManager(MasterDevice, Synchronized):
|
||||
:param device: device ID or response info
|
||||
:return: CompletedDevice, None if not found.
|
||||
"""
|
||||
if isinstance(device, int):
|
||||
for slave in self._device:
|
||||
if slave.device_id == device:
|
||||
return slave
|
||||
try:
|
||||
if isinstance(device, int):
|
||||
for slave in self._device:
|
||||
if slave.device_id == device:
|
||||
return slave
|
||||
|
||||
elif isinstance(device, str):
|
||||
for slave in self._device:
|
||||
if ':'.join('{:02x}'.format(b) for b in slave.mac_address) == device.lower():
|
||||
return slave
|
||||
elif isinstance(device, str):
|
||||
for slave in self._device:
|
||||
if ':'.join('{:02x}'.format(b) for b in slave.mac_address) == device.lower():
|
||||
return slave
|
||||
|
||||
elif isinstance(device, DeviceInfo):
|
||||
for slave in self._device:
|
||||
if device.match(slave):
|
||||
return slave
|
||||
elif isinstance(device, DeviceInfo):
|
||||
for slave in self._device:
|
||||
if device.match(slave):
|
||||
return slave
|
||||
except BaseException as e:
|
||||
self.log_error('device not found', str(device))
|
||||
|
||||
return None
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import abc
|
||||
import struct
|
||||
import math
|
||||
import numpy
|
||||
from typing import Optional, TypeVar, Generic, Tuple, Dict, List, AnyStr
|
||||
from datetime import datetime
|
||||
|
||||
@@ -1380,12 +1381,27 @@ class EISZeroOneDataDecoder(RecDataDecoder):
|
||||
def _decode_cali_coeff(cali_coeff: bytes) -> Optional[List[Tuple[int, int]]]:
|
||||
if cali_coeff != b'':
|
||||
cali_table = []
|
||||
phase_para_a = []
|
||||
phase_para_b = []
|
||||
hsrtia_a = []
|
||||
hsrtia_b = []
|
||||
hsrtia_c = []
|
||||
hsrtia_d = []
|
||||
phase_coeff = []
|
||||
phase_offset = []
|
||||
|
||||
# phase_coeff = [[0]*4 for i in range(4)]
|
||||
# phase_offset = [[0]*4 for i in range(4)]
|
||||
|
||||
phase_coeff = numpy.zeros([4, 4], dtype = int)
|
||||
phase_offset = numpy.zeros([4, 4], dtype = int)
|
||||
|
||||
########################################
|
||||
# phase_coeff
|
||||
# [[gain0, g1, g2, g3] ----->最高頻
|
||||
# [gain0, g1, g2, g3] ----->中頻
|
||||
# [gain0, g1, g2, g3] ----->低頻
|
||||
# [gain0, g1, g2, g3] ----->最低頻
|
||||
# ]
|
||||
#######################################
|
||||
|
||||
# print('cali_coeff', cali_coeff)
|
||||
cutoff_freq = struct.unpack('>I', cali_coeff[1:5])[0] * 100 #4
|
||||
@@ -1396,15 +1412,19 @@ class EISZeroOneDataDecoder(RecDataDecoder):
|
||||
# hsrtia_160k = struct.unpack('>I', cali_coeff[8:12])[0] #4
|
||||
|
||||
index = 20
|
||||
for i in range(index, index+16, 8):
|
||||
phase_para_a.append(struct.unpack('>i', cali_coeff[i+1:i+5])[0])
|
||||
phase_para_b.append(struct.unpack('>i', cali_coeff[i+5:i+9])[0])
|
||||
|
||||
g = 0
|
||||
phase_coeff[0][g] = struct.unpack('>i', cali_coeff[index+1:index+5])[0]
|
||||
phase_offset[0][g] = struct.unpack('>i', cali_coeff[index+5:index+9])[0]
|
||||
phase_coeff[1][g] = struct.unpack('>i', cali_coeff[index+9:index+13])[0]
|
||||
phase_offset[1][g] = struct.unpack('>i', cali_coeff[index+13:index+17])[0]
|
||||
|
||||
index = 40
|
||||
for i in range(index, index+16, 8):
|
||||
phase_para_a.append(struct.unpack('>i', cali_coeff[i+1:i+5])[0])
|
||||
phase_para_b.append(struct.unpack('>i', cali_coeff[i+5:i+9])[0])
|
||||
|
||||
g = 0
|
||||
phase_coeff[2][g] = struct.unpack('>i', cali_coeff[index+1:index+5])[0]
|
||||
phase_offset[2][g] = struct.unpack('>i', cali_coeff[index+5:index+9])[0]
|
||||
phase_coeff[3][g] = struct.unpack('>i', cali_coeff[index+9:index+13])[0]
|
||||
phase_offset[3][g] = struct.unpack('>i', cali_coeff[index+13:index+17])[0]
|
||||
|
||||
#Lv[0] 160k
|
||||
index = 60
|
||||
hsrtia_a.append(struct.unpack('>i', cali_coeff[index+1:index+5])[0]/1e8)
|
||||
@@ -1429,18 +1449,58 @@ class EISZeroOneDataDecoder(RecDataDecoder):
|
||||
hsrtia_b.append(struct.unpack('>i', cali_coeff[index+5:index+9])[0]/1e8)
|
||||
hsrtia_c.append(struct.unpack('>i', cali_coeff[index+9:index+13])[0]/1e4)
|
||||
|
||||
# hsrtia_a.append(struct.unpack('>I', cali_coeff[index+1:index+5])[0])
|
||||
# hsrtia_b.append(struct.unpack('>I', cali_coeff[index+5:index+9])[0]/1e6)
|
||||
# hsrtia_c.append(struct.unpack('>I', cali_coeff[index+9:index+13])[0]/1e5)
|
||||
index = 140
|
||||
g = 1
|
||||
phase_coeff[0][g] = struct.unpack('>i', cali_coeff[index+1:index+5])[0]
|
||||
phase_offset[0][g] = struct.unpack('>i', cali_coeff[index+5:index+9])[0]
|
||||
phase_coeff[1][g] = struct.unpack('>i', cali_coeff[index+9:index+13])[0]
|
||||
phase_offset[1][g] = struct.unpack('>i', cali_coeff[index+13:index+17])[0]
|
||||
|
||||
index = 160
|
||||
g = 1
|
||||
phase_coeff[2][g] = struct.unpack('>i', cali_coeff[index+1:index+5])[0]
|
||||
phase_offset[2][g] = struct.unpack('>i', cali_coeff[index+5:index+9])[0]
|
||||
phase_coeff[3][g] = struct.unpack('>i', cali_coeff[index+9:index+13])[0]
|
||||
phase_offset[3][g] = struct.unpack('>i', cali_coeff[index+13:index+17])[0]
|
||||
|
||||
index = 180
|
||||
g = 2
|
||||
phase_coeff[0][g] = struct.unpack('>i', cali_coeff[index+1:index+5])[0]
|
||||
phase_offset[0][g] = struct.unpack('>i', cali_coeff[index+5:index+9])[0]
|
||||
phase_coeff[1][g] = struct.unpack('>i', cali_coeff[index+9:index+13])[0]
|
||||
phase_offset[1][g] = struct.unpack('>i', cali_coeff[index+13:index+17])[0]
|
||||
|
||||
index = 200
|
||||
g = 2
|
||||
phase_coeff[2][g] = struct.unpack('>i', cali_coeff[index+1:index+5])[0]
|
||||
phase_offset[2][g] = struct.unpack('>i', cali_coeff[index+5:index+9])[0]
|
||||
phase_coeff[3][g] = struct.unpack('>i', cali_coeff[index+9:index+13])[0]
|
||||
phase_offset[3][g] = struct.unpack('>i', cali_coeff[index+13:index+17])[0]
|
||||
|
||||
index = 220
|
||||
g = 3
|
||||
phase_coeff[0][g] = struct.unpack('>i', cali_coeff[index+1:index+5])[0]
|
||||
phase_offset[0][g] = struct.unpack('>i', cali_coeff[index+5:index+9])[0]
|
||||
phase_coeff[1][g] = struct.unpack('>i', cali_coeff[index+9:index+13])[0]
|
||||
phase_offset[1][g] = struct.unpack('>i', cali_coeff[index+13:index+17])[0]
|
||||
|
||||
index = 240
|
||||
g = 3
|
||||
phase_coeff[2][g] = struct.unpack('>i', cali_coeff[index+1:index+5])[0]
|
||||
phase_offset[2][g] = struct.unpack('>i', cali_coeff[index+5:index+9])[0]
|
||||
phase_coeff[3][g] = struct.unpack('>i', cali_coeff[index+9:index+13])[0]
|
||||
phase_offset[3][g] = struct.unpack('>i', cali_coeff[index+13:index+17])[0]
|
||||
|
||||
# print('cutoff_freq', cutoff_freq)
|
||||
# print('hsrtia_a', hsrtia_a)
|
||||
# print('hsrtia_b', hsrtia_b)
|
||||
# print('hsrtia_c', hsrtia_c)
|
||||
# print('phase_para_a', phase_para_a)
|
||||
# print('phase_para_b', phase_para_b)
|
||||
# print('phase_coeff')
|
||||
# print(phase_coeff)
|
||||
# print('phase_offset')
|
||||
# print(phase_offset)
|
||||
|
||||
cali_table.append((cutoff_freq, phase_para_a, phase_para_b, hsrtia_a, hsrtia_b, hsrtia_c, hsrtia_d))
|
||||
cali_table.append((cutoff_freq, phase_coeff, phase_offset, hsrtia_a, hsrtia_b, hsrtia_c, hsrtia_d))
|
||||
|
||||
return cali_table
|
||||
else:
|
||||
@@ -1490,13 +1550,12 @@ class EISZeroOneDataDecoder(RecDataDecoder):
|
||||
return None
|
||||
else:
|
||||
if self.cali_coeff is not None and self._mode == 0:
|
||||
phase_para_a = []
|
||||
phase_para_b = []
|
||||
hsrtia_a = []
|
||||
hsrtia_b = []
|
||||
hsrtia_c = []
|
||||
hsrtia_d = []
|
||||
cutoff_freq, phase_para_a, phase_para_b, hsrtia_a, hsrtia_b, hsrtia_c, hsrtia_d = self.cali_coeff[0]
|
||||
cutoff_freq, phase_coeff, phase_offset, hsrtia_a, hsrtia_b, hsrtia_c, hsrtia_d = self.cali_coeff[0]
|
||||
|
||||
voltage_amp = round(self._ac_amp * 800 / 2047) # use UI value
|
||||
if (self._freq_start > self._freq_stop):
|
||||
self._freq_direction = 0
|
||||
@@ -1507,6 +1566,7 @@ class EISZeroOneDataDecoder(RecDataDecoder):
|
||||
img = ch1
|
||||
real = ch2
|
||||
freq = ch3
|
||||
fre_idx = 0
|
||||
|
||||
voltage_mag = math.sqrt(img ** 2 + real ** 2) * (1 + freq ** 2 / cutoff_freq ** 2)
|
||||
|
||||
@@ -1526,32 +1586,32 @@ class EISZeroOneDataDecoder(RecDataDecoder):
|
||||
else:
|
||||
impedance = 0
|
||||
|
||||
if (real > 0):
|
||||
raw_phase = math.atan(img / real) * 180 / math.pi
|
||||
elif (real == 0):
|
||||
raw_phase = 90
|
||||
else:
|
||||
raw_phase = math.atan(img / real) * 180 / math.pi + 180
|
||||
raw_phase = math.atan2(img , real) * 180 / math.pi
|
||||
|
||||
if (freq >= 1000000): # 10000 Hz
|
||||
i = 0
|
||||
fre_idx = 0
|
||||
elif (freq >= 10000): # 100 Hz
|
||||
i = 1
|
||||
fre_idx = 1
|
||||
elif (freq >= 1000): # 10 Hz
|
||||
i = 2
|
||||
fre_idx = 2
|
||||
elif (freq >= 1): # 0.01 Hz
|
||||
i = 3
|
||||
fre_idx = 3
|
||||
|
||||
ideal_raw_phase = phase_para_a[i] /1e10 * freq + phase_para_b[i] / 1e6
|
||||
|
||||
ideal_raw_phase = phase_coeff[gain][fre_idx] /1e10 * freq + phase_offset[gain][fre_idx] / 1e6
|
||||
phase = raw_phase - ideal_raw_phase
|
||||
phase = phase % 180 if phase % 180<=90 else phase % 180-180
|
||||
|
||||
if (self._first_phase_flag):
|
||||
self._last_phase = phase
|
||||
self._first_phase_flag = 0
|
||||
elif (abs(phase - self._last_phase) >= 200):
|
||||
phase -= 360
|
||||
self._last_phase = phase
|
||||
# last_phase_to90 = self._last_phase % 180 if self._last_phase % 180<=90 else self._last_phase % 180-180
|
||||
# diff = phase - last_phase_to90
|
||||
|
||||
# if (self._first_phase_flag):
|
||||
# # self._last_phase = phase
|
||||
# self._first_phase_flag = 0
|
||||
# elif (abs(diff) >= 90):
|
||||
# phase = self._last_phase + diff + (180 if diff<0 else-180)
|
||||
# else:
|
||||
# phase = self._last_phase + diff
|
||||
# self._last_phase = phase
|
||||
|
||||
imag_after_cal = impedance * math.sin(round(phase) * math.pi / 180)
|
||||
real_after_cal = impedance * math.cos(round(phase) * math.pi / 180)
|
||||
|
||||
@@ -738,7 +738,7 @@ class DeviceCommonInstruction:
|
||||
elif instruction == cls.START:
|
||||
return '_data_format("TDC4VAF2")', '_notify(True)', 'VIS_STI', '_sync(True)'
|
||||
elif instruction == cls.INTERRUPT:
|
||||
return '_sync(False)', '_notify(False)', 'VIS_INT'
|
||||
return '_notify(False)', 'VIS_INT', '_sync(False)'
|
||||
elif instruction == cls.CLOSE:
|
||||
return '_sync(False)', '_notify(False)', 'VIS_INT'
|
||||
elif instruction == cls.CALL:
|
||||
|
||||
@@ -968,7 +968,7 @@ class CompletedDevice(Device):
|
||||
"""
|
||||
__slots__ = ('_master', '_device_id', '_device', '_library', '_context',
|
||||
'_parameter', '_configuration', '_lock', '_feature_mask',
|
||||
'_cache_battery', '_cache_battery_timestamp', '_coeff', '_status')
|
||||
'_cache_battery', '_cache_battery_timestamp', '_coeff', '_status', '_occupied_by_project')
|
||||
|
||||
def __init__(self, master: MasterDevice, library: DeviceLibrary, device_id: int, device: Device):
|
||||
"""
|
||||
@@ -986,6 +986,8 @@ class CompletedDevice(Device):
|
||||
|
||||
# device status ( 0: idle, 1: working, 2: error, 3: power off)
|
||||
self._status = 0
|
||||
# device be occupied by project
|
||||
self._occupied_by_project = None
|
||||
|
||||
# context
|
||||
s1 = library.constant
|
||||
@@ -1032,7 +1034,7 @@ class CompletedDevice(Device):
|
||||
|
||||
@property
|
||||
def mac_address_in_str(self) -> str:
|
||||
return ':'.join('{:02x}'.format(b) for b in self._device.mac_address)
|
||||
return ':'.join('{:02x}'.format(b) for b in self._device.mac_address).upper()
|
||||
|
||||
@property
|
||||
def device(self) -> Device:
|
||||
@@ -1082,6 +1084,14 @@ class CompletedDevice(Device):
|
||||
def status(self, new_status):
|
||||
self._status = new_status
|
||||
|
||||
@property
|
||||
def occupied_by_project(self) -> str:
|
||||
return self._occupied_by_project
|
||||
|
||||
@occupied_by_project.setter
|
||||
def occupied_by_project(self, new_occupied_by_project):
|
||||
self._occupied_by_project = new_occupied_by_project
|
||||
|
||||
# device parameter getter/setter
|
||||
|
||||
def parameters(self) -> List[str]:
|
||||
@@ -1303,6 +1313,7 @@ class CompletedDevice(Device):
|
||||
'recording_file_name': self.recording_file_name,
|
||||
'library_name': self._library.name,
|
||||
'library_version': str(self._library.version),
|
||||
'occupied_by_project': self._occupied_by_project,
|
||||
'configuration': self.configuration.as_json(list_hide=True),
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ class MultiExtMemSpiInterface(LowLevelHardwareInterface):
|
||||
'_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')
|
||||
'_head_wrong_cnt', '_pin_busy_value')
|
||||
|
||||
def __init__(self,
|
||||
select: Selector,
|
||||
@@ -50,11 +50,11 @@ class MultiExtMemSpiInterface(LowLevelHardwareInterface):
|
||||
self._single_data_len = self._elite_data_len + self._mem_header_len + self._mem_tailer_len
|
||||
|
||||
# buffer
|
||||
self._tx_buffer_header = [0] * 19
|
||||
self._tx_buffer_header = [0] * 64
|
||||
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_busy: Optional[InputPin] = InputPin.get_used(P3Pin.MEM_BZY)
|
||||
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
|
||||
@@ -62,6 +62,7 @@ class MultiExtMemSpiInterface(LowLevelHardwareInterface):
|
||||
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._pin_busy_value = [bool(self.pin_busy) for _ in range(Selector.SIZE)]
|
||||
|
||||
self._read_green_times = 0
|
||||
self._read_red_times = 0
|
||||
@@ -98,6 +99,14 @@ class MultiExtMemSpiInterface(LowLevelHardwareInterface):
|
||||
self._pin_ram_sel_value[channel] = True
|
||||
return self._pin_ram_sel_value[channel]
|
||||
|
||||
def get_pin_busy(self):
|
||||
channel = self.select
|
||||
if self.pin_busy.input() == 0:
|
||||
self._pin_busy_value[channel] = False
|
||||
else:
|
||||
self._pin_busy_value[channel] = True
|
||||
return self._pin_busy_value[channel]
|
||||
|
||||
@property
|
||||
def select(self) -> int:
|
||||
return self._selector.channel
|
||||
@@ -216,7 +225,9 @@ class MultiExtMemSpiInterface(LowLevelHardwareInterface):
|
||||
return
|
||||
|
||||
def recv_memory(self, device: int) -> Optional[bytes]:
|
||||
self.pin_busy.output(False)
|
||||
# self.pin_busy.output(False)
|
||||
|
||||
# print('mem_req==ram_sel,[', self._pin_mem_req_value[device], ',', self._pin_ram_sel_value[device], ']')
|
||||
|
||||
rx = []
|
||||
|
||||
@@ -300,6 +311,9 @@ class MultiExtMemSpiInterface(LowLevelHardwareInterface):
|
||||
print("green data print:", data, device, datetime.now())
|
||||
return None
|
||||
|
||||
# print('data=', list(data))
|
||||
# print('Ram:', data[62])
|
||||
|
||||
if (length >= 4000):
|
||||
flag_print = True
|
||||
print("green data: big length:", length)
|
||||
@@ -415,9 +429,9 @@ class MultiExtMemSpiInterface(LowLevelHardwareInterface):
|
||||
except BaseException as e:
|
||||
print(e)
|
||||
|
||||
finally:
|
||||
# print("\n")
|
||||
self.pin_busy.output(True)
|
||||
# finally:
|
||||
# # print("\n")
|
||||
# self.pin_busy.output(True)
|
||||
|
||||
return bytes(rx)
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ class Project(threading.Thread):
|
||||
self._name = None
|
||||
self._desc = None
|
||||
self._device = None
|
||||
self._complete_device = []
|
||||
self._complete_device = {}
|
||||
self._status = 0
|
||||
|
||||
self._instruction_set = Instruction()
|
||||
@@ -64,8 +64,10 @@ class Project(threading.Thread):
|
||||
|
||||
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)
|
||||
mac_address = device_list[device]['pair']
|
||||
complete_device = self._device_manager.get_device(mac_address)
|
||||
complete_device.occupied_by_project = self._uuid
|
||||
self._complete_device[device] = complete_device
|
||||
|
||||
@property
|
||||
def id(self) -> int:
|
||||
@@ -226,8 +228,10 @@ class Project(threading.Thread):
|
||||
if action.type == 'start':
|
||||
self._count += 1
|
||||
for instruction in instruction_set:
|
||||
print('instruction 1', device, instruction, datetime.now())
|
||||
args = list(map(lambda arg: task_info[arg], instruction['arguments']))
|
||||
target=getattr(device, instruction['method'])(*args)
|
||||
print('instruction 2', device, instruction, datetime.now())
|
||||
|
||||
delay_time += (time() - now)
|
||||
|
||||
@@ -250,6 +254,8 @@ class Project(threading.Thread):
|
||||
pass
|
||||
|
||||
def stop(self):
|
||||
for device in self._complete_device:
|
||||
self._complete_device[device].occupied_by_project = None
|
||||
self._task_manager.running_task.stop()
|
||||
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._status = 2
|
||||
@@ -258,6 +264,8 @@ class Project(threading.Thread):
|
||||
self.mqtt_thread.broadcast_command('project:project ' + str(self._name) + ' stop at ' + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
|
||||
|
||||
def close(self):
|
||||
for device in self._complete_device:
|
||||
self._complete_device[device].occupied_by_project = None
|
||||
self._status = 2
|
||||
self._end_time = time()
|
||||
self._stop_flag = True
|
||||
@@ -316,6 +324,18 @@ class Project(threading.Thread):
|
||||
'device': self._device,
|
||||
'task': self.task_list,
|
||||
'running_task': running_task,
|
||||
'cycle': self._cycle
|
||||
'cycle': self._cycle,
|
||||
'count': self._count,
|
||||
}
|
||||
return data
|
||||
|
||||
def info_pass_data_server(self):
|
||||
if self._task_manager.running_task is not None:
|
||||
running_task = self._task_manager.running_task.as_json()
|
||||
data = {
|
||||
'project': self._uuid,
|
||||
'task': running_task,
|
||||
'cycle': self._cycle,
|
||||
'serial_number': self._count,
|
||||
}
|
||||
return data
|
||||
|
||||
@@ -118,7 +118,7 @@ class RecordingMetaFile(JsonSerialize):
|
||||
'_dirty', '_last_modify_time', '_file_size_cache',
|
||||
'_recording_file_ch', '_recording_sub_file', '_size',
|
||||
'_parameter', '_parent', '_recording_file_name', '_recording_sub_mini', '_recording_mini_ch',
|
||||
'_raw_serial_number', '_mini_serial_number', '_device_id')
|
||||
'_raw_serial_number', '_mini_serial_number', '_device_id', '_project_id')
|
||||
|
||||
def __init__(self, filepath: Union[str, Path], data_format: bytes = None, id_db = 0, database = None):
|
||||
if isinstance(filepath, str):
|
||||
@@ -153,6 +153,7 @@ class RecordingMetaFile(JsonSerialize):
|
||||
self._parent = ''
|
||||
self._recording_file_name = ''
|
||||
self._device_id = -1
|
||||
self._project_id = None
|
||||
|
||||
# recording parameter
|
||||
self._configuration = None
|
||||
@@ -297,6 +298,7 @@ class RecordingMetaFile(JsonSerialize):
|
||||
'uuid': str(self._file_uuid),
|
||||
'data_format': 'rec',
|
||||
'device': self._device,
|
||||
'project': self._project_id,
|
||||
}
|
||||
|
||||
if len(self._parent) > 0:
|
||||
@@ -462,7 +464,7 @@ class RecordingMetaFile(JsonSerialize):
|
||||
def parameter(self) -> str:
|
||||
return self._parameter
|
||||
|
||||
@device.setter
|
||||
@parameter.setter
|
||||
def parameter(self, parameter):
|
||||
self._parameter = parameter
|
||||
return None
|
||||
@@ -471,7 +473,7 @@ class RecordingMetaFile(JsonSerialize):
|
||||
def parent(self) -> str:
|
||||
return self._parent
|
||||
|
||||
@device.setter
|
||||
@parent.setter
|
||||
def parent(self, parent):
|
||||
self._parent = parent
|
||||
|
||||
@@ -479,7 +481,7 @@ class RecordingMetaFile(JsonSerialize):
|
||||
def recording_file_name(self) -> str:
|
||||
return self._recording_file_name
|
||||
|
||||
@device.setter
|
||||
@recording_file_name.setter
|
||||
def recording_file_name(self, recording_file_name):
|
||||
self._recording_file_name = recording_file_name
|
||||
|
||||
@@ -492,6 +494,15 @@ class RecordingMetaFile(JsonSerialize):
|
||||
self._configuration = conf
|
||||
self._dirty = True
|
||||
return None
|
||||
|
||||
@property
|
||||
def project_id(self) -> int:
|
||||
return self._project_id
|
||||
|
||||
@project_id.setter
|
||||
def project_id(self, project: int):
|
||||
self._project_id = project
|
||||
return None
|
||||
|
||||
@property
|
||||
def channels(self) -> List[int]:
|
||||
|
||||
@@ -4,7 +4,6 @@ from time import time, sleep
|
||||
from typing import Iterable
|
||||
from datetime import datetime
|
||||
import gc
|
||||
|
||||
import base64
|
||||
|
||||
from biopro.data import *
|
||||
@@ -27,7 +26,6 @@ from .mqtt import MqttDataMessageHandler, MqttThread
|
||||
from .database import DataBaseProcess
|
||||
from .recording import RecordingProcess
|
||||
from multiprocessing import Queue
|
||||
import queue
|
||||
|
||||
from json import loads as json_parse, dumps as _json_stringify
|
||||
import json
|
||||
@@ -317,7 +315,8 @@ class DataServer(SocketServer, DataAPI):
|
||||
def update_device_configuration(self,
|
||||
device: str,
|
||||
meta_file: Union[str, Path, RecordingMetaFile],
|
||||
data_format: Union[AnyStr, DataDecodeFormat]):
|
||||
data_format: Union[AnyStr, DataDecodeFormat],
|
||||
project_info: str):
|
||||
# meta file
|
||||
|
||||
device_id = -1
|
||||
@@ -345,6 +344,8 @@ class DataServer(SocketServer, DataAPI):
|
||||
_parent = json_stringify(_device['parent'])
|
||||
_recording_file_name = _device['recording_file_name']
|
||||
mac_address = json.loads(device)['device_address']
|
||||
device_id = _device['device_id']
|
||||
|
||||
del _device['configuration']
|
||||
del _device['parent']
|
||||
del _device['recording_file_name']
|
||||
@@ -354,13 +355,22 @@ class DataServer(SocketServer, DataAPI):
|
||||
# meta_file.parameter = _parameter
|
||||
# meta_file.parent = _parent
|
||||
# meta_file.recording_file_name = _recording_file_name
|
||||
device_id = int(json.loads(device)['device_id'])
|
||||
|
||||
if device_id < 0:
|
||||
raise ValueError('illegal device ID : ' + str(device_id))
|
||||
|
||||
self.log_verbose('device ID', device_id)
|
||||
|
||||
# project binding meta file
|
||||
project_id = None
|
||||
_project = None
|
||||
if project_info != None:
|
||||
_project = json.loads(project_info)
|
||||
self.database_process.put_queue(['project_insert', device_id, _project])
|
||||
result = self._queue_ds_dict[int(device_id)].get()
|
||||
if result[0] == 'project_id':
|
||||
project_id = result[1]
|
||||
|
||||
# while len(self._configurations) <= device_id:
|
||||
# self._configurationsappend(None)
|
||||
|
||||
@@ -380,8 +390,6 @@ class DataServer(SocketServer, DataAPI):
|
||||
else:
|
||||
data_format = data_format.name
|
||||
|
||||
# self.log_verbose('device data format', data_format)
|
||||
|
||||
self.log_verbose('device meta file', meta_file)
|
||||
|
||||
# data runtime
|
||||
@@ -406,15 +414,15 @@ class DataServer(SocketServer, DataAPI):
|
||||
c.shutdown()
|
||||
c.join()
|
||||
self._spi.set_wait_flag(c._device, True)
|
||||
|
||||
data_runtime_process = RecordingProcess('data_server', self.log_verbose, device_id,
|
||||
Queue(), self._queue_ds_dict[int(device_id)], self._queue_msg, meta_file,
|
||||
json_stringify(_device), _parameter, _parent, _recording_file_name,
|
||||
data_format, self.socket_mqtt_ip, self.socket_mqtt_port,
|
||||
database = self.database_process )
|
||||
# data_runtime_process.start()
|
||||
data_format, self.socket_mqtt_ip, self.socket_mqtt_port,
|
||||
project_id = project_id,
|
||||
database = self.database_process)
|
||||
|
||||
# check channel
|
||||
|
||||
if isinstance(data_runtime_process, RecordingProcess) and device_id not in self._available_channel:
|
||||
raise RuntimeError('set device configuration on un-available channel', device_id)
|
||||
|
||||
@@ -646,6 +654,7 @@ class DataServer(SocketServer, DataAPI):
|
||||
def whether_to_record(self, device):
|
||||
# if user click "start", return True; if user click "stop", return False;
|
||||
if device in self._configurations.keys() and self._configurations[device] is not None:
|
||||
# print(self._configurations.keys(), ',', device, datetime.now())
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
@@ -654,6 +663,9 @@ class DataServer(SocketServer, DataAPI):
|
||||
ret = False
|
||||
sync = self.get_spi_obj()
|
||||
|
||||
busy = sync.get_pin_busy()
|
||||
# print('pin_busy=', busy, device, datetime.now())
|
||||
|
||||
if sync.get_pin_mem_req() == sync.get_pin_ram_sel():
|
||||
spi_data = sync.recv_memory(device)
|
||||
signal = sync.get_pin_mem_req()
|
||||
@@ -662,6 +674,7 @@ class DataServer(SocketServer, DataAPI):
|
||||
|
||||
else:
|
||||
data = None
|
||||
print('data=None, mem_req!=ram_sel, [', sync.get_pin_mem_req(), ', ', sync.get_pin_ram_sel(), ']', device, datetime.now())
|
||||
|
||||
if data is not None:
|
||||
if self._configurations.get(device, None) != None:
|
||||
|
||||
@@ -550,4 +550,33 @@ class DataBaseProcess(Process):
|
||||
except psycopg2.Error as e:
|
||||
print('e', e)
|
||||
|
||||
return True
|
||||
return True
|
||||
|
||||
def project_insert(self, device_id, _data):
|
||||
sql_str = 'INSERT INTO "public"."meta_project_info" ('
|
||||
sql_set = []
|
||||
for item in _data.keys():
|
||||
sql_str = sql_str + str(item) + ', '
|
||||
if isinstance(_data[item], dict) or isinstance(_data[item], list):
|
||||
sql_set.append(json_stringify(_data[item]))
|
||||
else:
|
||||
sql_set.append(_data[item])
|
||||
|
||||
sql_str = sql_str[0:-2] + ') VALUES ('
|
||||
for item in _data.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 BaseException as e:
|
||||
print('insert error', e)
|
||||
self._psql_conn.commit()
|
||||
sql_cursor.close()
|
||||
self._queue_error.put()
|
||||
finally:
|
||||
self._queue_ds[int(device_id)].put(['project_id', int(sql_cursor.fetchone()[0])])
|
||||
self._psql_conn.commit()
|
||||
sql_cursor.close()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from time import sleep
|
||||
from typing import Iterable
|
||||
from datetime import datetime
|
||||
import json
|
||||
|
||||
import biopro.impl.vcgencmd as vcg
|
||||
from biopro.data import DataServerOptions, DataAPI
|
||||
@@ -31,8 +32,10 @@ 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
|
||||
from biopro.db.base import Base, Session, engine
|
||||
from biopro.db.project_report import ProjectReport
|
||||
from biopro.db.meta_project_info import MetaProjectInfo
|
||||
|
||||
|
||||
_RUNTIME_COMPILE = False
|
||||
|
||||
@@ -117,8 +120,8 @@ class ControlServer(SocketServer, ControlServerAPI):
|
||||
self.ups_thread = UPSDetectThread(self, c.flag_ups_wait_time)
|
||||
|
||||
# user session
|
||||
self._session = {}
|
||||
self._user_session_expire = c.user_session_expire_days * 24 * 60 * 60 # sec
|
||||
# self._session = {}
|
||||
# self._user_session_expire = c.user_session_expire_days * 24 * 60 * 60 # sec
|
||||
|
||||
# indicate those device together
|
||||
self._device_instruction_group = None
|
||||
@@ -129,6 +132,10 @@ class ControlServer(SocketServer, ControlServerAPI):
|
||||
# _api request build
|
||||
self._api = ApiRequests()
|
||||
|
||||
# sqlalchemy
|
||||
Base.metadata.create_all(engine)
|
||||
self._session = Session()
|
||||
|
||||
# init method
|
||||
|
||||
def _init_file_manager(self, option: ControlServerOptions) -> FileManager:
|
||||
@@ -820,16 +827,19 @@ class ControlServer(SocketServer, ControlServerAPI):
|
||||
|
||||
@logging_info
|
||||
def device_battery(self, device:int) -> List[int]:
|
||||
battery = {}
|
||||
if device == 'all':
|
||||
device_list = self.device_manager.list_device()
|
||||
if len(device_list) > 0:
|
||||
battery = list(map(lambda x: {"device": x.memory_board, "battery":self.device_manager.get_device(x).battery}, device_list))
|
||||
else:
|
||||
battery = {
|
||||
"device": device,
|
||||
"battery": self.device_manager.get_device(device).battery
|
||||
}
|
||||
try:
|
||||
battery = {}
|
||||
if device == 'all':
|
||||
device_list = self.device_manager.list_device()
|
||||
if len(device_list) > 0:
|
||||
battery = list(map(lambda x: {"device": x.memory_board, "battery":self.device_manager.get_device(x).battery}, device_list))
|
||||
else:
|
||||
battery = {
|
||||
"device": device,
|
||||
"battery": self.device_manager.get_device(device).battery
|
||||
}
|
||||
except AttributeError as e:
|
||||
print('device_battery', device, 'not found', e)
|
||||
return battery
|
||||
|
||||
@logging_info
|
||||
@@ -1021,8 +1031,17 @@ class ControlServer(SocketServer, ControlServerAPI):
|
||||
@logging_info
|
||||
def run_project(self, project) -> bool:
|
||||
if project is not None:
|
||||
# print(project)
|
||||
project = self._project_manager.create(project)
|
||||
with self._session as session:
|
||||
project_report = ProjectReport(
|
||||
name = project.name,
|
||||
uuid = project.uuid,
|
||||
cycle = project.cycle,
|
||||
task = project.task_list,
|
||||
device = project.device
|
||||
)
|
||||
session.add(project_report)
|
||||
session.commit()
|
||||
self._project_manager.run_project(project)
|
||||
return project.as_json()
|
||||
|
||||
@@ -1078,6 +1097,7 @@ class ControlServer(SocketServer, ControlServerAPI):
|
||||
self.log_verbose('update data format', value)
|
||||
|
||||
client = self.data_server.client()
|
||||
project = None
|
||||
if client is not None:
|
||||
info = self.file_manager.use(device)
|
||||
|
||||
@@ -1088,9 +1108,12 @@ class ControlServer(SocketServer, ControlServerAPI):
|
||||
filename = self._file_save_cache.get(device.device_id, self.TEMP_FILENAME_EXPR)
|
||||
filename = format_filename(filename, device)
|
||||
info = self.file_manager.save(device, filename)
|
||||
|
||||
if device.occupied_by_project != None:
|
||||
project = json.dumps(self.project_manager.get(device.occupied_by_project).info_pass_data_server())
|
||||
|
||||
with client:
|
||||
client.update_device_configuration(device, info.meta_file, value)
|
||||
client.update_device_configuration(device, info.meta_file, value, project)
|
||||
|
||||
def _device_set_disable_cache(self, device: CompletedDevice, disable):
|
||||
if disable:
|
||||
@@ -1124,7 +1147,6 @@ class ControlServer(SocketServer, ControlServerAPI):
|
||||
filename = format_filename(self.TEMP_FILENAME_EXPR, device)
|
||||
info = self.file_manager.save(device, filename)
|
||||
client.update_device_configuration(device, info.meta_file, RawDataDecoder())
|
||||
|
||||
if self._device_instruction_group is None:
|
||||
client.start_sync(device)
|
||||
|
||||
|
||||
@@ -44,7 +44,9 @@ class RecordingProcess(Process):
|
||||
def __init__(self, client_id: str, log_verbose, device_id, queue_rec, queue_ds, queue_msg, meta_path,
|
||||
device_info, parameter, parent, recording_file_name, data_format,
|
||||
mqtt_ip, mqtt_port,
|
||||
name = 'Recording-Process', database = None):
|
||||
name = 'Recording-Process',
|
||||
project_id = None,
|
||||
database = None):
|
||||
super(RecordingProcess, self).__init__(name = name)
|
||||
|
||||
self._database = database
|
||||
@@ -57,6 +59,7 @@ class RecordingProcess(Process):
|
||||
self._meta_file._parent = parent
|
||||
self._meta_file._recording_file_name = recording_file_name
|
||||
self._meta_file._device_id = device_id
|
||||
self._meta_file._project_id = project_id
|
||||
print(self._meta_file._device, self._meta_file._parameter, self._meta_file._parent, self._meta_file._filepath)
|
||||
self._meta_file.write(self._database)
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ class SocketClient(metaclass=abc.ABCMeta):
|
||||
if self._socket is None:
|
||||
try:
|
||||
self._socket = Socket(AF_UNIX, SOCK_STREAM)
|
||||
self._socket.settimeout(3)
|
||||
self._socket.settimeout(5)
|
||||
self._socket.connect(self._socket_file)
|
||||
except Exception as e:
|
||||
print('open_socket error:', e)
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
"description": "DPV current recording period start",
|
||||
"record_meta": true,
|
||||
"initial": [
|
||||
13422819,
|
||||
13333333,
|
||||
7
|
||||
],
|
||||
"domain": {
|
||||
|
||||
@@ -63,6 +63,8 @@
|
||||
"EIS CURVE",
|
||||
"Cyclic Voltammetry",
|
||||
"Chronoamperometric",
|
||||
"V-T Graph",
|
||||
"R-T Graph",
|
||||
"Dev Mode"
|
||||
]
|
||||
},
|
||||
@@ -70,7 +72,7 @@
|
||||
"description": "DPV current recording period start",
|
||||
"record_meta": true,
|
||||
"initial": [
|
||||
13422819,
|
||||
13333333,
|
||||
7
|
||||
],
|
||||
"domain": {
|
||||
@@ -277,6 +279,28 @@
|
||||
"expression": "VALUE"
|
||||
}
|
||||
},
|
||||
"MEASURE_VIN_RANGE": {
|
||||
"description": "measure range of Vin",
|
||||
"record_meta": true,
|
||||
"initial": 0,
|
||||
"value": [
|
||||
"0",
|
||||
"1",
|
||||
"2",
|
||||
"auto"
|
||||
]
|
||||
},
|
||||
"DAC_VOLT": {
|
||||
"description": "DAC output Voltage",
|
||||
"record_meta": true,
|
||||
"initial": 37500,
|
||||
"domain": [
|
||||
65536
|
||||
],
|
||||
"value": {
|
||||
"expression": "VALUE"
|
||||
}
|
||||
},
|
||||
"BLE_WRITE": {
|
||||
"description": "send msg to elite",
|
||||
"domain": {
|
||||
@@ -308,14 +332,18 @@
|
||||
"expression": "MODE",
|
||||
"when": {
|
||||
"1": "set_adc_gain_I",
|
||||
"2": "set_adc_gain_I"
|
||||
"2": "set_adc_gain_I",
|
||||
"3": "set_adc_gain_I",
|
||||
"4": "set_adc_gain_I"
|
||||
}
|
||||
},
|
||||
{
|
||||
"expression": "MODE",
|
||||
"when": {
|
||||
"1": "set_adc_gain_Vin",
|
||||
"2": "set_adc_gain_Vin"
|
||||
"2": "set_adc_gain_Vin",
|
||||
"3": "set_adc_gain_Vin",
|
||||
"4": "set_adc_gain_Vin"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -323,7 +351,9 @@
|
||||
"when": {
|
||||
"0": "curve_eis",
|
||||
"1": "curve_cv3",
|
||||
"2": "curve_const_vscan"
|
||||
"2": "curve_const_vscan",
|
||||
"3": "curve_vt",
|
||||
"4": "curve_zt"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -456,6 +486,40 @@
|
||||
"2B>pe"
|
||||
]
|
||||
},
|
||||
"curve_zt": {
|
||||
"type": "RIS",
|
||||
"parameter": {
|
||||
"va": "DAC_VOLT",
|
||||
"pa": "ADC_LEVEL_I_15",
|
||||
"pb": "ADC_LEVEL_V_IN_15",
|
||||
"pd": "CTRL_HIGH_Z_15",
|
||||
"pe": "SAMPLE_RATE"
|
||||
},
|
||||
"data": [
|
||||
"X04;",
|
||||
"2B>va;",
|
||||
"4b>pa;4b>pb;",
|
||||
"4b>0;4b>pd;",
|
||||
"2B>pe"
|
||||
]
|
||||
},
|
||||
"curve_vt": {
|
||||
"type": "RIS",
|
||||
"parameter": {
|
||||
"pa": "ADC_LEVEL_I_15",
|
||||
"pb": "ADC_LEVEL_V_IN_15",
|
||||
"pd": "CTRL_HIGH_Z_15",
|
||||
"pe": "SAMPLE_RATE",
|
||||
"va": "MEASURE_VIN_RANGE"
|
||||
},
|
||||
"data": [
|
||||
"X05;",
|
||||
"4b>pa;4b>pb;",
|
||||
"4b>0;4b>pd;",
|
||||
"2B>pe;",
|
||||
"1B>va"
|
||||
]
|
||||
},
|
||||
"ble_instru_send": [
|
||||
"ble_write",
|
||||
"_cdr('20X>ADC_VALUE_I')"
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
"EIS CURVE",
|
||||
"Cyclic Voltammetry",
|
||||
"Chronoamperometric",
|
||||
"V-T Graph",
|
||||
"Dev Mode"
|
||||
]
|
||||
},
|
||||
@@ -70,7 +71,7 @@
|
||||
"description": "DPV current recording period start",
|
||||
"record_meta": true,
|
||||
"initial": [
|
||||
13422819,
|
||||
13333333,
|
||||
7
|
||||
],
|
||||
"domain": {
|
||||
@@ -277,6 +278,17 @@
|
||||
"expression": "VALUE"
|
||||
}
|
||||
},
|
||||
"MEASURE_VIN_RANGE": {
|
||||
"description": "measure range of Vin",
|
||||
"record_meta": true,
|
||||
"initial": 0,
|
||||
"value": [
|
||||
"0",
|
||||
"1",
|
||||
"2",
|
||||
"auto"
|
||||
]
|
||||
},
|
||||
"BLE_WRITE": {
|
||||
"description": "send msg to elite",
|
||||
"domain": {
|
||||
@@ -308,14 +320,16 @@
|
||||
"expression": "MODE",
|
||||
"when": {
|
||||
"1": "set_adc_gain_I",
|
||||
"2": "set_adc_gain_I"
|
||||
"2": "set_adc_gain_I",
|
||||
"3": "set_adc_gain_I"
|
||||
}
|
||||
},
|
||||
{
|
||||
"expression": "MODE",
|
||||
"when": {
|
||||
"1": "set_adc_gain_Vin",
|
||||
"2": "set_adc_gain_Vin"
|
||||
"2": "set_adc_gain_Vin",
|
||||
"3": "set_adc_gain_Vin"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -323,7 +337,8 @@
|
||||
"when": {
|
||||
"0": "curve_eis",
|
||||
"1": "curve_cv3",
|
||||
"2": "curve_const_vscan"
|
||||
"2": "curve_const_vscan",
|
||||
"3": "curve_vt"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -456,6 +471,23 @@
|
||||
"2B>pe"
|
||||
]
|
||||
},
|
||||
"curve_vt": {
|
||||
"type": "RIS",
|
||||
"parameter": {
|
||||
"pa": "ADC_LEVEL_I_15",
|
||||
"pb": "ADC_LEVEL_V_IN_15",
|
||||
"pd": "CTRL_HIGH_Z_15",
|
||||
"pe": "SAMPLE_RATE",
|
||||
"va": "MEASURE_VIN_RANGE"
|
||||
},
|
||||
"data": [
|
||||
"X05;",
|
||||
"4b>pa;4b>pb;",
|
||||
"4b>0;4b>pd;",
|
||||
"2B>pe;",
|
||||
"1B>va"
|
||||
]
|
||||
},
|
||||
"ble_instru_send": [
|
||||
"ble_write",
|
||||
"_cdr('20X>ADC_VALUE_I')"
|
||||
|
||||
Reference in New Issue
Block a user