Compare commits
86 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 26e02f2d40 | |||
| ead98fe8da | |||
| dc4e1bd233 | |||
| 42025d2243 | |||
| b341dbf073 | |||
| 20f6f126b0 | |||
| bf4a00db1a | |||
| 0b7a650b95 | |||
| 062613c681 | |||
| bffaff310b | |||
| 06bf262d59 | |||
| b2f9d98336 | |||
| a6b523404b | |||
| 6c232b3b07 | |||
| cfc2bf1d83 | |||
| 2b60e68197 | |||
| efb5e9aeb6 | |||
| b4d88a0e67 | |||
| 6029ff6fe1 | |||
| 6efc5e1097 | |||
| a23394d3d1 | |||
| c96f76f438 | |||
| f0f1c9fc49 | |||
| 512c80af40 | |||
| 499964b287 | |||
| 16f12d40bf | |||
| 63c1ba8efb | |||
| 4a28348db4 | |||
| 64dfe87d05 | |||
| f7a5a867a4 | |||
| 1accaa9b9f | |||
| b810e35fb2 | |||
| 82c9d2b0e3 | |||
| e5a3f33b9f | |||
| 1dd4ae2ce4 | |||
| 515cc9f7a2 | |||
| 9b92249fdb | |||
| adcc13b4de | |||
| 0cd0fd7027 | |||
| 5228290eac | |||
| 034b7976cd | |||
| fa8c219f76 | |||
| f233c019fd | |||
| ced466f3aa | |||
| f36906c034 | |||
| 0b5c62e525 | |||
| abe86238ca | |||
| f9ab0bc59b | |||
| 5dbe231c73 | |||
| c721950bf7 | |||
| 70c0271771 | |||
| 13825fe9ff | |||
| dd2e31d01f | |||
| 455fa1f86b | |||
| 71850b31a8 | |||
| 8d52fef4c1 | |||
| e091f220fa | |||
| 6049154fae | |||
| 3502472021 | |||
| 5e48c8ae0a | |||
| cb2a4c9d56 | |||
| b253aca73f | |||
| 2fd05d18ed | |||
| 03011ebd5f | |||
| 4b9bc30e28 | |||
| 4966113393 | |||
| 3371c21bbd | |||
| afc87829d9 | |||
| 952403cbf4 | |||
| 1cdd04901c | |||
| cd60e14cbe | |||
| ae55e6c789 | |||
| b8addb7686 | |||
| da581ae225 | |||
| a941f7c060 | |||
| 4b0472ecf4 | |||
| de51f53657 | |||
| 6974950d31 | |||
| 0887c48ddc | |||
| 184c7536a6 | |||
| 1a3a833680 | |||
| df3c7db8bc | |||
| 7287f4c19b | |||
| 7d3f7a47ff | |||
| 81c699e830 | |||
| 71e469ec2f |
@@ -1,5 +1,7 @@
|
||||
.DS_Store
|
||||
*.cpython-37.opt-2.pyc
|
||||
*.cpython-39-arm-linux-gnueabihf.so
|
||||
*.
|
||||
*.pyc
|
||||
*/__pycache__
|
||||
/.vscode
|
||||
|
||||
@@ -4,7 +4,7 @@ New goal on pi4 without kotlin and django, and with only one dataserver.
|
||||
# Installation
|
||||
### Get Raspbrain into SD card
|
||||
|
||||
###### Download Raspbian Buster Lite
|
||||
###### Download Raspbian Bullseye Lite
|
||||
|
||||
>https://www.raspberrypi.org/downloads/raspberry-pi-os/
|
||||
|
||||
@@ -14,7 +14,7 @@ New goal on pi4 without kotlin and django, and with only one dataserver.
|
||||
lsblk
|
||||
|
||||
# copy data to sd card
|
||||
sudo dd bs=4M if=yyyy-mm-dd-raspbian-buster.img of=/dev/sdX conv=fsync status=progress
|
||||
sudo dd bs=4M if=yyyy-mm-dd-raspios-bullseye-armhf-lite.img of=/dev/sdX conv=fsync status=progress
|
||||
|
||||
# enable ssh on first boot
|
||||
add ssh.txt in boot folder
|
||||
@@ -77,18 +77,22 @@ add ssh.txt in boot folder
|
||||
|
||||
|
||||
###### Install dependencies
|
||||
sudo apt-get install vim git wiringpi build-essential libi2c-dev i2c-tools python-dev libffi-dev python3-pip postgresql
|
||||
sudo apt-get install vim git wiringpi build-essential libi2c-dev i2c-tools python-dev libffi-dev python3-pip postgresql npm
|
||||
|
||||
###### wiringpi conflict
|
||||
need to install wiringpi: https://github.com/WiringPi/WiringPi
|
||||
install instructions: https://github.com/WiringPi/WiringPi/blob/master/INSTALL
|
||||
|
||||
### Setup project
|
||||
###### Clone project
|
||||
###### Clone data server project
|
||||
```
|
||||
cd ~
|
||||
git clone https://gitlab.com/bioproscientific/bioprorelife.git
|
||||
git clone https://gitlab.com/wisetop/controller/wisetopdataserver.git
|
||||
```
|
||||
|
||||
###### Install python dependencies
|
||||
```
|
||||
cd ~/bioprorelife
|
||||
cd ~/wisetopdataserver
|
||||
pip3 install -r requirements.txt
|
||||
```
|
||||
##### Packages version
|
||||
@@ -112,14 +116,14 @@ psycopg2 2.8.5
|
||||
|
||||
###### Build C extension
|
||||
```
|
||||
cd ~/bioprorelife/python/biopro/ext/
|
||||
cd ~/wisetopdataserver/python/biopro/ext/
|
||||
rm -rf *.so build
|
||||
python3 setup.py build_ext --inplace
|
||||
```
|
||||
|
||||
###### Check setup-uart file
|
||||
```
|
||||
cd ~/bioprorelife
|
||||
cd ~/wisetopdataserver/
|
||||
sudo vim ./run-setup-uart.sh
|
||||
```
|
||||
##### Modify the code as following
|
||||
@@ -149,44 +153,72 @@ sudo raspi-config
|
||||
reboot
|
||||
```
|
||||
|
||||
###### Set pi password
|
||||
```
|
||||
$cd ~
|
||||
$passwd
|
||||
Current password:raspberry
|
||||
New password:5k6zj454778225
|
||||
Retype new password:5k6zj454778225
|
||||
```
|
||||
|
||||
###### Auto run program when device start
|
||||
```
|
||||
sudo vim /etc/rc.local
|
||||
```
|
||||
add the code following as:
|
||||
###### add the code following as:
|
||||
```
|
||||
sudo -H -u pi nohup /home/pi/bioprorelife/run-data-server.sh > /home/pi/.data_server.out &
|
||||
sudo -H -u pi nohup /home/pi/wisetopdataserver/run-data-server.sh > /home/pi/.data_server.out &
|
||||
#sudo -H -u pi nohup /home/pi/wisetopdataserver/run-data-server.sh > /home/pi/.wisetop_data_$now.out &
|
||||
```
|
||||
##### /etc/rc.local
|
||||
```
|
||||
_IP=$(hostname -I) || true
|
||||
if [ "$_IP" ]; then
|
||||
printf "My IP address is %s\n" "$_IP"
|
||||
fi
|
||||
|
||||
now=$(date +'%F_%T')
|
||||
|
||||
sudo nohup systemctl restart apache2
|
||||
sudo nohup systemctl restart mosquitto
|
||||
|
||||
nohup node /home/pi/wisetopapiserver/dist/app.js > /home/pi/.api_server.out &
|
||||
|
||||
sleep 5
|
||||
|
||||
sudo -H -u pi nohup /home/pi/wisetopdataserver/run-data-server.sh > /home/pi/.data_server.out &
|
||||
#sudo -H -u pi nohup /home/pi/wisetopdataserver/run-data-server.sh > /home/pi/.wisetop_data_$now.out &
|
||||
|
||||
exit 0
|
||||
```
|
||||
### MQTT broker install
|
||||
|
||||
1. Install mosquitto
|
||||
```
|
||||
sudo apt-get install mosquitto mosquitto-clients
|
||||
```
|
||||
###### 1.Install mosquitto
|
||||
$sudo apt-get install mosquitto mosquitto-clients
|
||||
|
||||
|
||||
###### 2.Enable Remote Access
|
||||
$sudo vim /etc/mosquitto/conf.d/default.conf
|
||||
|
||||
2. Enable Remote Access
|
||||
```
|
||||
sudo vim /etc/mosquitto/conf.d/default.conf
|
||||
```
|
||||
add the code following as:
|
||||
```
|
||||
listener 1883
|
||||
protocol mqtt
|
||||
listener 8083
|
||||
protocol websockets
|
||||
allow_anonymous true
|
||||
```
|
||||
restart mqtt broker
|
||||
```
|
||||
sudo systemctl restart mosquitto
|
||||
```
|
||||
###### 3.restart mqtt broker
|
||||
$sudo systemctl restart mosquitto
|
||||
|
||||
3. Robust MQTT
|
||||
###### 4.Robust MQTT
|
||||
create mosquitto_restart.sh
|
||||
```
|
||||
cd ~
|
||||
sudo vim mosquitto_restart.sh
|
||||
```
|
||||
|
||||
$cd ~
|
||||
$sudo vim mosquitto_restart.sh
|
||||
|
||||
|
||||
add the code following as:
|
||||
```
|
||||
if [ "`ps -aux | grep /usr/sbin/mosquitto | wc -l`" == "1" ]
|
||||
@@ -200,25 +232,129 @@ fi
|
||||
echo "$SERVICE is currently running" >> /home/ubuntu/cron.log
|
||||
exit 0
|
||||
```
|
||||
add mosquitto_restart.sh to root routing
|
||||
```
|
||||
sudo chmod +x mosquitto_restart.sh
|
||||
sudo -i
|
||||
crontab -e
|
||||
```
|
||||
###### 5.add mosquitto_restart.sh to root routing
|
||||
$sudo chmod +x mosquitto_restart.sh
|
||||
$sudo -i
|
||||
$crontab -e
|
||||
|
||||
add the code following as:
|
||||
```
|
||||
*/5 * * * * /home/pi/mosquitto_restart.sh
|
||||
```
|
||||
3. Auto run MQTT broker when when pi-start
|
||||
```
|
||||
sudo vim /etc/rc.local
|
||||
```
|
||||
###### 6.Auto run MQTT broker when when pi-start
|
||||
$sudo vim /etc/rc.local
|
||||
|
||||
add the code following as:
|
||||
```
|
||||
sudo nohup systemctl restart mosquitto
|
||||
```
|
||||
|
||||
### Setup routed wireless access point
|
||||
### Setting up a Routed Wireless Access Point
|
||||
###### 1.Install AP and Management Software
|
||||
$sudo apt install hostapd
|
||||
$sudo systemctl unmask hostapd
|
||||
$sudo systemctl enable hostapd
|
||||
$sudo apt install dnsmasq
|
||||
$sudo DEBIAN_FRONTEND=noninteractive apt install -y netfilter-persistent iptables-persistent
|
||||
|
||||
###### 2.Set up the Network Router
|
||||
$sudo nano /etc/dhcpcd.conf
|
||||
```
|
||||
interface wlan0
|
||||
static ip_address=192.168.2.1/24
|
||||
nohook wpa_supplicant
|
||||
```
|
||||
$sudo nano /etc/sysctl.d/routed-ap.conf
|
||||
```
|
||||
# Enable IPv4 routing
|
||||
net.ipv4.ip_forward=1
|
||||
```
|
||||
|
||||
$sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
|
||||
$sudo netfilter-persistent save
|
||||
$sudo mv /etc/dnsmasq.conf /etc/dnsmasq.conf.orig
|
||||
|
||||
|
||||
$sudo nano /etc/dnsmasq.conf
|
||||
|
||||
```
|
||||
interface=wlan0 # Listening interface
|
||||
dhcp-range=192.168.2.2,192.168.2.255,255.255.255.0,24h
|
||||
# Pool of IP addresses served via DHCP
|
||||
domain=wlan # Local wireless DNS domain
|
||||
address=/gw.wlan/192.168.2.1
|
||||
# Alias for this router
|
||||
```
|
||||
###### 3.Ensure Wireless Operation
|
||||
$sudo rfkill unblock wlan
|
||||
|
||||
###### 4.Configure the AP Software
|
||||
$sudo nano /etc/hostapd/hostapd.conf
|
||||
|
||||
```
|
||||
country_code=TW
|
||||
interface=wlan0
|
||||
ssid=WTP_NONE
|
||||
hw_mode=g
|
||||
channel=7
|
||||
macaddr_acl=0
|
||||
auth_algs=1
|
||||
ignore_broadcast_ssid=0
|
||||
wpa=2
|
||||
wpa_passphrase=00000000
|
||||
wpa_key_mgmt=WPA-PSK
|
||||
wpa_pairwise=TKIP
|
||||
rsn_pairwise=CCMP
|
||||
|
||||
# 802.11n support
|
||||
ieee80211n=1
|
||||
# make raspberry pi dongle fast
|
||||
wme_enabled=1
|
||||
# ht_capab: HT capabilities, enable 40MHz
|
||||
ht_capab=[HT40+][SHORT-GI-40]
|
||||
```
|
||||
###### 5.Running the new Wireless AP
|
||||
$sudo systemctl reboot
|
||||
|
||||
|
||||
### Set web site
|
||||
$sudo vim ./sites-available/000-default.conf
|
||||
```
|
||||
<VirtualHost *:8080> #80------>8080
|
||||
# The ServerName directive sets the request scheme, hostname and port that
|
||||
# the server uses to identify itself. This is used when creating
|
||||
# redirection URLs. In the context of virtual hosts, the ServerName
|
||||
# specifies what hostname must appear in the request's Host: header to
|
||||
# match this virtual host. For the default virtual host (this file) this
|
||||
# value is not decisive as it is used as a last resort host regardless.
|
||||
# However, you must set it for any further virtual host explicitly.
|
||||
#ServerName www.example.com
|
||||
|
||||
ServerAdmin webmaster@localhost
|
||||
DocumentRoot /var/www/html
|
||||
|
||||
# Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
|
||||
# error, crit, alert, emerg.
|
||||
# It is also possible to configure the loglevel for particular
|
||||
# modules, e.g.
|
||||
#LogLevel info ssl:warn
|
||||
|
||||
ErrorLog ${APACHE_LOG_DIR}/error.log
|
||||
CustomLog ${APACHE_LOG_DIR}/access.log combined
|
||||
|
||||
# For most configuration files from conf-available/, which are
|
||||
# enabled or disabled at a global level, it is possible to
|
||||
# include a line for only one particular virtual host. For example the
|
||||
# following line enables the CGI configuration for this host only
|
||||
# after it has been globally disabled with "a2disconf".
|
||||
#Include conf-available/serve-cgi-bin.conf
|
||||
</VirtualHost>
|
||||
|
||||
<VirtualHost *:80>
|
||||
ServerAdmin bioprovue@localhost
|
||||
DocumentRoot /var/www/bioprovuebuild
|
||||
</VirtualHost>
|
||||
```
|
||||
|
||||
##### raspberry website document:
|
||||
> https://www.raspberrypi.org/documentation/configuration/wireless/access-point-routed.md
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1578,10 +1578,16 @@ class ControlAPI(metaclass=Router):
|
||||
raise NotImplementedError()
|
||||
|
||||
def run_project(self, project) -> bool:
|
||||
print('create_project', project)
|
||||
self._project_manager.create(project)
|
||||
return False
|
||||
raise NotImplementedError()
|
||||
|
||||
def get_running_project(self) -> bool:
|
||||
raise NotImplementedError()
|
||||
|
||||
def stop_project(self, project) -> bool:
|
||||
raise NotImplementedError()
|
||||
|
||||
def show_device_data(self, device) -> bool:
|
||||
raise NotImplementedError()
|
||||
|
||||
# noinspection PyAbstractClass
|
||||
class ControlClient(SocketClient, ControlAPI, metaclass=SocketClientMacro(ControlAPI)):
|
||||
|
||||
@@ -130,6 +130,14 @@ class DataAPI(metaclass=abc.ABCMeta):
|
||||
def hardware_test(self) -> JSON_OBJECT:
|
||||
""""""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def show_data(self, device: Union[int, Device]):
|
||||
"""show device data
|
||||
|
||||
:param device: device ID
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
# noinspection PyAbstractClass
|
||||
@@ -191,6 +199,9 @@ class DataClient(SocketClient, DataAPI, metaclass=SocketClientMacro(DataAPI)):
|
||||
|
||||
def stop_sync(self, *device: Union[int, Device]):
|
||||
self.send_command('stop_sync', *self._to_device_id(*device))
|
||||
|
||||
def show_data(self, device: int):
|
||||
self.send_command('show_data', device)
|
||||
|
||||
@staticmethod
|
||||
def _to_device_id(*device: Union[int, Device]) -> Tuple[int, ...]:
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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
|
||||
|
||||
@@ -253,6 +253,7 @@ class DeviceInternalCommandHandler:
|
||||
return True
|
||||
|
||||
|
||||
# why inherit MasterDevice ?
|
||||
class DeviceManager(MasterDevice, Synchronized):
|
||||
"""device manager. It manager the device libraries, found device, connected device
|
||||
and the control of the master device.
|
||||
@@ -267,7 +268,6 @@ class DeviceManager(MasterDevice, Synchronized):
|
||||
options: DeviceManagerOptions,
|
||||
handler: Optional[DeviceInternalCommandHandler] = None):
|
||||
"""
|
||||
|
||||
:param options: manager options.
|
||||
:param handler: device internal command handler
|
||||
"""
|
||||
@@ -277,6 +277,7 @@ class DeviceManager(MasterDevice, Synchronized):
|
||||
if handler is None:
|
||||
handler = DeviceInternalCommandHandler()
|
||||
|
||||
# control server api
|
||||
self._handler: DeviceInternalCommandHandler = handler
|
||||
self._options: DeviceManagerOptions = options
|
||||
|
||||
@@ -286,7 +287,9 @@ class DeviceManager(MasterDevice, Synchronized):
|
||||
# hardware
|
||||
self._interface = options.interface
|
||||
self._master: Optional[MasterDevice] = None
|
||||
# memory board
|
||||
self._centralMaster: Optional[MasterDevice] = None
|
||||
# connected device
|
||||
self._device: List[CompletedDevice] = []
|
||||
|
||||
# demo device
|
||||
@@ -336,6 +339,10 @@ class DeviceManager(MasterDevice, Synchronized):
|
||||
def library_path(self) -> List[Path]:
|
||||
return self._repository.library_path
|
||||
|
||||
def get_device_status(self, mac_address) -> Optional[DeviceLibrary]:
|
||||
device = self.get_device(mac_address)
|
||||
return device.status
|
||||
|
||||
@logging_info
|
||||
def reload_library(self):
|
||||
"""reload device library"""
|
||||
@@ -562,7 +569,6 @@ 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
|
||||
@@ -1024,15 +1030,9 @@ class DeviceManager(MasterDevice, Synchronized):
|
||||
raise RuntimeError(DEVICE_NOT_FOUND, device)
|
||||
|
||||
if DeviceCommonInstruction(instruction) is not None:
|
||||
# print('deviceCommonInstr')
|
||||
# print(instruction)
|
||||
device.call_instruction(instruction)
|
||||
|
||||
elif instruction in device.library.instruction_table:
|
||||
# print('instruction')
|
||||
# print(instruction)
|
||||
device.call_instruction(instruction)
|
||||
|
||||
else:
|
||||
raise RuntimeError(INSTRUCTION_UNKNOWN, instruction)
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -853,7 +853,7 @@ class I4V4Z4T4DataDecoder(RecDataDecoder):
|
||||
|
||||
__slots__ = ('_message', '_cycle_number', '_start_return_data', '_time_stamp',
|
||||
'_total_time_stamp', '_mode', '_cycle_start_time',
|
||||
'_mode_stop')
|
||||
'_mode_stop', '_show_data')
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
@@ -868,6 +868,8 @@ class I4V4Z4T4DataDecoder(RecDataDecoder):
|
||||
self._mode = 0
|
||||
self._cycle_start_time = []
|
||||
|
||||
self._show_data = False
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return self.NAME
|
||||
@@ -881,22 +883,20 @@ class I4V4Z4T4DataDecoder(RecDataDecoder):
|
||||
def decode(self, data: bytes) -> Optional[RecordingData]:
|
||||
if len(data) < 18:
|
||||
return None
|
||||
voltage = 0
|
||||
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
|
||||
|
||||
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]
|
||||
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 +917,14 @@ class I4V4Z4T4DataDecoder(RecDataDecoder):
|
||||
print("error timeStamp full data:", list(data), datetime.now(), '\n')
|
||||
return None
|
||||
else:
|
||||
# print('|', time_stamp, '|', delta, '|', current, '|', voltage, '|', impedance,
|
||||
# '|', cycle_number, '|', finishMode, '@', str(self.device))
|
||||
if self._show_data:
|
||||
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 +932,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 +949,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(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))
|
||||
|
||||
|
||||
# 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)
|
||||
|
||||
if cycle_number != self._cycle_number:
|
||||
# notify cycle_number change
|
||||
@@ -1396,39 +1400,33 @@ class EISZeroOneDataDecoder(RecDataDecoder):
|
||||
hsrtia_a.append(struct.unpack('>i', cali_coeff[index+1:index+5])[0]/1e8)
|
||||
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_d.append(struct.unpack('>B', cali_coeff[index+13:index+14])[0])
|
||||
|
||||
#Lv[1] 20k
|
||||
index = 80
|
||||
hsrtia_a.append(struct.unpack('>i', cali_coeff[index+1:index+5])[0]/1e8)
|
||||
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_d.append(struct.unpack('>B', cali_coeff[index+13:index+14])[0])
|
||||
|
||||
#Lv[2] 5k
|
||||
index = 100
|
||||
hsrtia_a.append(struct.unpack('>i', cali_coeff[index+1:index+5])[0]/1e8)
|
||||
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_d.append(struct.unpack('>B', cali_coeff[index+13:index+14])[0])
|
||||
|
||||
#Lv[3] 200R
|
||||
index = 120
|
||||
hsrtia_a.append(struct.unpack('>i', cali_coeff[index+1:index+5])[0]/1e8)
|
||||
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_d.append(struct.unpack('>B', cali_coeff[index+13:index+14])[0])
|
||||
|
||||
# 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)
|
||||
# hsrtia_d.append(struct.unpack('>I', cali_coeff[index+13:index+17])[0]/1e6)
|
||||
|
||||
# print('cutoff_freq', cutoff_freq)
|
||||
# print('hsrtia_a', hsrtia_a)
|
||||
# print('hsrtia_b', hsrtia_b)
|
||||
# print('hsrtia_c', hsrtia_c)
|
||||
# print('hsrtia_d', hsrtia_d)
|
||||
# print('phase_para_a', phase_para_a)
|
||||
# print('phase_para_b', phase_para_b)
|
||||
|
||||
@@ -1456,12 +1454,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
|
||||
|
||||
@@ -1585,10 +1583,10 @@ class EISZeroOneDataDecoder(RecDataDecoder):
|
||||
|
||||
ret = RecordingData(self.device, int(time_stamp * 1000 / 2), 0)
|
||||
if (self._mode == 0): #EIS Mode
|
||||
ret.append_data(3, cycle_number)
|
||||
ret.append_data(0, ch1) #Raw Imag
|
||||
ret.append_data(1, ch2) #Raw Real
|
||||
ret.append_data(2, ch3 * 10) #Frequency [mHz]
|
||||
ret.append_data(3, cycle_number)
|
||||
ret.append_data(4, round(imag_after_cal)) #Z_imag [Ohm]
|
||||
ret.append_data(5, round(real_after_cal)) #Z_real [Ohm]
|
||||
ret.append_data(6, round(impedance)) #Impedance [Ohm]
|
||||
@@ -1597,10 +1595,10 @@ class EISZeroOneDataDecoder(RecDataDecoder):
|
||||
ret.append_data(9, gain) #Gain Level
|
||||
|
||||
else: #CV Mode
|
||||
ret.append_data(3, cycle_number)
|
||||
ret.append_data(0, ch1) #Iin [nA]
|
||||
ret.append_data(1, ch2) #Vset [nV]
|
||||
ret.append_data(2, ch3) #Vout [nV]
|
||||
ret.append_data(3, cycle_number)
|
||||
|
||||
if cycle_number != self._cycle_number:
|
||||
# notify cycle_number change
|
||||
|
||||
@@ -651,17 +651,9 @@ class DeviceInstruction:
|
||||
VIS_DEVICE_DONE = 0x20
|
||||
"""identify device done"""
|
||||
|
||||
VIS_CC_ZERO = 0x40
|
||||
|
||||
VIS_ASK = 0x30
|
||||
"""ask in virtual instruction"""
|
||||
|
||||
VIS_STI = 0xC0
|
||||
"""stimulation on virtual instruction"""
|
||||
|
||||
VIS_FUH = 0x90
|
||||
"""flush virtual instruction"""
|
||||
|
||||
VIS_INT = 0x60
|
||||
"""interrupt virtual instruction"""
|
||||
|
||||
@@ -732,7 +724,6 @@ class DeviceCommonInstruction:
|
||||
STOP_STIMULATE = "stop_stimulate"
|
||||
VIS_DEVICE_DETECT = 'VIS_DEVICE_DETECT'
|
||||
VIS_DEVICE_DONE = 'VIS_DEVICE_DONE'
|
||||
VIS_CC_ZERO = 'VIS_CC_ZERO'
|
||||
CIS_VOLT = 'CIS_VOLT'
|
||||
CIS_VERSION = 'CIS_VERSION'
|
||||
|
||||
@@ -750,16 +741,12 @@ class DeviceCommonInstruction:
|
||||
return '_sync(False)', '_notify(False)', 'VIS_INT'
|
||||
elif instruction == cls.CLOSE:
|
||||
return '_sync(False)', '_notify(False)', 'VIS_INT'
|
||||
elif instruction == cls.FLUSH:
|
||||
return 'VIS_FUH',
|
||||
elif instruction == cls.CALL:
|
||||
return 'VIS_CAL',
|
||||
elif instruction == cls.VIS_DEVICE_DETECT:
|
||||
return 'VIS_DEVICE_DETECT',
|
||||
elif instruction == cls.VIS_DEVICE_DONE:
|
||||
return 'VIS_DEVICE_DONE',
|
||||
elif instruction == cls.VIS_CC_ZERO:
|
||||
return 'VIS_CC_ZERO',
|
||||
elif instruction == cls.RECORD:
|
||||
return 'VIS_STARTR',
|
||||
elif instruction == cls.RECORD_ALL:
|
||||
|
||||
@@ -4,6 +4,7 @@ from biopro.util.text import part_suffix
|
||||
from . import *
|
||||
from .expression import *
|
||||
|
||||
import json
|
||||
|
||||
class DeviceParameterError(RuntimeError):
|
||||
__slots__ = ()
|
||||
@@ -309,6 +310,8 @@ class ParameterValueDomain(ParameterDomain, metaclass=abc.ABCMeta):
|
||||
return f
|
||||
|
||||
def valid_para(self, value: Any) -> bool:
|
||||
if isinstance(value, list):
|
||||
return True
|
||||
f, t = self.range
|
||||
return f <= float(value) < t
|
||||
|
||||
@@ -489,8 +492,12 @@ class ParameterCollectionValueOperator(metaclass=abc.ABCMeta):
|
||||
|
||||
@classmethod
|
||||
def parse(cls, expr: Union[int, str]) -> 'ParameterCollectionValueOperator':
|
||||
# parse epression then create value_operator
|
||||
if isinstance(expr, int):
|
||||
return SingleValueOperator(None, expr)
|
||||
|
||||
elif isinstance(expr, list):
|
||||
return CollectValueOperator((0, len(expr)), expr)
|
||||
|
||||
elif expr == '*':
|
||||
return AddAllValueOperator
|
||||
@@ -498,6 +505,10 @@ class ParameterCollectionValueOperator(metaclass=abc.ABCMeta):
|
||||
elif expr == ':=':
|
||||
return CollectValueOperator((None, None), [])
|
||||
|
||||
elif '[' in expr and ']' in expr:
|
||||
v = json.loads(expr)
|
||||
return CollectValueOperator((0, len(v)), v)
|
||||
|
||||
elif '=' in expr:
|
||||
a, v = part_suffix(expr, '=')
|
||||
|
||||
@@ -508,6 +519,7 @@ class ParameterCollectionValueOperator(metaclass=abc.ABCMeta):
|
||||
return CollectValueOperator((None, None), v)
|
||||
|
||||
else:
|
||||
# get list length (old way)
|
||||
a, b = part_suffix(a, ':')
|
||||
a = int(a) if len(a) else None
|
||||
b = int(b) if len(b) else None
|
||||
@@ -602,8 +614,8 @@ class ParameterCollectionDomain(ParameterDomain, metaclass=abc.ABCMeta):
|
||||
def __init__(self, domain: ParameterDomain):
|
||||
super().__init__()
|
||||
|
||||
if isinstance(domain, ParameterCollectionDomain):
|
||||
raise RuntimeError('cannot compose with parameter collection domain')
|
||||
# if isinstance(domain, ParameterCollectionDomain):
|
||||
# raise RuntimeError('cannot compose with parameter collection domain')
|
||||
|
||||
self._domain = domain
|
||||
|
||||
@@ -725,6 +737,7 @@ class ParameterListDomain(ParameterCollectionDomain):
|
||||
if oper == AddAllValueOperator:
|
||||
raise ValueError("list parameter cannot accept '*' (all) value")
|
||||
|
||||
# d: domain, sz: lsit length, i: slice(a, b), v: list value
|
||||
d = self.element_domain
|
||||
sz = len(target)
|
||||
i = oper.index(sz)
|
||||
|
||||
@@ -119,7 +119,10 @@ class DeviceConfigurationEncoder:
|
||||
e.write(b'L\0')
|
||||
|
||||
else:
|
||||
parameter_type = cls._value_type(value[0])
|
||||
parameter_type = cls._value_type(max(value))
|
||||
for v in value:
|
||||
if isinstance(v, int) and v < 0:
|
||||
parameter_type = parameter_type.lower()
|
||||
e.write(b'L')
|
||||
e.write(parameter_type.encode())
|
||||
e.u8(sz)
|
||||
@@ -153,7 +156,8 @@ class DeviceConfigurationEncoder:
|
||||
if isinstance(value, bool):
|
||||
e.u8(1 if value else 0)
|
||||
|
||||
elif isinstance(value, str):
|
||||
elif isinstance(value, str) or isinstance(value, list):
|
||||
value = str(value)
|
||||
e.encode_string(value)
|
||||
|
||||
elif isinstance(value, int):
|
||||
@@ -170,7 +174,7 @@ class DeviceConfigurationEncoder:
|
||||
if isinstance(value, bool):
|
||||
return '?'
|
||||
|
||||
elif isinstance(value, str):
|
||||
elif isinstance(value, str) or isinstance(value, list):
|
||||
return 'p'
|
||||
|
||||
elif isinstance(value, int):
|
||||
|
||||
@@ -1268,14 +1268,15 @@ class InstructionTable(DictNode['Instruction']):
|
||||
instruction: str):
|
||||
"""call instruction. chain context with :class:`DeviceInternalInstructionScope`
|
||||
|
||||
:param master: master device
|
||||
:param device: device
|
||||
:param master: DeviceManager
|
||||
:param device: CompletedDevice
|
||||
:param context: scope
|
||||
:param instruction: instruction name
|
||||
:raises InstructionNotFound: If instruction not found.
|
||||
"""
|
||||
|
||||
try:
|
||||
# ex. start
|
||||
ins = self[instruction]
|
||||
|
||||
except KeyError as e:
|
||||
@@ -1284,6 +1285,7 @@ class InstructionTable(DictNode['Instruction']):
|
||||
else:
|
||||
context = context.chain(InstructionTableScope(self))
|
||||
|
||||
# ex. _data_format, _sync, _notify
|
||||
for single in ins.eval_instruction(context):
|
||||
if isinstance(single, InternalInstruction):
|
||||
if not single.handle_internal_instruction(master, device, context):
|
||||
|
||||
@@ -510,9 +510,10 @@ class DeviceParameter(JsonSerialize):
|
||||
:param para: parameter name
|
||||
:param oper: operator expression
|
||||
"""
|
||||
# parse operator return CollectValueOperator instance
|
||||
if not isinstance(oper, ParameterCollectionValueOperator):
|
||||
oper = ParameterCollectionValueOperator.parse(oper)
|
||||
|
||||
|
||||
table = self._library.parameter_table
|
||||
info = table[para]
|
||||
domain = info.domain
|
||||
@@ -528,6 +529,7 @@ class DeviceParameter(JsonSerialize):
|
||||
old = list(target)
|
||||
|
||||
try:
|
||||
# replace target with new oper
|
||||
domain.oper_para(target, oper, self._context)
|
||||
except RuntimeError as e:
|
||||
raise IllegalParameterValueError(para, str(oper)) from e
|
||||
@@ -966,7 +968,7 @@ class CompletedDevice(Device):
|
||||
"""
|
||||
__slots__ = ('_master', '_device_id', '_device', '_library', '_context',
|
||||
'_parameter', '_configuration', '_lock', '_feature_mask',
|
||||
'_cache_battery', '_cache_battery_timestamp', '_coeff')
|
||||
'_cache_battery', '_cache_battery_timestamp', '_coeff', '_status')
|
||||
|
||||
def __init__(self, master: MasterDevice, library: DeviceLibrary, device_id: int, device: Device):
|
||||
"""
|
||||
@@ -976,11 +978,15 @@ class CompletedDevice(Device):
|
||||
:param device_id: device id
|
||||
:param device: slave device implementation
|
||||
"""
|
||||
# DeviceManager
|
||||
self._master = master
|
||||
self._device = device
|
||||
self._device_id = device_id
|
||||
self._library = library
|
||||
|
||||
# device status ( 0: idle, 1: working, 2: error, 3: power off)
|
||||
self._status = 0
|
||||
|
||||
# context
|
||||
s1 = library.constant
|
||||
s2 = DeviceScope(self)
|
||||
@@ -1008,6 +1014,10 @@ class CompletedDevice(Device):
|
||||
def device_id(self) -> int:
|
||||
return self._device_id
|
||||
|
||||
@property
|
||||
def memory_board(self) -> int:
|
||||
return self._device_id
|
||||
|
||||
@property
|
||||
def device_name(self) -> str:
|
||||
return self._device.device_name
|
||||
@@ -1020,6 +1030,10 @@ class CompletedDevice(Device):
|
||||
def mac_address(self) -> ADDRESS:
|
||||
return self._device.mac_address
|
||||
|
||||
@property
|
||||
def mac_address_in_str(self) -> str:
|
||||
return ':'.join('{:02x}'.format(b) for b in self._device.mac_address)
|
||||
|
||||
@property
|
||||
def device(self) -> Device:
|
||||
return self._device
|
||||
@@ -1056,11 +1070,18 @@ class CompletedDevice(Device):
|
||||
return self._library
|
||||
|
||||
# device lock
|
||||
|
||||
@property
|
||||
def lock(self) -> DeviceLock:
|
||||
return self._lock
|
||||
|
||||
@property
|
||||
def status(self) -> int:
|
||||
return self._status
|
||||
|
||||
@status.setter
|
||||
def status(self, new_status):
|
||||
self._status = new_status
|
||||
|
||||
# device parameter getter/setter
|
||||
|
||||
def parameters(self) -> List[str]:
|
||||
@@ -1115,7 +1136,8 @@ class CompletedDevice(Device):
|
||||
self._master.log_warn('on_change instruction not found : ' + on_change)
|
||||
|
||||
else:
|
||||
self.call_instruction(on_change)
|
||||
if self._status == 1:
|
||||
self.call_instruction(on_change)
|
||||
|
||||
# device instruction call
|
||||
|
||||
@@ -1258,14 +1280,20 @@ class CompletedDevice(Device):
|
||||
|
||||
def as_json(self) -> JSON_OBJECT:
|
||||
return {
|
||||
'id': self.device_id,
|
||||
'name': self.device_name,
|
||||
'status': self._status,
|
||||
'device_id': self.device_id,
|
||||
'device_name': self.device_name,
|
||||
'device_address': list(self.mac_address),
|
||||
'device_status': self._status,
|
||||
'mac_address': self.mac_address_in_str,
|
||||
'memory_board': self.memory_board,
|
||||
'serial_number': self.serial_number.as_json(),
|
||||
'version': self.device_version,
|
||||
'battery': self.battery,
|
||||
'parent': self.parent,
|
||||
'recording_file_name': self.recording_file_name,
|
||||
'device_version': self.device_version,
|
||||
'serial_number': self.serial_number.as_json(),
|
||||
'library_name': self._library.name,
|
||||
'library_version': str(self._library.version),
|
||||
'configuration': self.configuration.as_json(list_hide=True),
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+119
-43
@@ -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
|
||||
@@ -74,6 +76,8 @@ class MultiExtMemSpiInterface(LowLevelHardwareInterface):
|
||||
|
||||
def set_pin_mem_req(self, value: bool):
|
||||
channel = self.select
|
||||
# if self._pin_mem_req_value[channel] == value:
|
||||
# print('last_req_sig[channel] == value', channel, self._pin_mem_req_value[channel], value, datetime.now())
|
||||
self.pin_mem_req.output(value)
|
||||
self._pin_mem_req_value[channel] = value
|
||||
|
||||
@@ -165,6 +169,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 +241,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 +260,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 +278,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 +357,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)
|
||||
|
||||
@@ -118,13 +118,13 @@ class Selector:
|
||||
self._p2.output(p[2])
|
||||
|
||||
# if (value == 4 and self._last_sel != 6):
|
||||
# print('mem_sel is not use gray code, value:', value, ', last value:', self._last_sel)
|
||||
# print('mem_sel is not use gray code, value:', value, ', last value:', self._last_sel, datetime.now())
|
||||
# elif (value == 5 and self._last_sel != 4):
|
||||
# print('mem_sel is not use gray code, value:', value, ', last value:', self._last_sel)
|
||||
# print('mem_sel is not use gray code, value:', value, ', last value:', self._last_sel, datetime.now())
|
||||
# elif (value == 7 and self._last_sel != 5):
|
||||
# print('mem_sel is not use gray code, value:', value, ', last value:', self._last_sel)
|
||||
# print('mem_sel is not use gray code, value:', value, ', last value:', self._last_sel, datetime.now())
|
||||
# elif (value == 6 and self._last_sel != 7):
|
||||
# print('mem_sel is not use gray code, value:', value, ', last value:', self._last_sel)
|
||||
# print('mem_sel is not use gray code, value:', value, ', last value:', self._last_sel, datetime.now())
|
||||
|
||||
self._last_sel = value
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,65 +1,26 @@
|
||||
|
||||
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()
|
||||
def __init__(self, action_id, action):
|
||||
self._id: str = action_id
|
||||
self._type: str = action['type']
|
||||
self._target: str = action['target']
|
||||
self._condition : list[str] = action['condition']
|
||||
# self._duration = action.get('duration', None)
|
||||
# self._goto = action.get('goto', None)
|
||||
# self._cycle = action.get('cycle', None)
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
return self._id
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return self._type
|
||||
|
||||
def update_instruction(self):
|
||||
self._instruction = {
|
||||
"device_instruction": {
|
||||
"header": "call_instruction",
|
||||
"device": self._target,
|
||||
"arguments": {
|
||||
"instruction": self._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])
|
||||
|
||||
@property
|
||||
def target(self):
|
||||
return self._target
|
||||
|
||||
@property
|
||||
def condition(self):
|
||||
return self._condition
|
||||
|
||||
@@ -3,70 +3,91 @@ from time import time
|
||||
|
||||
class Condition():
|
||||
def __init__(self, id, condition):
|
||||
print('condition', id, condition)
|
||||
self._id = id
|
||||
self._type = condition['type']
|
||||
self._comparsion = condition['comparsion']
|
||||
self._value = condition['value']
|
||||
self._active = False
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
return self._id
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return self._type
|
||||
|
||||
@property
|
||||
def comparsion(self):
|
||||
return self._comparsion
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
return self._value
|
||||
|
||||
def set_comparsion(self, comparsion):
|
||||
self._comparsion = comparsion
|
||||
|
||||
def set_type(self, type):
|
||||
self._type = type
|
||||
@id.setter
|
||||
def id(self, new_id):
|
||||
self._id = new_id
|
||||
|
||||
def set_value(self, value):
|
||||
self._value = value
|
||||
@type.setter
|
||||
def type(self, new_type):
|
||||
self._type = new_type
|
||||
|
||||
def compareWith(self, operator:str, x, y) -> bool:
|
||||
@comparsion.setter
|
||||
def comparsion(self, new_comparsion):
|
||||
self._comparsion = new_comparsion
|
||||
|
||||
@value.setter
|
||||
def value(self, new_value):
|
||||
self._value = new_value
|
||||
|
||||
def compareWith(self, operator, x, y) -> bool:
|
||||
# print(operator, x, y)
|
||||
cases = {
|
||||
"equal": lambda a, b: a == b,
|
||||
"bigger": lambda a, b: a > b,
|
||||
"smaller": lambda a, b: a < b,
|
||||
}
|
||||
|
||||
# print('x','y',x, y,type(x),type(y))
|
||||
return cases[operator](x, y)
|
||||
|
||||
def match_or_not(self, **kwargs):
|
||||
return self.method_mapping(self.type)()
|
||||
# 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))
|
||||
now = int(time())
|
||||
time_condition = round(self.datetime_to_timestamp(self.str_to_datetime(self._value)))
|
||||
|
||||
return self.compareWith(self.comparsion, int(now), int(time_condition))
|
||||
return self.compareWith(self.comparsion, now, time_condition)
|
||||
|
||||
def relative_time(self, **kwargs):
|
||||
now = time()
|
||||
def after_project_run(self, **kwargs):
|
||||
project_start_time = kwargs['project_start_time']
|
||||
delay_time = kwargs['delay_time']
|
||||
|
||||
time_diff = int(time() - project_start_time - delay_time)
|
||||
return self.compareWith(self.comparsion, time_diff, int(self._value))
|
||||
|
||||
def after_task_run(self, **kwargs):
|
||||
# print('relative_time_from_task', kwargs,kwargs['task_start_time'],kwargs['delay_time'])
|
||||
if len(kwargs['task_start_time']) == 0:
|
||||
return False
|
||||
task_start_time = kwargs['task_start_time'][-1]
|
||||
delay_time = kwargs['delay_time']
|
||||
|
||||
time_diff = int(time() - task_start_time - delay_time)
|
||||
# print('time_diff', time_diff)
|
||||
return self.compareWith(self.comparsion, time_diff, int(self._value))
|
||||
|
||||
def device(self, **kwargs):
|
||||
print('device')
|
||||
|
||||
def 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 previous_task_done(self, **kwargs):
|
||||
running_task = kwargs['running_task']
|
||||
if running_task.status == 2 and self._active == False:
|
||||
self._active = True
|
||||
return True
|
||||
return False
|
||||
|
||||
def str_to_datetime(self, time_str):
|
||||
return datetime.strptime(time_str,'%Y-%m-%dT%H:%M')
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
|
||||
class Instruction():
|
||||
def __init__(self):
|
||||
self._instruction_set = {
|
||||
'set_file_name': {
|
||||
'method': 'update_recording_file_name_info',
|
||||
'arguments': ['file_name']
|
||||
},
|
||||
'set_parent': {
|
||||
'method': 'update_parent_info',
|
||||
'arguments': ['parent']
|
||||
},
|
||||
'set_parameter':{
|
||||
'method': 'set_multi_parameters',
|
||||
'arguments': ['parameter']
|
||||
},
|
||||
'call_instruction': {
|
||||
'method': 'call_instruction',
|
||||
'arguments': ['instruction']
|
||||
},
|
||||
}
|
||||
|
||||
self._start_instruction = list(map(lambda ins: self._instruction_set[ins] ,['set_file_name', 'set_parent', 'set_parameter', 'call_instruction']))
|
||||
self._stop_instruction = list(map(lambda ins: self._instruction_set[ins] ,['call_instruction']))
|
||||
|
||||
@property
|
||||
def start(self) -> list:
|
||||
return self._start_instruction
|
||||
|
||||
@property
|
||||
def stop(self) -> list:
|
||||
return self._stop_instruction
|
||||
@@ -1,14 +1,23 @@
|
||||
from .task import Task
|
||||
from .task_manager import TaskManager
|
||||
import sys
|
||||
import json
|
||||
import threading
|
||||
import time
|
||||
|
||||
from time import time, sleep
|
||||
from datetime import datetime
|
||||
from collections import deque
|
||||
from copy import copy
|
||||
from uuid import uuid4
|
||||
|
||||
from .task import Task
|
||||
from .task_manager import TaskManager
|
||||
from .instruction import Instruction
|
||||
from biopro.device.manager import DeviceManager
|
||||
from biopro.text import *
|
||||
|
||||
key_list = {
|
||||
'deviceList': 'device',
|
||||
}
|
||||
|
||||
class Project(threading.Thread):
|
||||
def __init__(self, project, device_manager: DeviceManager, mqttThread = None, name="project"):
|
||||
super(Project, self).__init__(name = name)
|
||||
@@ -17,62 +26,202 @@ class Project(threading.Thread):
|
||||
self._mqtt_thread = mqttThread
|
||||
self._time_interval = 1
|
||||
self._start_time = None
|
||||
self._end_time = None
|
||||
|
||||
self._task_manager = TaskManager(self._project['taskList'])
|
||||
self._id = None
|
||||
self._uuid = str(uuid4())
|
||||
self._name = None
|
||||
self._desc = None
|
||||
self._device = None
|
||||
self._complete_device = []
|
||||
self._status = 0
|
||||
|
||||
self._instruction_set = Instruction()
|
||||
self._stop_flag = False
|
||||
|
||||
self._task_manager = None
|
||||
|
||||
self.setup_project(project)
|
||||
self.setup_device(self._device)
|
||||
|
||||
def setup_project(self, project):
|
||||
for (key, value) in project.items():
|
||||
if key in key_list.keys():
|
||||
key = key_list[key]
|
||||
|
||||
if key == 'task':
|
||||
self._task_manager = TaskManager(project['task'])
|
||||
elif key == 'uuid':
|
||||
pass
|
||||
else:
|
||||
setattr(self, key, value)
|
||||
|
||||
def setup_device(self, device_list):
|
||||
for device in device_list:
|
||||
complete_device = self._device_manager.get_device(device['connectDevice']['device_address'])
|
||||
self._complete_device.append(complete_device)
|
||||
|
||||
@property
|
||||
def id(self) -> int:
|
||||
return self._id
|
||||
|
||||
@id.setter
|
||||
def id(self, new_id):
|
||||
self._id = new_id
|
||||
|
||||
@property
|
||||
def uuid(self) -> str:
|
||||
return self._uuid
|
||||
|
||||
@uuid.setter
|
||||
def uuid(self, new_uuid):
|
||||
self._uuid = new_uuid
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return self._name
|
||||
|
||||
@name.setter
|
||||
def name(self, new_name):
|
||||
self._name = new_name
|
||||
|
||||
self._start_time = None
|
||||
|
||||
@property
|
||||
def desc(self) -> str:
|
||||
return self._project['desc']
|
||||
return self._desc
|
||||
|
||||
@desc.setter
|
||||
def desc(self, new_desc):
|
||||
self._desc = new_desc
|
||||
|
||||
@property
|
||||
def status(self) -> str:
|
||||
return self._project['status']
|
||||
return self._status
|
||||
|
||||
@status.setter
|
||||
def status(self, new_status):
|
||||
self._status = new_status
|
||||
|
||||
@property
|
||||
def device(self) -> list:
|
||||
return self._project['deviceList']
|
||||
return self._device
|
||||
|
||||
@device.setter
|
||||
def device(self, new_device):
|
||||
self._device = new_device
|
||||
|
||||
@property
|
||||
def task_list(self):
|
||||
return self._task_manager.export_task_list
|
||||
|
||||
@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 mqtt_thread(self):
|
||||
return self._mqtt_thread
|
||||
|
||||
def run(self):
|
||||
self._start_time = time.time()
|
||||
self._status = 1
|
||||
self._start_time = time()
|
||||
self.mqtt_thread.broadcast_command('project:' + self._name + ' start at ' + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
|
||||
|
||||
while not self._stop_flag :
|
||||
# check running task first
|
||||
delay_time = 0
|
||||
check_list = copy(self._task_manager.check_list)
|
||||
|
||||
while True:
|
||||
# current task
|
||||
for task in self._task_manager.get_check_task_list():
|
||||
# [<match_condition>, ...]
|
||||
match_condition_list = task.check_condition('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':
|
||||
self._task_manager.set_current_task(task)
|
||||
task.do_action(action)
|
||||
|
||||
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'])
|
||||
for task in check_list:
|
||||
if task != None:
|
||||
now = time()
|
||||
# print('round task', task.name)
|
||||
# print('running task', self._task_manager.running_task.name, self._task_manager.running_task.status)
|
||||
# if self._task_manager.prev_task != None:
|
||||
# print('previous_task', self._task_manager.prev_task.name, self._task_manager.prev_task.status)
|
||||
|
||||
if device is None:
|
||||
raise RuntimeError(DEVICE_NOT_FOUND, device)
|
||||
match_condition_list = task.check_condition(
|
||||
project_start_time = self._start_time,
|
||||
delay_time = delay_time,
|
||||
running_task= self._task_manager.running_task,
|
||||
previous_task = self._task_manager.prev_task
|
||||
)
|
||||
# print('match_condition_list', match_condition_list)
|
||||
for condition in match_condition_list:
|
||||
match_action_list = task.get_match_action(condition.id)
|
||||
for action in match_action_list:
|
||||
# print('match_action', action.type, action.target)
|
||||
if action.type == 'start' and task.status != 1:
|
||||
self._task_manager.set_running_task(task)
|
||||
self.mqtt_thread.broadcast_command('project:task ' + task.name + ' start at ' + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
|
||||
|
||||
device = self._complete_device[action.target]
|
||||
task_info = task.get_task_info(action)
|
||||
instruction_set = getattr(self._instruction_set, action.type, None)
|
||||
# print('instruction_set',instruction_set)
|
||||
|
||||
# print(instruction['header'], *instruction['arguments'].values())
|
||||
getattr(device, instruction['header'])(*instruction['arguments'].values())
|
||||
if instruction_set != None:
|
||||
for instruction in instruction_set:
|
||||
args = list(map(lambda arg: task_info[arg], instruction['arguments']))
|
||||
threading.Thread(target=getattr(device, instruction['method'])(*args))
|
||||
|
||||
delay_time += (time() - now)
|
||||
|
||||
# check task not running then stop
|
||||
if self.check_running_task_not_run() == True:
|
||||
self.mqtt_thread.broadcast_command('project:task ' + str(self._task_manager.running_task.name) + ' stop at ' + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
|
||||
self._task_manager.running_task.stop()
|
||||
|
||||
# check project done then close project
|
||||
if self.check_project_done() == True:
|
||||
print('project stop at', datetime.now())
|
||||
self.close()
|
||||
|
||||
if self._time_interval - delay_time > 0:
|
||||
sleep(self._time_interval - delay_time)
|
||||
|
||||
def pause(self):
|
||||
# TODO
|
||||
pass
|
||||
|
||||
time.sleep(self._time_interval)
|
||||
def stop(self):
|
||||
return
|
||||
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
|
||||
self._end_time = time()
|
||||
self._stop_flag = True
|
||||
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):
|
||||
return
|
||||
self._status = 2
|
||||
self._end_time = time()
|
||||
self._stop_flag = True
|
||||
self.mqtt_thread.broadcast_command('project:project ' + str(self._name) + ' stop at ' + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
|
||||
|
||||
def check_project_done(self):
|
||||
for task in self._task_manager.task_list:
|
||||
# if task never start or still task is running then reject
|
||||
if task.status == 1 or task.status == -1:
|
||||
return False
|
||||
return True
|
||||
|
||||
def check_running_task_not_run(self):
|
||||
# if no running task
|
||||
if self._task_manager.running_task == None:
|
||||
return False
|
||||
|
||||
for device in self._task_manager.running_task.device:
|
||||
if self._complete_device[device].status == 1:
|
||||
return False
|
||||
return True
|
||||
|
||||
def as_json(self):
|
||||
running_task = None
|
||||
if self._task_manager.running_task is not None:
|
||||
running_task = self._task_manager.running_task.as_json()
|
||||
data = {
|
||||
'id': self._id,
|
||||
'name': self._name,
|
||||
'uuid': self._uuid,
|
||||
'desc': self._desc,
|
||||
'status': self._status,
|
||||
'device': self._device,
|
||||
'task': self.task_list,
|
||||
'running_task': running_task
|
||||
}
|
||||
return data
|
||||
|
||||
@@ -18,16 +18,22 @@ class ProjectManager():
|
||||
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 get(self, project_uuid = None):
|
||||
if project_uuid == None:
|
||||
return self._project_list
|
||||
else:
|
||||
for project in self._project_list:
|
||||
if project.uuid == project_uuid:
|
||||
return project
|
||||
|
||||
def run(self, project):
|
||||
def run_project(self, project):
|
||||
project.start()
|
||||
|
||||
def stop(self, project):
|
||||
project.stop()
|
||||
def stop_project(self, project):
|
||||
_project = self.get(project)
|
||||
_project.stop()
|
||||
|
||||
+202
-118
@@ -1,110 +1,187 @@
|
||||
from typing import List
|
||||
from .condition import Condition
|
||||
from .action import Action
|
||||
from time import time
|
||||
from datetime import datetime
|
||||
|
||||
key_list = {
|
||||
'deviceList': 'device',
|
||||
'parameterSet': 'parameter_set'
|
||||
}
|
||||
|
||||
class Task:
|
||||
def __init__(self, task):
|
||||
self._task = task
|
||||
|
||||
self._condition_list = []
|
||||
self._action_list = []
|
||||
|
||||
self._start_time = time()
|
||||
self._idle_time = []
|
||||
self._period = None
|
||||
self._next_time = None
|
||||
self._last_time = None
|
||||
self._id = None
|
||||
self._name = None
|
||||
self._parent = None
|
||||
self._cycle = None
|
||||
self._device = None
|
||||
self._event = None
|
||||
self._trigger = None
|
||||
self._parameter_set = None
|
||||
self._condition = None
|
||||
self._action = None
|
||||
# -1: initial 0: start(idle), 1: running, 2: close(idle)
|
||||
self._status = 0
|
||||
self._next = None
|
||||
|
||||
self._condition_list: List[Condition] = []
|
||||
self._action_list: List[Action] = []
|
||||
self._instruction_list = []
|
||||
self._record_list = []
|
||||
|
||||
self.setup()
|
||||
self._start_time = []
|
||||
self._idle_time = []
|
||||
self._end_time = []
|
||||
self._period = None
|
||||
|
||||
self.load_task(task)
|
||||
|
||||
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)
|
||||
def load_task(self, task) -> None:
|
||||
# update task attribute
|
||||
for key, value in task.items():
|
||||
if key in key_list.keys():
|
||||
key = key_list[key]
|
||||
if key == 'condition':
|
||||
self.update_condition_list(value)
|
||||
if key == 'action':
|
||||
self.update_action_list(value)
|
||||
# print(key, value)
|
||||
setattr(self, key, value)
|
||||
|
||||
# add action
|
||||
for key, action in self._task['action'].items():
|
||||
new_action = Action(self, key, action)
|
||||
self._action_list.append(new_action)
|
||||
def update_condition_list(self, condition_dict):
|
||||
self._condition_list.clear()
|
||||
for key, condition in condition_dict.items():
|
||||
self._condition_list.append(Condition(key, condition))
|
||||
|
||||
def update_action_list(self, action_dict):
|
||||
self._action_list.clear()
|
||||
for key, action in action_dict.items():
|
||||
self._action_list.append(Action(key, action))
|
||||
|
||||
@property
|
||||
def id(self) -> str:
|
||||
return self._task['id']
|
||||
return self._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']
|
||||
@id.setter
|
||||
def id(self, new_id):
|
||||
self._id = new_id
|
||||
|
||||
@property
|
||||
def uuid(self) -> str:
|
||||
return self._task['uuid']
|
||||
return self._uuid
|
||||
|
||||
@uuid.setter
|
||||
def uuid(self, new_uuid):
|
||||
self._uuid = new_uuid
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
@name.setter
|
||||
def name(self, new_name):
|
||||
self._name = new_name
|
||||
|
||||
@property
|
||||
def parent(self):
|
||||
if self._parent == None:
|
||||
return {"folder": [2]}
|
||||
return self._parent
|
||||
|
||||
@parent.setter
|
||||
def parent(self, new_parent):
|
||||
self._parent = new_parent
|
||||
|
||||
@property
|
||||
def cycle(self) -> int:
|
||||
return self._cycle
|
||||
|
||||
@cycle.setter
|
||||
def cycle(self, new_cycle):
|
||||
self._cycle = new_cycle
|
||||
|
||||
@property
|
||||
def device(self) -> dict:
|
||||
return self._device
|
||||
|
||||
@device.setter
|
||||
def device(self, new_device):
|
||||
self._device = new_device
|
||||
|
||||
@property
|
||||
def event(self) -> list:
|
||||
return self._event
|
||||
|
||||
@event.setter
|
||||
def event(self, new_event):
|
||||
self._event = new_event
|
||||
|
||||
@property
|
||||
def trigger(self) -> list:
|
||||
return self._trigger
|
||||
|
||||
@trigger.setter
|
||||
def trigger(self, new_trigger):
|
||||
self._trigger = new_trigger
|
||||
|
||||
@property
|
||||
def parameter_set(self) -> list:
|
||||
return self._parameter_set
|
||||
|
||||
@parameter_set.setter
|
||||
def parameter_set(self, new_parameter_set):
|
||||
self._parameter_set = new_parameter_set
|
||||
|
||||
@property
|
||||
def condition(self) -> list:
|
||||
return self._condition
|
||||
|
||||
@condition.setter
|
||||
def condition(self, new_condition):
|
||||
self._condition = new_condition
|
||||
|
||||
@property
|
||||
def action(self) -> list:
|
||||
return self._action
|
||||
|
||||
@action.setter
|
||||
def action(self, new_action):
|
||||
self._action = new_action
|
||||
|
||||
@property
|
||||
def status(self) -> str:
|
||||
return self._status
|
||||
|
||||
@status.setter
|
||||
def status(self, new_status):
|
||||
self._status = new_status
|
||||
|
||||
@property
|
||||
def next(self) -> str:
|
||||
return self._task['next']
|
||||
return self._next
|
||||
|
||||
@next.setter
|
||||
def next(self, new_next):
|
||||
self._next = new_next
|
||||
|
||||
@property
|
||||
def instruction_list(self) -> List:
|
||||
return self._instruction_list
|
||||
|
||||
@property
|
||||
def start_time(self) -> List:
|
||||
return self._start_time
|
||||
|
||||
@property
|
||||
def end_time(self) -> List:
|
||||
return self._end_time
|
||||
|
||||
def new_start_time(self):
|
||||
self._start_time.append(time())
|
||||
|
||||
def new_end_time(self):
|
||||
self._end_time.append(time())
|
||||
|
||||
def get_parameter_set_by_device(self, device):
|
||||
return [parameter_set for parameter_set in self.parameter_set.values() if device == parameter_set['target']]
|
||||
@@ -121,48 +198,55 @@ class Task:
|
||||
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
|
||||
print(self._name, 'run at', datetime.now())
|
||||
self._status = 1
|
||||
self._start_time.append(time())
|
||||
|
||||
def start(self):
|
||||
self.set_status('running')
|
||||
self.status = 1
|
||||
|
||||
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')
|
||||
self.status = 2
|
||||
|
||||
def get_match_action_list(self, match_condition_list):
|
||||
return map(lambda condition: [x for x in self._action_list if condition.id in x.get_condition_list()], match_condition_list)
|
||||
|
||||
def get_match_action(self, condition_id):
|
||||
return [action for action in self._action_list if condition_id in action.condition]
|
||||
|
||||
def do_action(self, action):
|
||||
# # match_action = [x for x in self._action_list if condition_id in x.get_condition_list()]
|
||||
|
||||
# for action in match_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)]
|
||||
|
||||
def get_task_info(self, action):
|
||||
_type = action.type
|
||||
if _type == 'stop':
|
||||
_type = 'interrupt'
|
||||
|
||||
def check_condition(self, type):
|
||||
return [condition for condition in self._condition_list if condition.match_or_not()]
|
||||
return {
|
||||
'device': action.target,
|
||||
'parameter': self.get_parameter_set_by_device(action.target),
|
||||
'file_name': self._name + '-' + str(action.target),
|
||||
'parent': self.parent,
|
||||
'instruction': _type
|
||||
}
|
||||
|
||||
def as_json(self):
|
||||
return {
|
||||
'id': self.id,
|
||||
'name': self.name,
|
||||
'parent': self.parent,
|
||||
'cycle': self.cycle,
|
||||
'device': self.device,
|
||||
'event': self.event,
|
||||
'trigger': self.trigger,
|
||||
'parameter_set': self.parameter_set,
|
||||
'condition': self.condition,
|
||||
'action': self.action,
|
||||
'status': self.status,
|
||||
'next': self.next,
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from json import loads as json_parse, dumps as _json_stringify
|
||||
from typing import Dict, Optional, Any
|
||||
from socket import if_nametoindex
|
||||
from typing import Dict, List, Optional, Any
|
||||
from xml.dom.expatbuilder import parseString
|
||||
import paho.mqtt.client as mqtt
|
||||
from biopro.text import *
|
||||
@@ -12,45 +13,76 @@ def json_stringify(o: Any) -> str:
|
||||
|
||||
class TaskManager():
|
||||
def __init__(self, task_list):
|
||||
self._current_task = None
|
||||
self._task_list = []
|
||||
self._need_to_check_task_list = []
|
||||
self._next_task = []
|
||||
self._prev_task = None
|
||||
self._running_task = None
|
||||
|
||||
self.load_task_list(task_list)
|
||||
|
||||
# self.set_running_task(self._task_list[0])
|
||||
# self._running_task.run()
|
||||
self._next_task.append(self._task_list[0])
|
||||
|
||||
@property
|
||||
def task_list(self):
|
||||
return self._task_list
|
||||
|
||||
@property
|
||||
def export_task_list(self):
|
||||
return [d.as_json() for d in self._task_list]
|
||||
|
||||
@property
|
||||
def prev_task(self):
|
||||
return self._prev_task
|
||||
|
||||
@property
|
||||
def running_task(self):
|
||||
return self._running_task
|
||||
|
||||
@property
|
||||
def next_task(self):
|
||||
return self._next_task
|
||||
|
||||
@property
|
||||
def check_list(self):
|
||||
return [self._running_task, *self._next_task]
|
||||
|
||||
@property
|
||||
def check_list(self):
|
||||
return [self._running_task, *self._next_task]
|
||||
|
||||
def load_task_list(self, task_list):
|
||||
for task in task_list:
|
||||
task = Task(task)
|
||||
self._task_list.append(task)
|
||||
|
||||
self.set_current_task(self._task_list[0])
|
||||
self._current_task.run()
|
||||
|
||||
def remove(self, index):
|
||||
pass
|
||||
def set_running_task(self, task):
|
||||
try:
|
||||
# if there is task running & same task active ,then reject
|
||||
if self._running_task != None and self._running_task.uuid == task.uuid:
|
||||
return False
|
||||
|
||||
# save running task
|
||||
self._prev_task = self._running_task
|
||||
# clear next task list
|
||||
self._next_task.clear()
|
||||
self._running_task = task
|
||||
self._running_task.run()
|
||||
|
||||
if self._prev_task != None:
|
||||
# if previous task is still running, then need to close
|
||||
if self._prev_task.status == 1:
|
||||
self._prev_task.stop()
|
||||
print('prev', 'run', self._prev_task.name, self._running_task.name)
|
||||
|
||||
for task_uuid in self._running_task.next:
|
||||
_task = next((task for task in self._task_list if task.uuid == task_uuid), None)
|
||||
if _task != None:
|
||||
self._next_task.append(_task)
|
||||
except RuntimeError as e:
|
||||
print(e)
|
||||
|
||||
def get_task(self, task_id):
|
||||
return self._task_list[task_id]
|
||||
|
||||
def get_check_task_list(self):
|
||||
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)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+103
-69
@@ -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', '_id_db_save')
|
||||
'_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': {
|
||||
@@ -1069,12 +1090,15 @@ class RecordingFileWriter:
|
||||
|
||||
# splitting
|
||||
self.splitting_threshold_time = 30 * 60 * 1000 # one minute
|
||||
self.splitting_threshold_size = 4 * 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:
|
||||
@@ -1107,14 +1131,17 @@ class RecordingFileWriter:
|
||||
self._splitting_size = 0
|
||||
return None
|
||||
|
||||
def close(self):
|
||||
# if self._recording_file is not None:
|
||||
# self._recording_file.close()
|
||||
# self._recording_file = None
|
||||
print('close1')
|
||||
def close(self, mqtt_thread):
|
||||
self._close = True
|
||||
if len(self._recording_file_dict) > 0:
|
||||
for ch in self._data_db.keys():
|
||||
if len(self._data_rl[ch]) > 0:
|
||||
self._data_rl[ch].append(str(int(self._time_now)))
|
||||
mes = ' '.join(self._data_rl[ch])
|
||||
mqtt_thread[ch].on_message(mes)
|
||||
self._data_rl[ch].clear()
|
||||
self._send_data[ch] = False
|
||||
|
||||
if self._recording_file_dict[ch]._status:
|
||||
_data = ' '.join(self._data_db[ch])
|
||||
self._raw_save['data'][ch] = _data
|
||||
@@ -1290,7 +1317,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
|
||||
@@ -1349,42 +1377,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
|
||||
if self._time_now - self._time[ch] > 2000000:
|
||||
|
||||
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])
|
||||
@@ -1395,26 +1435,22 @@ class RecordingFileWriter:
|
||||
|
||||
if data_save is True:
|
||||
if self._database is not None:
|
||||
# print('raw_save', self._raw_save['id'])
|
||||
# print('id_save', self._id_db_save)
|
||||
self._database.put_queue(['data_raw_recording', self._raw_save['id'], self._channel_list, self._raw_save['data'], self._id_db_save])
|
||||
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
|
||||
@@ -1433,16 +1469,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():
|
||||
@@ -1460,14 +1496,12 @@ class RecordingFileWriter:
|
||||
|
||||
if self._database is not None:
|
||||
self._database.put_queue(['data_mini_create', mini_data_dict, self._channel_list, scale, self._device_id])
|
||||
# self._database.put_queue(['data_mini_create', self._meta, self._recording_mini_dict[str(scale)], mini_data_dict, self._channel_list, scale])
|
||||
|
||||
self._meta._last_time = self._time_now
|
||||
self._meta.update_subfile(database = self._database)
|
||||
# self._meta.update_subfile(database = self._database)
|
||||
return None
|
||||
|
||||
def update_meta_id(self, _id):
|
||||
# print('update meta')
|
||||
self._meta._id_db = _id
|
||||
return None
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user