Compare commits
260 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c79f2a0e92 | |||
| c92b25e217 | |||
| 2f4f257974 | |||
| 7adcdf064f | |||
| 94eb567d9b | |||
| 536bc23896 | |||
| 7deb709946 | |||
| 25267411d8 | |||
| 200feead76 | |||
| f445550b4e | |||
| dfbbfe4e07 | |||
| 57e5c1a9e2 | |||
| ba192ccce8 | |||
| aae1ab7a33 | |||
| 59148cff6d | |||
| c9b10fc6aa | |||
| f82c3ab033 | |||
| 3884fad006 | |||
| 75ca525f36 | |||
| 9bb947f8e0 | |||
| fc4f931f9d | |||
| 57ba7ed94f | |||
| cf8433c7ee | |||
| 4d1eee6893 | |||
| 7a77c4d413 | |||
| 6f8d68f476 | |||
| 8ae45d3b50 | |||
| 5e4980a1d5 | |||
| 7716908a3b | |||
| 813ff7bc7d | |||
| c2224ed624 | |||
| 72943c3b6f | |||
| 4d47d07996 | |||
| 2fdcef998f | |||
| 2b6381fa46 | |||
| c29d9729ba | |||
| 001905ec96 | |||
| 5033381e64 | |||
| aa88201a93 | |||
| c02c59345b | |||
| 0386cf1847 | |||
| 62d8610191 | |||
| 991f5d06ea | |||
| 55711285e6 | |||
| 3ec5fee43b | |||
| 614a9c0b0f | |||
| 22eb8a09f4 | |||
| dbd7431124 | |||
| 15c15275a7 | |||
| 836d75b77e | |||
| 417bdd91a4 | |||
| 62ee763e2c | |||
| 44e9e4cb67 | |||
| 38537563fd | |||
| 375372996d | |||
| d79491db8b | |||
| 5a35da98ac | |||
| 9c054bd733 | |||
| 64412f9376 | |||
| 97034d6b32 | |||
| f065bad826 | |||
| 9c1dafd003 | |||
| 03443ada99 | |||
| 17dc5470e7 | |||
| 695f37c2dd | |||
| 690f859e86 | |||
| 0ed4d0594a | |||
| 959d86c0fe | |||
| 24c07a7fa5 | |||
| e43857a5bc | |||
| c084f29f06 | |||
| 130d260add | |||
| 575d5d8af1 | |||
| fbf6297047 | |||
| c540013d19 | |||
| 7f0b00a323 | |||
| 4828c85668 | |||
| 4ce9fe5b8d | |||
| d74f09254e | |||
| 79ecff69cc | |||
| df45126ead | |||
| 9fade3469a | |||
| a77331176c | |||
| 8f98337267 | |||
| 205d39cb11 | |||
| a5ea3243fa | |||
| 2edf28c7ba | |||
| 5531dcc0f0 | |||
| b20d46daa8 | |||
| 789d9b3a81 | |||
| 0d0427ed14 | |||
| d434509c5b | |||
| 787d76d48c | |||
| 50f2432088 | |||
| 1cff19ac58 | |||
| baef447c0e | |||
| ee9c13d4c5 | |||
| 9076f2f10b | |||
| 9b2e2964b0 | |||
| 2622109c89 | |||
| a3fe6b87af | |||
| 64419ca1c5 | |||
| 7d77c44741 | |||
| 29b4dd5cc7 | |||
| f151ae6fce | |||
| e535e3d2b1 | |||
| 06c36aa737 | |||
| 402022c451 | |||
| c0bb567bf7 | |||
| 4daff72d39 | |||
| f99719832a | |||
| 58e09bfcda | |||
| 55780514b9 | |||
| 936514871f | |||
| f25d9221c6 | |||
| 2ee9fa6b19 | |||
| fcc39dbfed | |||
| e2f7bba961 | |||
| 1174d54bc0 | |||
| bff75dc49e | |||
| 35912f614e | |||
| cfc4e39c8a | |||
| 8c4916d1e8 | |||
| e3c252f204 | |||
| c2164da48b | |||
| ab2d746afb | |||
| 8a870a860a | |||
| f4c5cf0135 | |||
| 1f01fd3b9b | |||
| d1fe388c27 | |||
| 91d5e73c5e | |||
| d1b6c2892f | |||
| 4243a13536 | |||
| 97188abff8 | |||
| 9d8178d11a | |||
| bbde653a8e | |||
| 6c0cef7925 | |||
| 3bbf0c912a | |||
| 4333958ebe | |||
| 3239a691e3 | |||
| 30183788d8 | |||
| 13df921b1c | |||
| d182a04ed3 | |||
| 35a09ff9a0 | |||
| e134b9780c | |||
| df39f241b3 | |||
| 0b72ac0c9d | |||
| 0afbe66229 | |||
| 9846cfd708 | |||
| b4ad2a7fba | |||
| 675fdc2226 | |||
| a847b1222d | |||
| bd0c36923a | |||
| 612785f51a | |||
| 7dbf09e9a5 | |||
| ee64d43de1 | |||
| 60b91f0c1e | |||
| 8ac01bdf54 | |||
| 0f90b16b6e | |||
| cd98a14e84 | |||
| 2e97ad23eb | |||
| e0dd5a6972 | |||
| 76e0a150d1 | |||
| ecd4b9325d | |||
| 978b1254f0 | |||
| 26e02f2d40 | |||
| ead98fe8da | |||
| 257958768f | |||
| 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 | |||
| e4bef30be2 | |||
| 96ec0a983f | |||
| affacfddeb | |||
| de8a6e58e4 | |||
| 390da7b004 | |||
| f8e41e9247 | |||
| 81ef9740c5 | |||
| 1d96f49f63 |
@@ -1,7 +1,10 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
*.cpython-37.opt-2.pyc
|
*.cpython-37.opt-2.pyc
|
||||||
|
*.cpython-39-arm-linux-gnueabihf.so
|
||||||
|
*.
|
||||||
*.pyc
|
*.pyc
|
||||||
*/__pycache__
|
*/__pycache__
|
||||||
/.vscode
|
/.vscode
|
||||||
/media
|
/media
|
||||||
python/biopro/sever/_identify.py
|
python/biopro/sever/_identify.py
|
||||||
|
*.log
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ New goal on pi4 without kotlin and django, and with only one dataserver.
|
|||||||
# Installation
|
# Installation
|
||||||
### Get Raspbrain into SD card
|
### Get Raspbrain into SD card
|
||||||
|
|
||||||
###### Download Raspbian Buster Lite
|
###### Download Raspbian Bullseye Lite
|
||||||
|
|
||||||
>https://www.raspberrypi.org/downloads/raspberry-pi-os/
|
>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
|
lsblk
|
||||||
|
|
||||||
# copy data to sd card
|
# 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
|
# enable ssh on first boot
|
||||||
add ssh.txt in boot folder
|
add ssh.txt in boot folder
|
||||||
@@ -77,19 +77,26 @@ add ssh.txt in boot folder
|
|||||||
|
|
||||||
|
|
||||||
###### Install dependencies
|
###### 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
|
||||||
|
sudo apt-get install libatlas-base-dev
|
||||||
|
sudo apt-get install python3-numpy
|
||||||
|
|
||||||
|
###### wiringpi conflict
|
||||||
|
need to install wiringpi: https://github.com/WiringPi/WiringPi
|
||||||
|
install instructions: https://github.com/WiringPi/WiringPi/blob/master/INSTALL
|
||||||
|
|
||||||
### Setup project
|
### Setup project
|
||||||
###### Clone project
|
###### Clone data server project
|
||||||
```
|
```
|
||||||
cd ~
|
cd ~
|
||||||
git clone https://gitlab.com/bioproscientific/bioprorelife.git
|
git clone https://gitlab.com/wisetop/controller/wisetopdataserver.git
|
||||||
```
|
```
|
||||||
|
|
||||||
###### Install python dependencies
|
###### Install python dependencies
|
||||||
```
|
```
|
||||||
cd ~/bioprorelife
|
cd ~/wisetopdataserver
|
||||||
pip3 install -r requirements.txt
|
pip3 install -r requirements.txt
|
||||||
|
pip3 install SQLAlchemy
|
||||||
```
|
```
|
||||||
##### Packages version
|
##### Packages version
|
||||||
```
|
```
|
||||||
@@ -112,14 +119,14 @@ psycopg2 2.8.5
|
|||||||
|
|
||||||
###### Build C extension
|
###### Build C extension
|
||||||
```
|
```
|
||||||
cd ~/bioprorelife/python/biopro/ext/
|
cd ~/wisetopdataserver/python/biopro/ext/
|
||||||
rm -rf *.so build
|
rm -rf *.so build
|
||||||
python3 setup.py build_ext --inplace
|
python3 setup.py build_ext --inplace
|
||||||
```
|
```
|
||||||
|
|
||||||
###### Check setup-uart file
|
###### Check setup-uart file
|
||||||
```
|
```
|
||||||
cd ~/bioprorelife
|
cd ~/wisetopdataserver/
|
||||||
sudo vim ./run-setup-uart.sh
|
sudo vim ./run-setup-uart.sh
|
||||||
```
|
```
|
||||||
##### Modify the code as following
|
##### Modify the code as following
|
||||||
@@ -149,44 +156,72 @@ sudo raspi-config
|
|||||||
reboot
|
reboot
|
||||||
```
|
```
|
||||||
|
|
||||||
|
###### Set pi password
|
||||||
|
```
|
||||||
|
cd ~
|
||||||
|
passwd
|
||||||
|
Current password:raspberry
|
||||||
|
New password:5k6zj454778225
|
||||||
|
Retype new password:5k6zj454778225
|
||||||
|
```
|
||||||
|
|
||||||
###### Auto run program when device start
|
###### Auto run program when device start
|
||||||
```
|
```
|
||||||
sudo vim /etc/rc.local
|
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
|
### MQTT broker install
|
||||||
|
|
||||||
1. Install mosquitto
|
###### 1.Install mosquitto
|
||||||
```
|
|
||||||
sudo apt-get install mosquitto mosquitto-clients
|
sudo apt-get install mosquitto mosquitto-clients
|
||||||
```
|
|
||||||
|
|
||||||
2. Enable Remote Access
|
|
||||||
```
|
###### 2.Enable Remote Access
|
||||||
sudo vim /etc/mosquitto/conf.d/default.conf
|
sudo vim /etc/mosquitto/conf.d/default.conf
|
||||||
```
|
|
||||||
add the code following as:
|
add the code following as:
|
||||||
```
|
```
|
||||||
listener 1883
|
listener 1883
|
||||||
protocol mqtt
|
protocol mqtt
|
||||||
listener 8083
|
listener 8083
|
||||||
protocol websockets
|
protocol websockets
|
||||||
|
allow_anonymous true
|
||||||
```
|
```
|
||||||
restart mqtt broker
|
###### 3.restart mqtt broker
|
||||||
```
|
|
||||||
sudo systemctl restart mosquitto
|
sudo systemctl restart mosquitto
|
||||||
```
|
|
||||||
|
|
||||||
3. Robust MQTT
|
###### 4.Robust MQTT
|
||||||
create mosquitto_restart.sh
|
create mosquitto_restart.sh
|
||||||
```
|
|
||||||
cd ~
|
cd ~
|
||||||
sudo vim mosquitto_restart.sh
|
sudo vim mosquitto_restart.sh
|
||||||
```
|
|
||||||
|
|
||||||
add the code following as:
|
add the code following as:
|
||||||
```
|
```
|
||||||
if [ "`ps -aux | grep /usr/sbin/mosquitto | wc -l`" == "1" ]
|
if [ "`ps -aux | grep /usr/sbin/mosquitto | wc -l`" == "1" ]
|
||||||
@@ -200,25 +235,155 @@ fi
|
|||||||
echo "$SERVICE is currently running" >> /home/ubuntu/cron.log
|
echo "$SERVICE is currently running" >> /home/ubuntu/cron.log
|
||||||
exit 0
|
exit 0
|
||||||
```
|
```
|
||||||
add mosquitto_restart.sh to root routing
|
###### 5.add mosquitto_restart.sh to root routing
|
||||||
```
|
|
||||||
sudo chmod +x mosquitto_restart.sh
|
sudo chmod +x mosquitto_restart.sh
|
||||||
sudo -i
|
sudo -i
|
||||||
crontab -e
|
crontab -e
|
||||||
```
|
|
||||||
add the code following as:
|
add the code following as:
|
||||||
```
|
```
|
||||||
*/5 * * * * /home/pi/mosquitto_restart.sh
|
*/5 * * * * /home/pi/mosquitto_restart.sh
|
||||||
```
|
```
|
||||||
3. Auto run MQTT broker when when pi-start
|
###### 6.Auto run MQTT broker when when pi-start
|
||||||
```
|
|
||||||
sudo vim /etc/rc.local
|
sudo vim /etc/rc.local
|
||||||
```
|
|
||||||
add the code following as:
|
add the code following as:
|
||||||
```
|
```
|
||||||
sudo nohup systemctl restart mosquitto
|
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
|
||||||
|
|
||||||
|
### Install Apache2
|
||||||
|
sudo apt install apache2
|
||||||
|
|
||||||
|
### Deploy web site
|
||||||
|
sudo vim /etc/apache2/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:
|
##### raspberry website document:
|
||||||
> https://www.raspberrypi.org/documentation/configuration/wireless/access-point-routed.md
|
> https://www.raspberrypi.org/documentation/configuration/wireless/access-point-routed.md
|
||||||
|
|
||||||
|
# ChangeLog
|
||||||
|
[2022.12.28]
|
||||||
|
change meta_project_info to project_metas
|
||||||
|
change project_report to project_reports
|
||||||
|
alter table project_meta column cycle type string to jsonb
|
||||||
|
|
||||||
|
[2022.11.16]
|
||||||
|
add python package SQLAlchemy
|
||||||
|
add new column project(int4) in postgresSQL table recording_meta_datas
|
||||||
|
add new postgresSQL table project_report
|
||||||
|
add new postgresSQL table meta_project_info
|
||||||
|
|
||||||
|
[2022.10.18]
|
||||||
|
socektTimeout from 1s -> 5s
|
||||||
|
socketListen from 3 -> 20
|
||||||
|
|
||||||
|
[2022.09.30]
|
||||||
|
add new column cycle(jsonb) in postgresSQL table projects
|
||||||
|
|
||||||
|
[2022.9.28]
|
||||||
|
add python package numpy
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
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,22 @@ class ControlAPI(metaclass=Router):
|
|||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def run_project(self, project) -> bool:
|
def run_project(self, project) -> bool:
|
||||||
print('create_project', project)
|
raise NotImplementedError()
|
||||||
self._project_manager.create(project)
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
def get_running_project(self) -> bool:
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def stop_project(self, project) -> bool:
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def set_project(self, project, content) -> bool:
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def set_project_cycle(self, project, index, content) -> bool:
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def show_device_data(self, device) -> bool:
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
# noinspection PyAbstractClass
|
# noinspection PyAbstractClass
|
||||||
class ControlClient(SocketClient, ControlAPI, metaclass=SocketClientMacro(ControlAPI)):
|
class ControlClient(SocketClient, ControlAPI, metaclass=SocketClientMacro(ControlAPI)):
|
||||||
|
|||||||
+16
-3
@@ -87,7 +87,8 @@ class DataAPI(metaclass=abc.ABCMeta):
|
|||||||
def update_device_configuration(self,
|
def update_device_configuration(self,
|
||||||
device: Union[int, Device],
|
device: Union[int, Device],
|
||||||
meta_file: Union[str, Path, RecordingMetaFile],
|
meta_file: Union[str, Path, RecordingMetaFile],
|
||||||
data_format: Union[AnyStr, DataDecodeFormat]):
|
data_format: Union[AnyStr, DataDecodeFormat],
|
||||||
|
project_info: str):
|
||||||
"""set device configuration.
|
"""set device configuration.
|
||||||
|
|
||||||
:param device: device ID
|
:param device: device ID
|
||||||
@@ -130,6 +131,14 @@ class DataAPI(metaclass=abc.ABCMeta):
|
|||||||
def hardware_test(self) -> JSON_OBJECT:
|
def hardware_test(self) -> JSON_OBJECT:
|
||||||
""""""
|
""""""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def show_data(self, device: Union[int, Device]):
|
||||||
|
"""show device data
|
||||||
|
|
||||||
|
:param device: device ID
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyAbstractClass
|
# noinspection PyAbstractClass
|
||||||
@@ -146,7 +155,8 @@ class DataClient(SocketClient, DataAPI, metaclass=SocketClientMacro(DataAPI)):
|
|||||||
def update_device_configuration(self,
|
def update_device_configuration(self,
|
||||||
device: Union[int, Device],
|
device: Union[int, Device],
|
||||||
meta_file: Union[str, Path, RecordingMetaFile],
|
meta_file: Union[str, Path, RecordingMetaFile],
|
||||||
data_format: Union[AnyStr, DataDecodeFormat]):
|
data_format: Union[AnyStr, DataDecodeFormat],
|
||||||
|
project_info: str):
|
||||||
|
|
||||||
# meta file
|
# meta file
|
||||||
if isinstance(meta_file, str):
|
if isinstance(meta_file, str):
|
||||||
@@ -178,7 +188,7 @@ class DataClient(SocketClient, DataAPI, metaclass=SocketClientMacro(DataAPI)):
|
|||||||
raise TypeError('not a data decode format : ' + data_format.__class__.__name__)
|
raise TypeError('not a data decode format : ' + data_format.__class__.__name__)
|
||||||
|
|
||||||
# send
|
# send
|
||||||
self.send_command('update_device_configuration', device, meta_file, data_format)
|
self.send_command('update_device_configuration', device, meta_file, data_format, project_info)
|
||||||
|
|
||||||
def is_sync(self, device: Union[None, int, Device] = None) -> bool:
|
def is_sync(self, device: Union[None, int, Device] = None) -> bool:
|
||||||
if isinstance(device, Device):
|
if isinstance(device, Device):
|
||||||
@@ -191,6 +201,9 @@ class DataClient(SocketClient, DataAPI, metaclass=SocketClientMacro(DataAPI)):
|
|||||||
|
|
||||||
def stop_sync(self, *device: Union[int, Device]):
|
def stop_sync(self, *device: Union[int, Device]):
|
||||||
self.send_command('stop_sync', *self._to_device_id(*device))
|
self.send_command('stop_sync', *self._to_device_id(*device))
|
||||||
|
|
||||||
|
def show_data(self, device: int):
|
||||||
|
self.send_command('show_data', device)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _to_device_id(*device: Union[int, Device]) -> Tuple[int, ...]:
|
def _to_device_id(*device: Union[int, Device]) -> Tuple[int, ...]:
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
from sqlalchemy import create_engine
|
||||||
|
# from sqlalchemy.ext.declarative import declarative_base
|
||||||
|
from sqlalchemy.orm import sessionmaker, declarative_base
|
||||||
|
|
||||||
|
SQLALCHEMY_DATABASE_URL = "postgresql://biopro:BioProControlBox@127.0.0.1:5432/postgres"
|
||||||
|
|
||||||
|
engine = create_engine(SQLALCHEMY_DATABASE_URL)
|
||||||
|
Session = sessionmaker(bind=engine)
|
||||||
|
|
||||||
|
Base = declarative_base()
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
from sqlalchemy import Table, Column, String, MetaData, ForeignKey, JSON
|
||||||
|
from sqlalchemy.sql import select, func
|
||||||
|
from sqlalchemy.types import Integer, BigInteger, String, Boolean, TIMESTAMP, Numeric
|
||||||
|
from sqlalchemy.dialects.postgresql import JSONB
|
||||||
|
from biopro.db.base import Session
|
||||||
|
|
||||||
|
from .base import Base
|
||||||
|
|
||||||
|
class Collection(Base):
|
||||||
|
__tablename__ = "collections"
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
name = Column(String(255))
|
||||||
|
parent = Column(JSONB)
|
||||||
|
controller_id = Column(Integer)
|
||||||
|
type = Column(String(255))
|
||||||
|
description = Column(String(255))
|
||||||
|
deleted = Column(Boolean)
|
||||||
|
created_at = Column(TIMESTAMP(timezone=True), server_default=func.now())
|
||||||
|
updated_at = Column(TIMESTAMP(timezone=True), onupdate=func.now())
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create_collection(cls, collection_name, parent):
|
||||||
|
with Session() as session:
|
||||||
|
name = cls.check_name_duplicate(collection_name, parent, 0)
|
||||||
|
collection = Collection(
|
||||||
|
name = name,
|
||||||
|
parent = parent,
|
||||||
|
type= "folder",
|
||||||
|
)
|
||||||
|
session.add(collection)
|
||||||
|
session.commit()
|
||||||
|
print('a', collection.id)
|
||||||
|
return collection
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def check_name_duplicate(cls, collection_name, parent, n):
|
||||||
|
with Session() as session:
|
||||||
|
result = session.query(Collection).filter(Collection.name == cls.generate_name(collection_name, n), Collection.parent == parent).first()
|
||||||
|
if result is None:
|
||||||
|
return cls.generate_name(collection_name, n)
|
||||||
|
else:
|
||||||
|
new_num = n + 1
|
||||||
|
# new_name = f"{collection_name}({new_num})"
|
||||||
|
return cls.check_name_duplicate(collection_name, parent, new_num)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def generate_name(cls, collection_name, n):
|
||||||
|
if n==0:
|
||||||
|
return collection_name
|
||||||
|
else:
|
||||||
|
return f"{collection_name}({n})"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def find_collection(cls, collection_name, parent):
|
||||||
|
with Session() as session:
|
||||||
|
result = session.query(Collection).filter(Collection.name == collection_name, Collection.parent == parent).first()
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
from sqlalchemy import Table, Column, String, MetaData, ForeignKey, JSON
|
||||||
|
from sqlalchemy.sql import select, func
|
||||||
|
from sqlalchemy.types import Integer, BigInteger, String, Boolean, TIMESTAMP, Numeric, Float, BINARY, LargeBinary
|
||||||
|
from sqlalchemy.dialects.postgresql import JSONB
|
||||||
|
|
||||||
|
from .base import Base, Session
|
||||||
|
|
||||||
|
class Device(Base):
|
||||||
|
__tablename__ = "devices"
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
name = Column(String(255))
|
||||||
|
mac_address = Column(String(255))
|
||||||
|
serial_number = Column(String(255))
|
||||||
|
configuration = Column(JSONB)
|
||||||
|
library = Column(String(255))
|
||||||
|
library_version = Column(String(255))
|
||||||
|
device_version = Column(String(255))
|
||||||
|
type = Column(String(255))
|
||||||
|
battery = Column(Integer)
|
||||||
|
temperature = Column(Float)
|
||||||
|
auto_connect = Column(Boolean)
|
||||||
|
connect_priority = Column(Integer)
|
||||||
|
connect_time = Column(BigInteger)
|
||||||
|
parameter_set = Column(JSONB)
|
||||||
|
running = Column(Boolean)
|
||||||
|
calibration = Column(LargeBinary)
|
||||||
|
calibration_version = Column(Integer, default=-1)
|
||||||
|
user_auth = Column(JSONB)
|
||||||
|
deleted = Column(Boolean)
|
||||||
|
created_at = Column(TIMESTAMP(timezone=True), server_default=func.now())
|
||||||
|
updated_at = Column(TIMESTAMP(timezone=True), onupdate=func.now())
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def update_device(cls, device, options):
|
||||||
|
with Session() as session:
|
||||||
|
result = session.query(Device).filter(Device.mac_address == device['mac_address']).first()
|
||||||
|
for key, value in options.items():
|
||||||
|
setattr(result, key, value)
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_device(cls, device):
|
||||||
|
with Session() as session:
|
||||||
|
result = session.query(Device).filter(Device.mac_address == device['mac_address']).first()
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# def __repr__(self):
|
||||||
|
# return f"User(id={self.id!r}, name={self.name!r}, fullname={self.task!r})"
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
from sqlalchemy import Table, Column, String, MetaData, ForeignKey, JSON
|
||||||
|
from sqlalchemy.sql import select, func
|
||||||
|
from sqlalchemy.types import Integer, BigInteger, String, Boolean, TIMESTAMP, Numeric
|
||||||
|
from sqlalchemy.dialects.postgresql import JSONB
|
||||||
|
|
||||||
|
from .base import Base
|
||||||
|
|
||||||
|
class Project(Base):
|
||||||
|
__tablename__ = "project"
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
name = Column(String)
|
||||||
|
desc = Column(String)
|
||||||
|
task = Column(JSONB)
|
||||||
|
cycle = Column(JSONB)
|
||||||
|
device = Column(JSONB)
|
||||||
|
uuid = Column(String(36))
|
||||||
|
user_auth = Column(JSONB)
|
||||||
|
deleted = Column(Boolean, default = False)
|
||||||
|
created_at = Column(TIMESTAMP(timezone=True), server_default=func.now())
|
||||||
|
updated_at = Column(TIMESTAMP(timezone=True), onupdate=func.now())
|
||||||
|
|
||||||
|
# def __repr__(self):
|
||||||
|
# return f"User(id={self.id!r}, name={self.name!r}, fullname={self.task!r})"
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
from sqlalchemy import Table, Column, String, MetaData, ForeignKey, JSON
|
||||||
|
from sqlalchemy.sql import select, func
|
||||||
|
from sqlalchemy.types import Integer, BigInteger, String, Boolean, TIMESTAMP, Numeric
|
||||||
|
from sqlalchemy.dialects.postgresql import JSONB
|
||||||
|
|
||||||
|
from .base import Base, Session
|
||||||
|
|
||||||
|
class MetaProjectInfo(Base):
|
||||||
|
__tablename__ = "project_metas"
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
project = Column(String(36))
|
||||||
|
cycle = Column(JSONB)
|
||||||
|
task = Column(JSONB)
|
||||||
|
serial_number = Column(Integer)
|
||||||
|
deleted = Column(Boolean, default = False)
|
||||||
|
created_at = Column(TIMESTAMP(timezone=True), server_default=func.now())
|
||||||
|
updated_at = Column(TIMESTAMP(timezone=True), onupdate=func.now())
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create_project_meta(cls, project):
|
||||||
|
with Session() as session:
|
||||||
|
project_meta = MetaProjectInfo(project = project['project'], cycle= project['cycle'], task=project['task'], serial_number=int(project['serial_number']))
|
||||||
|
session.add(project_meta)
|
||||||
|
session.commit()
|
||||||
|
return project_meta.id
|
||||||
|
|
||||||
|
# def __repr__(self):
|
||||||
|
# return f"User(id={self.id!r}, name={self.name!r}, fullname={self.task!r})"
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
from sqlalchemy import Table, Column, String, MetaData, ForeignKey, JSON
|
||||||
|
from sqlalchemy.sql import select, func
|
||||||
|
from sqlalchemy.types import Integer, BigInteger, String, Boolean, TIMESTAMP, Numeric
|
||||||
|
from sqlalchemy.dialects.postgresql import JSONB
|
||||||
|
|
||||||
|
from .base import Base
|
||||||
|
|
||||||
|
class ProjectReport(Base):
|
||||||
|
__tablename__ = "project_reports"
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
name = Column(String)
|
||||||
|
desc = Column(String)
|
||||||
|
task = Column(JSONB)
|
||||||
|
cycle = Column(JSONB)
|
||||||
|
device = Column(JSONB)
|
||||||
|
uuid = Column(String(36))
|
||||||
|
user_auth = Column(JSONB)
|
||||||
|
deleted = Column(Boolean, default = False)
|
||||||
|
created_at = Column(TIMESTAMP(timezone=True), server_default=func.now())
|
||||||
|
updated_at = Column(TIMESTAMP(timezone=True), onupdate=func.now())
|
||||||
|
|
||||||
|
# def __repr__(self):
|
||||||
|
# return f"User(id={self.id!r}, name={self.name!r}, fullname={self.task!r})"
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -350,6 +350,7 @@ class CC2650Device(Device):
|
|||||||
self._recording_file_name: str = 'recording_data'
|
self._recording_file_name: str = 'recording_data'
|
||||||
self._coeff: bytes = b''
|
self._coeff: bytes = b''
|
||||||
self._device_version = ""
|
self._device_version = ""
|
||||||
|
self._cali_version = -1
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_id(self) -> int:
|
def device_id(self) -> int:
|
||||||
@@ -432,12 +433,12 @@ class CC2650Device(Device):
|
|||||||
if length == 1 and instruction[0] < 0:
|
if length == 1 and instruction[0] < 0:
|
||||||
return struct.pack('2B1b',
|
return struct.pack('2B1b',
|
||||||
(ins_type & 0xF0) | (self.device_id & 0x0F),
|
(ins_type & 0xF0) | (self.device_id & 0x0F),
|
||||||
(ins_oper & 0xF0) | (length & 0x0F),
|
(ins_oper & 0xFF),
|
||||||
*instruction)
|
*instruction)
|
||||||
|
|
||||||
return struct.pack('%dB' % (length + 2),
|
return struct.pack('%dB' % (length + 2),
|
||||||
(ins_type & 0xF0) | (self.device_id & 0x0F),
|
(ins_type & 0xF0) | (self.device_id & 0x0F),
|
||||||
(ins_oper & 0xF0) | (length & 0x0F),
|
(ins_oper & 0xFF),
|
||||||
*instruction)
|
*instruction)
|
||||||
|
|
||||||
def _decode_data(self, ins_oper: int, data: bytes) -> bytes:
|
def _decode_data(self, ins_oper: int, data: bytes) -> bytes:
|
||||||
@@ -477,22 +478,24 @@ class CC2650Device(Device):
|
|||||||
|
|
||||||
else:
|
else:
|
||||||
if data is not None and len(data) > 0:
|
if data is not None and len(data) > 0:
|
||||||
year = struct.unpack('<B', data[0:1])[0]
|
year = struct.unpack('<B', data[2:3])[0]
|
||||||
month = struct.unpack('<B', data[1:2])[0]
|
month = struct.unpack('<B', data[3:4])[0]
|
||||||
day = struct.unpack('<B', data[2:3])[0]
|
day = struct.unpack('<B', data[4:5])[0]
|
||||||
hour = struct.unpack('<B', data[3:4])[0]
|
hour = struct.unpack('<B', data[5:6])[0]
|
||||||
minute = struct.unpack('<B', data[4:5])[0]
|
minute = struct.unpack('<B', data[6:7])[0]
|
||||||
mac1 = struct.unpack('<B', data[5:6])[0]
|
# mac1 = struct.unpack('<B', data[7:8])[0]
|
||||||
mac2 = struct.unpack('<B', data[6:7])[0]
|
# mac2 = struct.unpack('<B', data[8:9])[0]
|
||||||
mac1 = "%02X" % mac1
|
# mac1 = "%02X" % mac1
|
||||||
mac2 = "%02X" % mac2
|
# mac2 = "%02X" % mac2
|
||||||
|
|
||||||
self._device_version = str(year) + '/' + str(month) + '/' + str(day) + " " + str(hour) + ":" + str(
|
self._device_version = str(year) + '/' + str(month) + '/' + str(day) + " " + str(hour) + ":" + str(
|
||||||
minute) + " | " + str(mac1) + ":" + str(mac2)
|
minute)
|
||||||
|
# + " | " + str(mac1) + ":" + str(mac2)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def battery(self) -> int:
|
def battery(self) -> int:
|
||||||
self.update_battery_info()
|
if self._start_flag == False:
|
||||||
|
self.update_battery_info()
|
||||||
return self._battery
|
return self._battery
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -536,8 +539,8 @@ class CC2650Device(Device):
|
|||||||
self._master.log_warn('device', self.device_id, 'update_battery_info no response')
|
self._master.log_warn('device', self.device_id, 'update_battery_info no response')
|
||||||
|
|
||||||
else:
|
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]
|
battery = struct.unpack('<H', data[2:4])[0]
|
||||||
if battery is not None:
|
if battery is not None:
|
||||||
self._battery = battery
|
self._battery = battery
|
||||||
|
|
||||||
@@ -549,6 +552,39 @@ class CC2650Device(Device):
|
|||||||
self.update_calibration_info(device_type)
|
self.update_calibration_info(device_type)
|
||||||
|
|
||||||
return self._coeff
|
return self._coeff
|
||||||
|
|
||||||
|
def _check_crc(self, data):
|
||||||
|
data_chk_sum = data[-1]
|
||||||
|
|
||||||
|
# print('data:', list(data), 'data_chk_sum:', data_chk_sum)
|
||||||
|
# print('data[0:-1]:', list(data[0:-1]), 'check_sum:', sum(data[0:-1]) & 0b11111111)
|
||||||
|
|
||||||
|
if data_chk_sum == sum(data[0:-1]) & 0b11111111:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def update_cali_version(self) -> bool:
|
||||||
|
for _ in range(5):
|
||||||
|
try:
|
||||||
|
code = self._encode_instruction(DeviceInstruction.TYP_CIS, DeviceInstruction.CIS_CALI, 0)
|
||||||
|
self._master.write_characteristic(self.device_id, CC2650MasterDevice.COMMAND_HANDLE, code)
|
||||||
|
except SendInstructionTimeoutError:
|
||||||
|
self._master.log_warn('device', self.device_id, 'update cali version error')
|
||||||
|
return False
|
||||||
|
except RuntimeError:
|
||||||
|
self._master.log_warn('device', self.device_id, 'update cali version error')
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
version = self._master.read_characteristic(self.device_id,CC2650MasterDevice.RETURN_HANDLE)
|
||||||
|
|
||||||
|
if self._check_crc(version):
|
||||||
|
self._cali_version = struct.unpack('<H', version[2:4])[0]
|
||||||
|
print('self._cali_version=', self._cali_version)
|
||||||
|
return True
|
||||||
|
|
||||||
|
self._master.log_warn('device', self.device_id, 'update cali version error')
|
||||||
|
return False
|
||||||
|
|
||||||
def update_calibration_info(self, device_type: str):
|
def update_calibration_info(self, device_type: str):
|
||||||
""" get device calibration info """
|
""" get device calibration info """
|
||||||
@@ -571,20 +607,6 @@ class CC2650Device(Device):
|
|||||||
elif device_type == 'TDC4VC':
|
elif device_type == 'TDC4VC':
|
||||||
i = 0
|
i = 0
|
||||||
request_times = 0
|
request_times = 0
|
||||||
# neulive 2.1 (only support ch1~ch8)
|
|
||||||
# try:
|
|
||||||
# # send
|
|
||||||
# code = self._encode_instruction(DeviceInstruction.TYP_CIS, DeviceInstruction.CIS_CALI, 0)
|
|
||||||
# self._master.write_characteristic(self.device_id, CC2650MasterDevice.COMMAND_HANDLE, code)
|
|
||||||
# # receive
|
|
||||||
# data = self._master.read_characteristic(self.device_id, CC2650MasterDevice.RETURN_HANDLE)
|
|
||||||
#
|
|
||||||
# coeff.append(self._decode_data(DeviceInstruction.CIS_CALI, data))
|
|
||||||
# except SendInstructionTimeoutError:
|
|
||||||
# self._master.log_warn('device', self.device_id, 'update_calibration_info no response')
|
|
||||||
# except RuntimeError:
|
|
||||||
# self._master.log_warn('device', self.device_id, 'update_calibration_info no response')
|
|
||||||
|
|
||||||
while i < 4:
|
while i < 4:
|
||||||
try:
|
try:
|
||||||
# print('i', i)
|
# print('i', i)
|
||||||
@@ -660,43 +682,34 @@ class CC2650Device(Device):
|
|||||||
break
|
break
|
||||||
|
|
||||||
elif device_type == 'EISZeroOne':
|
elif device_type == 'EISZeroOne':
|
||||||
i = 0
|
i = 1
|
||||||
request_times = 0
|
while i <= 24:
|
||||||
while i < 7:
|
for _ in range(5):
|
||||||
try:
|
try:
|
||||||
# send
|
# send
|
||||||
code = self._encode_instruction(DeviceInstruction.TYP_CIS, DeviceInstruction.CIS_CALI, i)
|
code = self._encode_instruction(DeviceInstruction.TYP_CIS, DeviceInstruction.CIS_CALI, i)
|
||||||
self._master.write_characteristic(self.device_id, CC2650MasterDevice.COMMAND_HANDLE, code)
|
self._master.write_characteristic(self.device_id, CC2650MasterDevice.COMMAND_HANDLE, code)
|
||||||
|
|
||||||
sleep(0.1)
|
except SerialTimeoutException:
|
||||||
|
self._master.log_warn('device', self.device_id, 'send update_calibration_info instruction fail')
|
||||||
# receive
|
continue
|
||||||
data = self._master.read_characteristic(self.device_id,
|
|
||||||
CC2650MasterDevice.RETURN_HANDLE)
|
|
||||||
coeff.append(self._decode_data(DeviceInstruction.CIS_CALI, data))
|
|
||||||
|
|
||||||
except SendInstructionTimeoutError as e:
|
|
||||||
print(e)
|
|
||||||
self._master.log_warn('device', self.device_id, 'update_calibration_info no response')
|
|
||||||
raise BaseException
|
|
||||||
except RuntimeError as e:
|
|
||||||
print(e)
|
|
||||||
self._master.log_warn('device', self.device_id, 'update_calibration_info no response - 2')
|
|
||||||
request_times += 1
|
|
||||||
if request_times > 3:
|
|
||||||
self._master.reset(self.device_id)
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
# print('data success')
|
|
||||||
if len(data) > 0:
|
|
||||||
i += 1
|
|
||||||
else:
|
else:
|
||||||
request_times += 1
|
try:
|
||||||
if request_times > 3:
|
# receive
|
||||||
self._master.reset(self.device_id)
|
data = self._master.read_characteristic(self.device_id,
|
||||||
break
|
CC2650MasterDevice.RETURN_HANDLE)
|
||||||
|
except RecvTimeout:
|
||||||
|
self._master.log_warn('device', self.device_id, 'update_calibration_info no response')
|
||||||
|
|
||||||
|
else:
|
||||||
|
if self._check_crc(data) and data is not None:
|
||||||
|
coeff.append(self._decode_data(DeviceInstruction.CIS_CALI, data))
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
self._master.log_warn('device', self.device_id, 'update_calibration_info crc wrong')
|
||||||
|
continue
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# default: neulive 2.1
|
# default: neulive 2.1
|
||||||
for i in range(1):
|
for i in range(1):
|
||||||
@@ -1950,119 +1963,6 @@ class CC2650SingleMasterCentralDevice(CC2650MasterDevice, Synchronized):
|
|||||||
"""initialize cc2650 (master)"""
|
"""initialize cc2650 (master)"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def scan_send_ins(self):
|
|
||||||
# send scan command
|
|
||||||
try:
|
|
||||||
print(':: scan_send_ins ::', self.CC2650_COMMAND_LEN, 3, 0, 0)
|
|
||||||
self._cc2650.send(self.CC2650_COMMAND_LEN, 3, 0, 0)
|
|
||||||
|
|
||||||
except SerialTimeoutException as e:
|
|
||||||
raise RecvTimeout('send scan fail') from e
|
|
||||||
|
|
||||||
else:
|
|
||||||
# wait scanning
|
|
||||||
# sleep(2)
|
|
||||||
clean_buf = self._cc2650.receive_timeout("20B", timeout=3)
|
|
||||||
print("clean_buf = ", clean_buf)
|
|
||||||
|
|
||||||
# def cc2650_uart_irq(self):
|
|
||||||
# uart_irq = self.get_uart_irq_pin()
|
|
||||||
# uart_irq.output(False)
|
|
||||||
# sleep(0.001)
|
|
||||||
# uart_irq.output(True)
|
|
||||||
|
|
||||||
@synchronized
|
|
||||||
def scan_callback(self, callback: Callable[[DeviceResponseInfo], None], timeout=5, all_device=False) -> bool:
|
|
||||||
self._found = found = []
|
|
||||||
self._found_with_id = []
|
|
||||||
hdr_BPHS = [66, 80, 72, 83]
|
|
||||||
scan_response: Union[Optional[tuple], Any] = None
|
|
||||||
|
|
||||||
# build scan instruction
|
|
||||||
scan_ins = bytearray()
|
|
||||||
scan_ins.append(3) #scan instruction
|
|
||||||
scan_ins.append(1) #length
|
|
||||||
scan_ins.append(0xF1)
|
|
||||||
|
|
||||||
# print('send_scan', bytes(scan_ins))
|
|
||||||
self._cc2650.send("bytes", bytes(scan_ins))
|
|
||||||
|
|
||||||
try:
|
|
||||||
scan_response = self._cc2650.recv_uart(timeout)
|
|
||||||
except RecvTimeout:
|
|
||||||
# self.reset_internal()
|
|
||||||
# self.reset_hardware()
|
|
||||||
# self._interface.flush()
|
|
||||||
return False
|
|
||||||
|
|
||||||
# instruction format:
|
|
||||||
# ins[0]: get_scan_response = 0x04
|
|
||||||
# ins[1]: number of scanned device=0; a certain device = device_id (could be 1~8)
|
|
||||||
# ins[2]: addr=MAC=1, localName=2, company_code=3, version_info=4, battery_info=5, all_info=6;
|
|
||||||
# attr_length=0, e.g. len(addr)=6, len(company_code)=4
|
|
||||||
local_mac = None
|
|
||||||
local_cc = None
|
|
||||||
local_ver = None
|
|
||||||
local_bat = None
|
|
||||||
local_name = None
|
|
||||||
|
|
||||||
local_addr_type = None
|
|
||||||
|
|
||||||
# get device attribute length
|
|
||||||
attr_length = [6, 4, 6, 5, 20]
|
|
||||||
index = 0
|
|
||||||
|
|
||||||
local_mac = get_device_mac_in_address_format(scan_response[index:index + 6])
|
|
||||||
index = index + 6
|
|
||||||
# print("local_mac = ", hex(local_mac[0]), hex(local_mac[1]),
|
|
||||||
# hex(local_mac[2]), hex(local_mac[3]),
|
|
||||||
# hex(local_mac[4]), hex(local_mac[5]))
|
|
||||||
|
|
||||||
local_cc = get_device_company_code(scan_response[index:index + 4])
|
|
||||||
index = index + 4
|
|
||||||
# print("local_cc = ", local_cc)
|
|
||||||
|
|
||||||
local_ver = scan_response[index:index + 6]
|
|
||||||
index = index + 6
|
|
||||||
# print("local_ver = ", local_ver)
|
|
||||||
|
|
||||||
local_bat = get_device_battery_info(scan_response[index:index + 5])
|
|
||||||
index = index + 5
|
|
||||||
# print("local_bat = ", local_bat)
|
|
||||||
|
|
||||||
local_name = get_device_name_in_string_format(list(scan_response[index:index + 20]))
|
|
||||||
index = index + 20
|
|
||||||
# print("local_name = ", local_name)
|
|
||||||
|
|
||||||
# addr type is don't care in BMD380
|
|
||||||
local_addr_type = int(scan_response[index:index + 1][0])
|
|
||||||
# local_addr_type = 0xFF
|
|
||||||
index = index + 1
|
|
||||||
# print("local_addr_type = ", local_addr_type)
|
|
||||||
|
|
||||||
response = is_headstage_device_central_version(local_mac,
|
|
||||||
local_addr_type,
|
|
||||||
local_name,
|
|
||||||
local_cc,
|
|
||||||
local_ver,
|
|
||||||
local_bat)
|
|
||||||
if response is not None:
|
|
||||||
self.log_info('found', address_str(response.mac_address), response.serial_number)
|
|
||||||
self._interface.flush_input()
|
|
||||||
|
|
||||||
# apppend into db
|
|
||||||
devicesList = DeviceAPI.getByMac(address_str(response.mac_address))
|
|
||||||
if devicesList is not None:
|
|
||||||
if len(devicesList) == 0:
|
|
||||||
DeviceAPI.create(response.device_name, local_ver, address_str(response.mac_address))
|
|
||||||
|
|
||||||
found.append(response)
|
|
||||||
# print('scan_done_found', found)
|
|
||||||
self._found_with_id.append((response, 0 + 1))
|
|
||||||
callback(response)
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def decode_uart_preamble(self, raw_uart: tuple, expect_ret_len: int = 0) -> Optional[list]:
|
def decode_uart_preamble(self, raw_uart: tuple, expect_ret_len: int = 0) -> Optional[list]:
|
||||||
# print("decode_uart_preamble: raw_uart = ", raw_uart)
|
# print("decode_uart_preamble: raw_uart = ", raw_uart)
|
||||||
if raw_uart is None:
|
if raw_uart is None:
|
||||||
@@ -2089,34 +1989,154 @@ class CC2650SingleMasterCentralDevice(CC2650MasterDevice, Synchronized):
|
|||||||
return self._found
|
return self._found
|
||||||
|
|
||||||
def check_mem_survive(self) -> Optional[CC2650Device]:
|
def check_mem_survive(self) -> Optional[CC2650Device]:
|
||||||
ack = []
|
chk_mem_response = None
|
||||||
ins = bytearray()
|
ins = bytearray()
|
||||||
ins.append(10)
|
|
||||||
ins.append(1) #length
|
ins.append(0x0A)
|
||||||
|
ins.append(0x01) #length
|
||||||
ins.append(0xF1)
|
ins.append(0xF1)
|
||||||
# print('ins', list(ins))
|
self._interface.flush_input()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
self.log_verbose('[CC2650]', 'check_mem_survive att_write','0x'+str.upper(ins.hex()))
|
||||||
self._cc2650.send("bytes", bytes(ins))
|
self._cc2650.send("bytes", bytes(ins))
|
||||||
|
|
||||||
except SerialTimeoutException as e:
|
except SerialTimeoutException:
|
||||||
raise RecvTimeout('device CC2650 check_mem_survive timeout') from e
|
self.log_verbose('[CC2650]', 'check_mem_survive send fail')
|
||||||
|
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
ack = self._cc2650.recv_uart(0.001)
|
chk_mem_response = self._cc2650.recv_uart(0.001)
|
||||||
|
|
||||||
except RecvTimeout:
|
except RecvTimeout:
|
||||||
self.log_info("no memory board")
|
self.log_verbose('[CC2650]', 'check_mem_survive response timeout, no memory board')
|
||||||
|
|
||||||
# else:
|
if chk_mem_response is None:
|
||||||
# print('ack=', ack)
|
return False
|
||||||
|
|
||||||
if ack == [3]:
|
pack_len = chk_mem_response[0]
|
||||||
|
mem_ack = chk_mem_response[1:pack_len+1]
|
||||||
|
|
||||||
|
if mem_ack == [3]:
|
||||||
|
chk_mem_response_hex = ''.join(format(i, '02X') for i in chk_mem_response)
|
||||||
|
self.log_verbose('[CC2650]', 'check_mem_survive success', '0x'+chk_mem_response_hex)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@synchronized
|
||||||
|
def scan_callback(self, callback: Callable[[DeviceResponseInfo], None], timeout=5, all_device=False) -> bool:
|
||||||
|
self._found = found = []
|
||||||
|
self._found_with_id = []
|
||||||
|
scan_response = None
|
||||||
|
ins = bytearray()
|
||||||
|
|
||||||
|
ins.append(0x03)
|
||||||
|
ins.append(0x01) #length
|
||||||
|
ins.append(0xF1)
|
||||||
|
self._interface.flush_input()
|
||||||
|
|
||||||
|
for _ in range(5):
|
||||||
|
try:
|
||||||
|
self.log_verbose('[CC2650]', 'scan_callback att_write','0x'+str.upper(ins.hex()))
|
||||||
|
self._cc2650.send("bytes", bytes(ins))
|
||||||
|
|
||||||
|
except SerialTimeoutException:
|
||||||
|
self.log_verbose('[CC2650]', 'scan_callback send fail, rescan')
|
||||||
|
continue
|
||||||
|
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
scan_response = self._cc2650.recv_uart(0.01)
|
||||||
|
|
||||||
|
except RecvTimeout:
|
||||||
|
self.log_verbose('[CC2650]', 'scan_callback response timeout, no device, rescan')
|
||||||
|
continue
|
||||||
|
|
||||||
|
else:
|
||||||
|
if scan_response is None:
|
||||||
|
self.log_verbose('[CC2650]', 'scan_callback response is None, rescan')
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
if scan_response is None:
|
||||||
|
self.log_verbose('[CC2650]', 'scan_callback response is None--2')
|
||||||
|
return False
|
||||||
|
|
||||||
|
scan_response_hex = ''.join(format(i, '02X') for i in scan_response)
|
||||||
|
self.log_verbose('[CC2650]', 'scan_callback success', '0x'+scan_response_hex)
|
||||||
|
|
||||||
|
if len(scan_response) <= 2:
|
||||||
|
print('******************************************************************')
|
||||||
|
print('******************************************************************')
|
||||||
|
print('******************************************************************')
|
||||||
|
print('******************************************************************')
|
||||||
|
print('****need to fix, len(scan) <= 2')
|
||||||
|
print()
|
||||||
|
return False
|
||||||
|
|
||||||
|
pack_len = scan_response[0]
|
||||||
|
device_info_pkg = scan_response[1:pack_len+1]
|
||||||
|
|
||||||
|
# instruction format:
|
||||||
|
# ins[0]: get_scan_response = 0x04
|
||||||
|
# ins[1]: number of scanned device=0; a certain device = device_id (could be 1~8)
|
||||||
|
# ins[2]: addr=MAC=1, localName=2, company_code=3, version_info=4, battery_info=5, all_info=6;
|
||||||
|
# attr_length=0, e.g. len(addr)=6, len(company_code)=4
|
||||||
|
local_mac = None
|
||||||
|
local_cc = None
|
||||||
|
local_ver = None
|
||||||
|
local_bat = None
|
||||||
|
local_name = None
|
||||||
|
local_addr_type = None
|
||||||
|
|
||||||
|
# get device attribute length
|
||||||
|
attr_length = [6, 4, 6, 5, 20]
|
||||||
|
index = 0
|
||||||
|
|
||||||
|
local_mac = get_device_mac_in_address_format(device_info_pkg[index:index + 6])
|
||||||
|
index = index + 6
|
||||||
|
|
||||||
|
local_cc = get_device_company_code(device_info_pkg[index:index + 4])
|
||||||
|
index = index + 4
|
||||||
|
|
||||||
|
local_ver = device_info_pkg[index:index + 6]
|
||||||
|
index = index + 6
|
||||||
|
|
||||||
|
local_bat = get_device_battery_info(device_info_pkg[index:index + 5])
|
||||||
|
index = index + 5
|
||||||
|
|
||||||
|
local_name = get_device_name_in_string_format(list(device_info_pkg[index:index + 20]))
|
||||||
|
index = index + 20
|
||||||
|
|
||||||
|
local_addr_type = int(device_info_pkg[index:index + 1][0])
|
||||||
|
|
||||||
|
index = index + 1
|
||||||
|
|
||||||
|
response = is_headstage_device_central_version(local_mac,
|
||||||
|
local_addr_type,
|
||||||
|
local_name,
|
||||||
|
local_cc,
|
||||||
|
local_ver,
|
||||||
|
local_bat)
|
||||||
|
if response is not None:
|
||||||
|
self.log_info('found', address_str(response.mac_address), response.serial_number)
|
||||||
|
self._interface.flush_input()
|
||||||
|
|
||||||
|
# apppend into db
|
||||||
|
devicesList = DeviceAPI.getByMac(address_str(response.mac_address))
|
||||||
|
if devicesList is not None:
|
||||||
|
if len(devicesList) == 0:
|
||||||
|
DeviceAPI.create(response.device_name, local_ver, address_str(response.mac_address))
|
||||||
|
|
||||||
|
found.append(response)
|
||||||
|
# print('scan_done_found', found)
|
||||||
|
self._found_with_id.append((response, 0 + 1))
|
||||||
|
callback(response)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
@synchronized
|
@synchronized
|
||||||
def connect(self, response: DeviceResponseInfo, direct_connect: bool = False) -> Optional[CC2650Device]:
|
def connect(self, response: DeviceResponseInfo, direct_connect: bool = False) -> Optional[CC2650Device]:
|
||||||
if self._handle is not None:
|
if self._handle is not None:
|
||||||
@@ -2126,225 +2146,199 @@ class CC2650SingleMasterCentralDevice(CC2650MasterDevice, Synchronized):
|
|||||||
addr_type = response.addr_type
|
addr_type = response.addr_type
|
||||||
address_s = cc2650.address_str(address)
|
address_s = cc2650.address_str(address)
|
||||||
|
|
||||||
self.log_info(DEVICE_CONNECTING, address_s)
|
|
||||||
|
|
||||||
connect_ins = bytearray()
|
|
||||||
connect_ins.append(5)
|
|
||||||
connect_ins.append(8) #length
|
|
||||||
connect_ins.append(addr_type)
|
|
||||||
connect_ins.append(address[0])
|
|
||||||
connect_ins.append(address[1])
|
|
||||||
connect_ins.append(address[2])
|
|
||||||
connect_ins.append(address[3])
|
|
||||||
connect_ins.append(address[4])
|
|
||||||
connect_ins.append(address[5])
|
|
||||||
connect_ins.append(0xF1)
|
|
||||||
|
|
||||||
connected = False
|
connected = False
|
||||||
|
connect_response = None
|
||||||
|
ins = bytearray()
|
||||||
|
|
||||||
# send connect command
|
ins.append(0x05)
|
||||||
if direct_connect is True:
|
ins.append(0x08) #length
|
||||||
|
ins.append(addr_type)
|
||||||
# send device mac and addrType
|
ins.append(address[0])
|
||||||
try:
|
ins.append(address[1])
|
||||||
self._cc2650.send("bytes", bytes(connect_ins))
|
ins.append(address[2])
|
||||||
|
ins.append(address[3])
|
||||||
except SerialTimeoutException as e:
|
ins.append(address[4])
|
||||||
raise RecvTimeout('device CC2650 connect fail') from e
|
ins.append(address[5])
|
||||||
return None
|
ins.append(0xF1)
|
||||||
|
|
||||||
# connection establish done?
|
|
||||||
for retry_recv_ack in range(10):
|
|
||||||
try:
|
|
||||||
con_done = self._cc2650.recv_uart(timeout = 0.5)
|
|
||||||
# print("con_done = ", con_done)
|
|
||||||
|
|
||||||
except RecvTimeout:
|
|
||||||
self.log_info("recv connection timeout, retry... ")
|
|
||||||
continue
|
|
||||||
|
|
||||||
# is the ack valid?
|
|
||||||
if con_done is None:
|
|
||||||
continue
|
|
||||||
|
|
||||||
elif con_done[0] is 46 and \
|
|
||||||
con_done[1] is 80 and \
|
|
||||||
con_done[2] is 48 and \
|
|
||||||
con_done[3] is 4:
|
|
||||||
connected = True
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
for dev in self._found:
|
|
||||||
if dev.mac_address == address:
|
|
||||||
|
|
||||||
# send device mac and addrType
|
|
||||||
try:
|
|
||||||
# print('send_connect',bytes(connect_ins))
|
|
||||||
self._cc2650.send("bytes", bytes(connect_ins))
|
|
||||||
|
|
||||||
except SerialTimeoutException as e:
|
|
||||||
raise RecvTimeout('device CC2650 connect fail') from e
|
|
||||||
|
|
||||||
else:
|
|
||||||
sleep(2)
|
|
||||||
|
|
||||||
# connection establish done?
|
|
||||||
for retry_recv_ack in range(5):
|
|
||||||
self._cc2650.send("bytes", bytes((0, 0, 0, 0)))
|
|
||||||
|
|
||||||
try:
|
|
||||||
con_done = self._cc2650.recv_uart(timeout = 0.1)
|
|
||||||
|
|
||||||
except RecvTimeout:
|
|
||||||
self.log_info("recv connection timeout, retry... ")
|
|
||||||
continue
|
|
||||||
|
|
||||||
# is the ack valid?
|
|
||||||
if con_done is None:
|
|
||||||
continue
|
|
||||||
|
|
||||||
elif con_done[0] is 46 and \
|
|
||||||
con_done[1] is 80 and \
|
|
||||||
con_done[2] is 48 and \
|
|
||||||
con_done[3] is 4:
|
|
||||||
connected = True
|
|
||||||
# print('con_done=', con_done)
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# if select device is invalid or connect failed
|
|
||||||
self._interface.flush_input()
|
self._interface.flush_input()
|
||||||
if connected is False:
|
|
||||||
if direct_connect is True:
|
|
||||||
self.reset_internal()
|
|
||||||
self.reset_hardware()
|
|
||||||
self._interface.flush()
|
|
||||||
return None
|
|
||||||
|
|
||||||
# CC2650Device(device_id, master, scan_response) is a slave device
|
for retry in range(5):
|
||||||
# device_id is don't care, because it will be overwrite later
|
try:
|
||||||
dont_care = 0
|
self.log_verbose('[CC2650]', 'connect att_write', '0x'+str.upper(ins.hex()))
|
||||||
self._device = ret = CC2650Device(device_id=dont_care, master=self, response_info=response)
|
self._cc2650.send("bytes", bytes(ins))
|
||||||
self.log_info(DEVICE_CONNECTED, address_s)
|
|
||||||
sleep(0.5)
|
|
||||||
print('ret',ret)
|
|
||||||
|
|
||||||
return ret
|
except RecvTimeout:
|
||||||
|
self.log_verbose('[CC2650]', 'connect send fail')
|
||||||
|
continue
|
||||||
|
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
connect_response = self._cc2650.recv_uart(2)
|
||||||
|
except RecvTimeout:
|
||||||
|
# self.log_verbose('[CC2650]', 'connect response timeout')
|
||||||
|
if retry < 5:
|
||||||
|
self.log_verbose('[CC2650]', 'connect retry')
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
if connect_response is None:
|
||||||
|
self.log_verbose('[CC2650]', 'connect response timeout')
|
||||||
|
return False
|
||||||
|
|
||||||
|
pack_len = connect_response[0]
|
||||||
|
connect_ack = connect_response[1:pack_len+1]
|
||||||
|
if pack_len == 1:
|
||||||
|
if connect_ack[0] == 3:
|
||||||
|
connected = True
|
||||||
|
connect_response_hex = ''.join(format(i, '02X') for i in connect_response)
|
||||||
|
self.log_verbose('[CC2650]', 'connect success', '0x'+connect_response_hex)
|
||||||
|
|
||||||
|
elif pack_len == 4:
|
||||||
|
if connect_ack[0] == 46 and connect_ack[1] == 80 and \
|
||||||
|
connect_ack[2] == 48 and connect_ack[3] == 4:
|
||||||
|
connected = True
|
||||||
|
connect_response_hex = ''.join(format(i, '02X') for i in connect_response)
|
||||||
|
self.log_verbose('[CC2650]', 'connect success', '0x'+connect_response_hex)
|
||||||
|
|
||||||
|
if connected == True:
|
||||||
|
# CC2650Device(device_id, master, scan_response) is a slave device
|
||||||
|
# device_id is don't care, because it will be overwrite later
|
||||||
|
dont_care = 0
|
||||||
|
self._device = ret = CC2650Device(device_id=dont_care, master=self, response_info=response)
|
||||||
|
self.log_verbose('[CC2650]', DEVICE_CONNECTED, address_s)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
connect_response_hex = ''.join(format(i, '02X') for i in connect_response)
|
||||||
|
self.log_verbose('[CC2650]', 'connect fail', '0x'+connect_response_hex)
|
||||||
|
return False
|
||||||
|
|
||||||
@synchronized
|
@synchronized
|
||||||
def disconnect(self, device: int, force=False) -> bool:
|
def disconnect(self, device: int, force=False) -> bool:
|
||||||
self.log_info(DEVICE_DISCONNECTING, device)
|
|
||||||
|
|
||||||
ins = bytearray()
|
ins = bytearray()
|
||||||
ins.append(8)
|
|
||||||
ins.append(1) #length
|
ins.append(0x08)
|
||||||
|
ins.append(0x01) #length
|
||||||
ins.append(0xF1)
|
ins.append(0xF1)
|
||||||
|
self._interface.flush_input()
|
||||||
|
|
||||||
|
for retry in range(5):
|
||||||
|
try:
|
||||||
|
self.log_verbose('[CC2650]', 'disconnect att_write','0x'+str.upper(ins.hex()))
|
||||||
|
self._cc2650.send("bytes", bytes(ins))
|
||||||
|
|
||||||
|
except SerialTimeoutException:
|
||||||
|
self.log_verbose('[CC2650]', 'disconnect send fail')
|
||||||
|
continue
|
||||||
|
|
||||||
|
else:
|
||||||
|
self.reset_internal()
|
||||||
|
self.reset_hardware()
|
||||||
|
self.log_verbose('[CC2650]', 'disconnect success')
|
||||||
|
return True
|
||||||
|
# try:
|
||||||
|
# disconnect_response = self._cc2650.recv_uart(0.01)
|
||||||
|
# print(disconnect_response)
|
||||||
|
|
||||||
|
# except RecvTimeout:
|
||||||
|
# self.log_verbose('[CC2650]', 'disconnect response timeout')
|
||||||
|
# if retry < 5:
|
||||||
|
# self.log_verbose('[CC2650]', 'connect retry')
|
||||||
|
# continue
|
||||||
|
# else:
|
||||||
|
# break
|
||||||
|
|
||||||
|
# if disconnect_response is None:
|
||||||
|
# return False
|
||||||
|
|
||||||
|
# pack_len = disconnect_response[0]
|
||||||
|
# disconnect_ack = disconnect_response[1:pack_len+1]
|
||||||
|
|
||||||
|
# if disconnect_ack == [3]:
|
||||||
|
# disconnect_response_hex = ''.join(format(i, '02X') for i in disconnect_response)
|
||||||
|
# self.log_verbose('[CC2650]', 'disconnect success', '0x'+disconnect_response_hex)
|
||||||
|
# self.reset_internal()
|
||||||
|
# self.reset_hardware()
|
||||||
|
# return True
|
||||||
|
|
||||||
|
self.log_verbose('[CC2650]', 'disconnect fail')
|
||||||
|
return False
|
||||||
|
|
||||||
|
@synchronized
|
||||||
|
def write_characteristic(self, device: int, handle: int, data: bytes) -> bool:
|
||||||
|
write_response = None
|
||||||
|
ins = bytearray()
|
||||||
|
|
||||||
|
ins.append(0x06)
|
||||||
|
ins.append(len(data)+2) #length = handle + C0C0XXXX(data len) + F1
|
||||||
|
ins.append(handle)
|
||||||
|
ins.extend(data)
|
||||||
|
ins.append(0xF1)
|
||||||
|
self._interface.flush_input()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# print('send_disconnect',bytes(ins))
|
self.log_verbose('[CC2650]', 'write_characteristic', device, str(hex(handle).upper()))
|
||||||
|
self.log_verbose('[CC2650]', 'write_characteristic att_write','0x'+str.upper(ins.hex()))
|
||||||
self._cc2650.send("bytes", bytes(ins))
|
self._cc2650.send("bytes", bytes(ins))
|
||||||
|
|
||||||
except RecvTimeout:
|
except SerialTimeoutException:
|
||||||
self.log_warn('disconnect time out')
|
self.log_verbose('[CC2650]', 'write_characteristic send fail')
|
||||||
return False
|
|
||||||
|
|
||||||
except RuntimeError as e:
|
|
||||||
self.log_warn('suppressed error', str(e))
|
|
||||||
return False
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
sleep(0.01)
|
try:
|
||||||
|
write_response = self._cc2650.recv_uart(0.5)
|
||||||
|
|
||||||
|
except RecvTimeout:
|
||||||
|
self.log_verbose('[CC2650]', 'write_characteristic response timeout')
|
||||||
|
|
||||||
|
if write_response is None:
|
||||||
|
self.log_verbose('[CC2650]', 'write_characteristic fail')
|
||||||
|
return False
|
||||||
|
|
||||||
|
pack_len = write_response[0]
|
||||||
|
write_ack = write_response[1:pack_len+1]
|
||||||
|
|
||||||
|
if write_ack == [3]:
|
||||||
|
write_response_hex = ''.join(format(i, '02X') for i in write_response)
|
||||||
|
self.log_verbose('[CC2650]', 'write_characteristic success', '0x'+write_response_hex)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
finally:
|
self.log_verbose('[CC2650]', 'write_characteristic fail')
|
||||||
self.log_info(DEVICE_DISCONNECTED, device)
|
return False
|
||||||
|
|
||||||
# reset single 2650 after disconnected
|
|
||||||
self.reset_internal()
|
|
||||||
self.reset_hardware()
|
|
||||||
self._interface.flush()
|
|
||||||
|
|
||||||
@synchronized
|
@synchronized
|
||||||
def read_characteristic(self, device: int, handle: int) -> Optional[bytes]:
|
def read_characteristic(self, device: int, handle: int) -> Optional[bytes]:
|
||||||
|
read_response = None
|
||||||
# print("read_characteristic, expect_data_length = ", expect_data_length)
|
|
||||||
|
|
||||||
ret = None
|
|
||||||
ins = bytearray()
|
ins = bytearray()
|
||||||
ins.append(7)
|
|
||||||
ins.append(2) #length
|
ins.append(0x07)
|
||||||
|
ins.append(0x02) #length
|
||||||
ins.append(handle)
|
ins.append(handle)
|
||||||
ins.append(0xF1)
|
ins.append(0xF1)
|
||||||
|
self._interface.flush_input()
|
||||||
for _ in range(2):
|
|
||||||
try:
|
|
||||||
# print('send_read',bytes(ins))
|
|
||||||
self._cc2650.send("bytes", bytes(ins))
|
|
||||||
except SerialTimeoutException:
|
|
||||||
raise RecvTimeout('device CC2650 send read_characteristic fail')
|
|
||||||
|
|
||||||
try:
|
|
||||||
ret = self._cc2650.recv_uart(timeout = 2)
|
|
||||||
except Exception as e2:
|
|
||||||
raise RecvTimeout()
|
|
||||||
else:
|
|
||||||
# print("======== read ret = ", ret)
|
|
||||||
self._interface.flush_input()
|
|
||||||
|
|
||||||
# try:
|
|
||||||
# ret = self._cc2650.recv_uart(timeout = 1)
|
|
||||||
# except Exception as e2:
|
|
||||||
# raise RecvTimeout()
|
|
||||||
# else:
|
|
||||||
# # print("read_characteristic ret = ", ret)
|
|
||||||
# pass
|
|
||||||
|
|
||||||
if ret is None:
|
|
||||||
return None
|
|
||||||
|
|
||||||
return bytes(ret)
|
|
||||||
|
|
||||||
@synchronized
|
|
||||||
def write_characteristic(self, device: int, handle: int, data: bytes):
|
|
||||||
|
|
||||||
# print("device", device)
|
|
||||||
# print("handle", handle)
|
|
||||||
# print("data", data.hex())
|
|
||||||
# self.log_info('reset')
|
|
||||||
self.log_verbose('write_characteristic', device, handle)
|
|
||||||
self.log_verbose('[CC2650]', 'att_write', str.upper(data.hex()))
|
|
||||||
ack = None
|
|
||||||
ret = None
|
|
||||||
|
|
||||||
data_array = bytearray()
|
|
||||||
data_array.append(6)
|
|
||||||
data_array.append(len(data)+2) #length
|
|
||||||
data_array.append(handle)
|
|
||||||
data_array.extend(data)
|
|
||||||
data_array.append(0xF1)
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self._cc2650.send("bytes", bytes(data_array))
|
self.log_verbose('[CC2650]', 'read_characteristic', device, str(hex(handle).upper()))
|
||||||
# print('send_write',bytes(data_array))
|
self.log_verbose('[CC2650]', 'read_characteristic att_write','0x'+str.upper(ins.hex()))
|
||||||
|
self._cc2650.send("bytes", bytes(ins))
|
||||||
|
|
||||||
except SerialTimeoutException as e:
|
except SerialTimeoutException:
|
||||||
raise RecvTimeout('device CC2650 send instruction fail') from e
|
self.log_verbose('[CC2650]', 'read_characteristic send fail')
|
||||||
|
|
||||||
# read error code
|
|
||||||
try:
|
|
||||||
ret = self._cc2650.recv_uart()
|
|
||||||
|
|
||||||
# print("_______ write ack = ", ret)
|
|
||||||
except Exception as e2:
|
|
||||||
pass
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
pass
|
try:
|
||||||
|
read_response = self._cc2650.recv_uart(1)
|
||||||
|
|
||||||
self._interface.flush_input()
|
except RecvTimeout:
|
||||||
self._interface.flush_output()
|
self.log_verbose('[CC2650]', 'read_characteristic response timeout')
|
||||||
|
|
||||||
|
if read_response is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
read_response_hex = ''.join(format(i, '02X') for i in read_response)
|
||||||
|
self.log_verbose('[CC2650]', 'read_characteristic success', '0x'+read_response_hex)
|
||||||
|
|
||||||
|
return bytes(read_response)
|
||||||
|
|
||||||
def set_notify(self, device: Union[int, Device], enable: bool):
|
def set_notify(self, device: Union[int, Device], enable: bool):
|
||||||
if isinstance(device, CompletedDevice):
|
if isinstance(device, CompletedDevice):
|
||||||
@@ -2445,7 +2439,6 @@ class CC2650MultiMasterCentralDevice(CC2650MasterDevice, Synchronized):
|
|||||||
self._cc2650_log_level = self.log_level
|
self._cc2650_log_level = self.log_level
|
||||||
|
|
||||||
def read_characteristic(self, device: int, handle: int) -> Optional[bytes]:
|
def read_characteristic(self, device: int, handle: int) -> Optional[bytes]:
|
||||||
self.log_verbose('read_characteristic', device, '0x%02X' % handle)
|
|
||||||
|
|
||||||
master = self._cc2650[device]
|
master = self._cc2650[device]
|
||||||
|
|
||||||
@@ -2503,11 +2496,6 @@ class CC2650MultiMasterCentralDevice(CC2650MasterDevice, Synchronized):
|
|||||||
|
|
||||||
self._interface.flush()
|
self._interface.flush()
|
||||||
self._selector.select(device_id)
|
self._selector.select(device_id)
|
||||||
# self._mem_selector.select(device_id)
|
|
||||||
# print("multiMaster selector = ", device_id)
|
|
||||||
# print("\n")
|
|
||||||
|
|
||||||
# device._notify_flag = enable
|
|
||||||
try:
|
try:
|
||||||
master.write_characteristic(device_id, self.NOTIFY_HANDLE, value)
|
master.write_characteristic(device_id, self.NOTIFY_HANDLE, value)
|
||||||
except SendInstructionTimeoutError:
|
except SendInstructionTimeoutError:
|
||||||
|
|||||||
@@ -253,6 +253,7 @@ class DeviceInternalCommandHandler:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
# why inherit MasterDevice ?
|
||||||
class DeviceManager(MasterDevice, Synchronized):
|
class DeviceManager(MasterDevice, Synchronized):
|
||||||
"""device manager. It manager the device libraries, found device, connected device
|
"""device manager. It manager the device libraries, found device, connected device
|
||||||
and the control of the master device.
|
and the control of the master device.
|
||||||
@@ -267,7 +268,6 @@ class DeviceManager(MasterDevice, Synchronized):
|
|||||||
options: DeviceManagerOptions,
|
options: DeviceManagerOptions,
|
||||||
handler: Optional[DeviceInternalCommandHandler] = None):
|
handler: Optional[DeviceInternalCommandHandler] = None):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
:param options: manager options.
|
:param options: manager options.
|
||||||
:param handler: device internal command handler
|
:param handler: device internal command handler
|
||||||
"""
|
"""
|
||||||
@@ -277,6 +277,7 @@ class DeviceManager(MasterDevice, Synchronized):
|
|||||||
if handler is None:
|
if handler is None:
|
||||||
handler = DeviceInternalCommandHandler()
|
handler = DeviceInternalCommandHandler()
|
||||||
|
|
||||||
|
# control server api
|
||||||
self._handler: DeviceInternalCommandHandler = handler
|
self._handler: DeviceInternalCommandHandler = handler
|
||||||
self._options: DeviceManagerOptions = options
|
self._options: DeviceManagerOptions = options
|
||||||
|
|
||||||
@@ -286,7 +287,9 @@ class DeviceManager(MasterDevice, Synchronized):
|
|||||||
# hardware
|
# hardware
|
||||||
self._interface = options.interface
|
self._interface = options.interface
|
||||||
self._master: Optional[MasterDevice] = None
|
self._master: Optional[MasterDevice] = None
|
||||||
|
# memory board
|
||||||
self._centralMaster: Optional[MasterDevice] = None
|
self._centralMaster: Optional[MasterDevice] = None
|
||||||
|
# connected device
|
||||||
self._device: List[CompletedDevice] = []
|
self._device: List[CompletedDevice] = []
|
||||||
|
|
||||||
# demo device
|
# demo device
|
||||||
@@ -336,6 +339,10 @@ class DeviceManager(MasterDevice, Synchronized):
|
|||||||
def library_path(self) -> List[Path]:
|
def library_path(self) -> List[Path]:
|
||||||
return self._repository.library_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
|
@logging_info
|
||||||
def reload_library(self):
|
def reload_library(self):
|
||||||
"""reload device library"""
|
"""reload device library"""
|
||||||
@@ -562,26 +569,28 @@ class DeviceManager(MasterDevice, Synchronized):
|
|||||||
|
|
||||||
@logging_verbose
|
@logging_verbose
|
||||||
def get_device(self, device: Union[int, DeviceInfo]) -> Optional[CompletedDevice]:
|
def get_device(self, device: Union[int, DeviceInfo]) -> Optional[CompletedDevice]:
|
||||||
print('get_device', device)
|
|
||||||
"""get connected device
|
"""get connected device
|
||||||
|
|
||||||
:param device: device ID or response info
|
:param device: device ID or response info
|
||||||
:return: CompletedDevice, None if not found.
|
:return: CompletedDevice, None if not found.
|
||||||
"""
|
"""
|
||||||
if isinstance(device, int):
|
try:
|
||||||
for slave in self._device:
|
if isinstance(device, int):
|
||||||
if slave.device_id == device:
|
for slave in self._device:
|
||||||
return slave
|
if slave.device_id == device:
|
||||||
|
return slave
|
||||||
|
|
||||||
elif isinstance(device, str):
|
elif isinstance(device, str):
|
||||||
for slave in self._device:
|
for slave in self._device:
|
||||||
if ':'.join('{:02x}'.format(b) for b in slave.mac_address) == device.lower():
|
if ':'.join('{:02x}'.format(b) for b in slave.mac_address) == device.lower():
|
||||||
return slave
|
return slave
|
||||||
|
|
||||||
elif isinstance(device, DeviceInfo):
|
elif isinstance(device, DeviceInfo):
|
||||||
for slave in self._device:
|
for slave in self._device:
|
||||||
if device.match(slave):
|
if device.match(slave):
|
||||||
return slave
|
return slave
|
||||||
|
except BaseException as e:
|
||||||
|
self.log_error('device not found', str(device))
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -823,6 +832,9 @@ class DeviceManager(MasterDevice, Synchronized):
|
|||||||
|
|
||||||
elif func == InternalInstruction.PREDEFINED_DISABLE_CACHE:
|
elif func == InternalInstruction.PREDEFINED_DISABLE_CACHE:
|
||||||
self._device_disable_cache(device, *para)
|
self._device_disable_cache(device, *para)
|
||||||
|
|
||||||
|
elif func == InternalInstruction.PREDEFINED_IDLE:
|
||||||
|
self._idle(device, *para)
|
||||||
|
|
||||||
elif isinstance(device, DebugDevice):
|
elif isinstance(device, DebugDevice):
|
||||||
if func == InternalInstruction.PREDEFINED_NOTIFY:
|
if func == InternalInstruction.PREDEFINED_NOTIFY:
|
||||||
@@ -842,6 +854,11 @@ class DeviceManager(MasterDevice, Synchronized):
|
|||||||
InternalInstruction.PREDEFINED_DATA_FORMAT,
|
InternalInstruction.PREDEFINED_DATA_FORMAT,
|
||||||
f)
|
f)
|
||||||
|
|
||||||
|
def _idle(self, device: Device, expr: AnyStr):
|
||||||
|
self._handler.device_internal_command(device.device_id,
|
||||||
|
InternalInstruction.PREDEFINED_IDLE,
|
||||||
|
None)
|
||||||
|
|
||||||
def _device_data_format_cali(self, device: Device, expr: str, cali: bytes = None):
|
def _device_data_format_cali(self, device: Device, expr: str, cali: bytes = None):
|
||||||
if cali is None:
|
if cali is None:
|
||||||
cali = device.calibration_info(expr)
|
cali = device.calibration_info(expr)
|
||||||
@@ -1024,15 +1041,9 @@ class DeviceManager(MasterDevice, Synchronized):
|
|||||||
raise RuntimeError(DEVICE_NOT_FOUND, device)
|
raise RuntimeError(DEVICE_NOT_FOUND, device)
|
||||||
|
|
||||||
if DeviceCommonInstruction(instruction) is not None:
|
if DeviceCommonInstruction(instruction) is not None:
|
||||||
# print('deviceCommonInstr')
|
|
||||||
# print(instruction)
|
|
||||||
device.call_instruction(instruction)
|
device.call_instruction(instruction)
|
||||||
|
|
||||||
elif instruction in device.library.instruction_table:
|
elif instruction in device.library.instruction_table:
|
||||||
# print('instruction')
|
|
||||||
# print(instruction)
|
|
||||||
device.call_instruction(instruction)
|
device.call_instruction(instruction)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise RuntimeError(INSTRUCTION_UNKNOWN, instruction)
|
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.
+409
-205
@@ -1,6 +1,7 @@
|
|||||||
import abc
|
import abc
|
||||||
import struct
|
import struct
|
||||||
import math
|
import math
|
||||||
|
import numpy
|
||||||
from typing import Optional, TypeVar, Generic, Tuple, Dict, List, AnyStr
|
from typing import Optional, TypeVar, Generic, Tuple, Dict, List, AnyStr
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
@@ -853,7 +854,8 @@ class I4V4Z4T4DataDecoder(RecDataDecoder):
|
|||||||
|
|
||||||
__slots__ = ('_message', '_cycle_number', '_start_return_data', '_time_stamp',
|
__slots__ = ('_message', '_cycle_number', '_start_return_data', '_time_stamp',
|
||||||
'_total_time_stamp', '_mode', '_cycle_start_time',
|
'_total_time_stamp', '_mode', '_cycle_start_time',
|
||||||
'_mode_stop')
|
'_mode_stop', '_show_data',
|
||||||
|
'_last_mem_wrong_information', '_last_mem_cnt', '_last_elite_notify_times')
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
@@ -868,6 +870,12 @@ class I4V4Z4T4DataDecoder(RecDataDecoder):
|
|||||||
self._mode = 0
|
self._mode = 0
|
||||||
self._cycle_start_time = []
|
self._cycle_start_time = []
|
||||||
|
|
||||||
|
self._show_data = False
|
||||||
|
|
||||||
|
self._last_mem_wrong_information = -1
|
||||||
|
self._last_mem_cnt = -1
|
||||||
|
self._last_elite_notify_times = -1
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self) -> str:
|
def name(self) -> str:
|
||||||
return self.NAME
|
return self.NAME
|
||||||
@@ -881,22 +889,71 @@ class I4V4Z4T4DataDecoder(RecDataDecoder):
|
|||||||
def decode(self, data: bytes) -> Optional[RecordingData]:
|
def decode(self, data: bytes) -> Optional[RecordingData]:
|
||||||
if len(data) < 18:
|
if len(data) < 18:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
#/* Elite Notify data:
|
||||||
|
# * +--------+----------+---------+---------+---------+-----------+-----------------+
|
||||||
|
# * | id(1B) | time(4B) | ch1(4B) | ch2(4B) | ch3(4B) | cycle(2B) | finish_flag(1B) |
|
||||||
|
# * | bat(4B) | notify#(1B) | ch4(4B) | ch5(4B) | ch6(4B) | __(3B) |
|
||||||
|
# * +---------+-------------+---------+---------+---------+--------+
|
||||||
|
# */
|
||||||
|
#/*
|
||||||
|
# * EliteADCControl(): use ADC plot, and send what data to controller
|
||||||
|
# * +---------------------------+-----------+-----------+-----------+-----------+-----------+
|
||||||
|
# * | MODE | ch1 | ch2 | ch3 | cycle | ch4 |
|
||||||
|
# * +---------------------------+-----------+-----------+-----------+-----------+-----------+
|
||||||
|
# * | CURVE_IV | Iin | Vout | Vin | | Vmon |
|
||||||
|
# * | CURVE_IV_CY | Iin | Vout | Vin | v | Vmon |
|
||||||
|
# * | CURVE_VO | Iin | Vout | Vin | | Vmon |
|
||||||
|
# * | CURVE_RT | Iin | Vout | R | | Vmon |
|
||||||
|
# * | CURVE_VT | Iin | Vin | | | |
|
||||||
|
# * | CURVE_IT | Iin | Vin | Vout | | Vmon |
|
||||||
|
# * | CURVE_CC | Iin | Vin | Vout | | Vmon |
|
||||||
|
# * | CURVE_CP | Iin | Vout-Vin | Vout | | Vmon |
|
||||||
|
# * | CURVE_CV | Iin | Vout-Vin | Vout | v | Vmon |
|
||||||
|
# * | CURVE_LSV | Iin | Vout-Vin | Vout | | Vmon |
|
||||||
|
# * | CURVE_CA | Iin | Vout-Vin | Vout | | Vmon |
|
||||||
|
# * | CURVE_OCP | Iin | Vmon-Vin | Vin | | Vmon |
|
||||||
|
# * | CURVE_UNI_PULSE | pul1_Iin | pul2_Iin | | | |
|
||||||
|
# * | CURVE_DPV | c1&c2_avg | Vout-Vin | Vout | | Vmon |
|
||||||
|
# * | CURVE_DPV_SMPRATE | Iin | Vout-Vin | Vout | | Vmon |
|
||||||
|
# * | CURVE_DPV_ADVANCE | c1&c2_avg | Vout-Vin | Vout | | Vmon |
|
||||||
|
# * | CURVE_DPV_ADVANCE_SMPRATE | Iin | Vout-Vin | Vout | | Vmon |
|
||||||
|
# * +---------------------------+-----------+-----------+-----------+-----------+-----------+
|
||||||
|
# *
|
||||||
|
# * ps. c1_avg = pul1_Iin
|
||||||
|
# * ps. c2_avg = pul2_Iin
|
||||||
|
# */
|
||||||
|
|
||||||
current = struct.unpack('>i', data[1:5])[0] # unit: 1/1000 nA
|
mem_cnt = data[1]
|
||||||
voltage = struct.unpack('>i', data[5:9])[0] # unit: mV
|
time_stamp: float = struct.unpack('<I', data[1+3:5+3])[0]
|
||||||
impedance = struct.unpack('>i', data[9:13])[0] # unit: kOm
|
ch1 = struct.unpack('<i', data[5+3:9+3])[0] # unit: nA
|
||||||
time_stamp: float = struct.unpack('<I', data[13:17])[0] # unit: ms
|
ch2 = struct.unpack('<i', data[9+3:13+3])[0] # unit: uV
|
||||||
cycle_number = struct.unpack('>H', data[17:19])[0]
|
ch3 = struct.unpack('<i', data[13+3:17+3])[0] # unit: mOm
|
||||||
finish_mode_falg = data[19]
|
|
||||||
|
|
||||||
mem_wrong_information = struct.unpack('>i', data[40:40+4])[0]
|
cycle_number = struct.unpack('<H', data[17+3:19+3])[0]
|
||||||
|
finish_mode_falg = data[19+3]
|
||||||
|
battery = struct.unpack('<i', data[20+3:24+3])[0]
|
||||||
|
elite_notify_times = data[24+3]
|
||||||
|
ch4 = struct.unpack('<i', data[25+3:29+3])[0]
|
||||||
|
ch5 = struct.unpack('<i', data[29+3:33+3])[0]
|
||||||
|
ch6 = struct.unpack('<i', data[33+3:37+3])[0]
|
||||||
|
# self._show_data = True
|
||||||
|
|
||||||
# print('decode', list(data[20:]))
|
mem_wrong_information = struct.unpack('<i', data[43:47])[0] # mem_wrong_information = green retry, green wrong, red retry, red wrong
|
||||||
mem_wrong = data[40]
|
|
||||||
mem_retry_cnt = data[41]
|
if mem_wrong_information != self._last_mem_wrong_information:
|
||||||
mem_green_wrong = data[42]
|
print(datetime.now(), 'device', str(self.device), 'mem_wrong_information[43:47]:', data[43:47], mem_wrong_information, self._last_mem_wrong_information, flush = True)
|
||||||
mem_green_retry_cnt = data[43]
|
if mem_cnt != self._last_mem_cnt+1:
|
||||||
ram_num = data[44]
|
if not (mem_cnt == 0 and self._last_mem_cnt == 255):
|
||||||
|
print(datetime.now(), 'device', str(self.device), 'mem_cnt:', mem_cnt, 'self._last_mem_cnt:', self._last_mem_cnt, flush = True)
|
||||||
|
if (elite_notify_times != self._last_elite_notify_times+1) and not (elite_notify_times == 0 and self._last_elite_notify_times == 0):
|
||||||
|
if not (elite_notify_times == 0 and self._last_elite_notify_times == 255):
|
||||||
|
print(datetime.now(), 'device', str(self.device), 'elite_notify_times:', elite_notify_times, 'self._elite_notify_times:', self._last_elite_notify_times, flush = True)
|
||||||
|
self._last_mem_wrong_information = mem_wrong_information
|
||||||
|
self._last_mem_cnt = mem_cnt
|
||||||
|
self._last_elite_notify_times = elite_notify_times
|
||||||
|
|
||||||
|
ram_num = data[47]
|
||||||
broken_flag = data[-1]
|
broken_flag = data[-1]
|
||||||
|
|
||||||
if (finish_mode_falg & 0b11110000 == 0b10100000):
|
if (finish_mode_falg & 0b11110000 == 0b10100000):
|
||||||
@@ -917,26 +974,31 @@ class I4V4Z4T4DataDecoder(RecDataDecoder):
|
|||||||
print("error timeStamp full data:", list(data), datetime.now(), '\n')
|
print("error timeStamp full data:", list(data), datetime.now(), '\n')
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
# print('|', time_stamp, '|', delta, '|', current, '|', voltage, '|', impedance,
|
if self._show_data:
|
||||||
# '|', cycle_number, '|', finishMode, '@', str(self.device))
|
print('|', time_stamp, '|', delta, '|', int(time_stamp * 1000 / 2),
|
||||||
# print('|', '{:10}'.format(time_stamp),
|
'|', ch1, '|', ch2, '|', ch3, '|', cycle_number,
|
||||||
# '|', '{:10}'.format(delta),
|
'|', ch4, '|', ch5, '|', ch6,
|
||||||
# '|', '{:10}'.format(current),
|
'|', finishMode, '@', str(self.device), flush = True)
|
||||||
# '|', '{:10}'.format(voltage),
|
|
||||||
# '|', '{:10}'.format(impedance),
|
|
||||||
# '|', '{:5}'.format(cycle_number),
|
|
||||||
# '|', '{:1}'.format(finishMode),
|
|
||||||
# '@', str(self.device), '|')
|
|
||||||
|
|
||||||
# print('|', '{:5}'.format(mem_wrong),
|
# print('|', '{:10}'.format(time_stamp),
|
||||||
# '|', '{:5}'.format(mem_retry_cnt),
|
# '|', '{:4}'.format(delta),
|
||||||
# '|', '{:5}'.format(mem_green_wrong),
|
# '|', '{:10}'.format(int(time_stamp * 1000 / 2)), #[usec]
|
||||||
# '|', '{:5}'.format(mem_green_retry_cnt),
|
# '|', '{:10}'.format(ch1), #[nA]
|
||||||
# '|', '{:5}'.format(mem_wrong_information),
|
# '|', '{:10}'.format(ch2), #[uV]
|
||||||
# '|', '{:5}'.format(ram_num),
|
# '|', '{:10}'.format(ch3),
|
||||||
# '|', '{:5}'.format(broken_flag),
|
# '|', '{:5}'.format(cycle_number),
|
||||||
# '@', str(self.device), '|')
|
# '|', '{:10}'.format(ch4), #Voutin[uV]
|
||||||
pass
|
# '|', '{:10}'.format(ch5),
|
||||||
|
# '|', '{:10}'.format(ch6),
|
||||||
|
# '|', '{:5}'.format(battery), #[mV]
|
||||||
|
# '|', '{:4}'.format(elite_notify_times),
|
||||||
|
# '|', '{:1}'.format(finishMode),
|
||||||
|
# '@', str(self.device), '|', flush = True)
|
||||||
|
|
||||||
|
# print('|', '{:5}'.format(mem_wrong_information),
|
||||||
|
# '|', '{:2}'.format(ram_num),
|
||||||
|
# '|', '{:2}'.format(broken_flag),
|
||||||
|
# '@', str(self.device), '|')
|
||||||
|
|
||||||
if finishMode == True:
|
if finishMode == True:
|
||||||
print("finishMode full data:", list(data), datetime.now())
|
print("finishMode full data:", list(data), datetime.now())
|
||||||
@@ -945,20 +1007,27 @@ class I4V4Z4T4DataDecoder(RecDataDecoder):
|
|||||||
self._mode_stop = 0
|
self._mode_stop = 0
|
||||||
|
|
||||||
ret = RecordingData(self.device, int(time_stamp * 1000 / 2), 0)
|
ret = RecordingData(self.device, int(time_stamp * 1000 / 2), 0)
|
||||||
ret.append_data(0, current)
|
ret.append_data(0, ch1)
|
||||||
ret.append_data(1, voltage)
|
ret.append_data(1, ch2)
|
||||||
ret.append_data(2, impedance)
|
ret.append_data(2, ch3)
|
||||||
ret.append_data(3, cycle_number)
|
ret.append_data(3, cycle_number)
|
||||||
|
ret.append_data(4, ch4)
|
||||||
|
ret.append_data(5, ch5)
|
||||||
|
ret.append_data(6, ch6)
|
||||||
|
# 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:
|
if cycle_number != self._cycle_number:
|
||||||
# notify cycle_number change
|
# notify cycle_number change
|
||||||
@@ -1332,9 +1401,9 @@ class EISZeroOneDataDecoder(RecDataDecoder):
|
|||||||
|
|
||||||
__slots__ = ('_message', '_cycle_number', '_start_return_data', '_time_stamp',
|
__slots__ = ('_message', '_cycle_number', '_start_return_data', '_time_stamp',
|
||||||
'_total_time_stamp', '_mode', '_cycle_start_time',
|
'_total_time_stamp', '_mode', '_cycle_start_time',
|
||||||
'_mode_stop', '_last_time_stamp', '_last_delta', '_cali_coeff',
|
'_mode_stop', '_last_time_stamp', '_last_delta',
|
||||||
'cali_coeff', '_ac_amp', '_mode', '_freq_start', '_freq_stop',
|
'_cali_package', 'cali_coeff', '_ac_amp', '_mode',
|
||||||
'_freq_direction', '_last_phase', '_first_phase_flag')
|
'_last_phase', '_first_phase_flag', '_show_data')
|
||||||
|
|
||||||
def __init__(self, cali_coeff: bytes = None):
|
def __init__(self, cali_coeff: bytes = None):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
@@ -1347,92 +1416,234 @@ class EISZeroOneDataDecoder(RecDataDecoder):
|
|||||||
self._mode_stop = 0
|
self._mode_stop = 0
|
||||||
|
|
||||||
self._cycle_start_time = []
|
self._cycle_start_time = []
|
||||||
self._ac_amp: int = 0
|
|
||||||
self._mode: int = 0
|
self._mode: int = 0
|
||||||
self._freq_start: int = 0
|
|
||||||
self._freq_stop: int = 0
|
|
||||||
self._freq_direction = 0
|
|
||||||
self._last_phase = 0
|
self._last_phase = 0
|
||||||
self._first_phase_flag = 1
|
self._first_phase_flag = 1
|
||||||
|
|
||||||
self._cali_coeff: Optional[bytes] = None
|
self._cali_package: Optional[bytes] = None
|
||||||
self.cali_coeff: Optional[List[Tuple[int, int]]] = None
|
self.cali_coeff: Optional[List[Tuple[int, int]]] = None
|
||||||
|
|
||||||
if cali_coeff is not None:
|
self._show_data = False
|
||||||
self._cali_coeff = cali_coeff
|
|
||||||
self.cali_coeff = self._decode_cali_coeff(cali_coeff)
|
if self._cali_package is None:
|
||||||
|
self._cali_package = cali_coeff
|
||||||
|
self.cali_coeff = self._decode_cali_coeff(self._cali_package)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _decode_cali_coeff(cali_coeff: bytes) -> Optional[List[Tuple[int, int]]]:
|
def _decode_cali_coeff(cali_coeff: bytes) -> Optional[List[Tuple[int, int]]]:
|
||||||
if cali_coeff != b'':
|
if cali_coeff != b'':
|
||||||
|
cis_data_len = 20
|
||||||
cali_table = []
|
cali_table = []
|
||||||
phase_para_a = []
|
|
||||||
phase_para_b = []
|
|
||||||
hsrtia_a = []
|
hsrtia_a = []
|
||||||
hsrtia_b = []
|
hsrtia_b = []
|
||||||
hsrtia_c = []
|
rolloff = []
|
||||||
hsrtia_d = []
|
phase_coeff = []
|
||||||
|
phase_offset = []
|
||||||
|
|
||||||
# print('cali_coeff', cali_coeff)
|
phase_coeff = numpy.zeros([8, 4], dtype = int)
|
||||||
cutoff_freq = struct.unpack('>I', cali_coeff[1:5])[0] * 100 #4
|
phase_offset = numpy.zeros([8, 4], dtype = int)
|
||||||
# temp = struct.unpack('>B', cali_coeff[5:6])[0] #1
|
|
||||||
# hsrtia_200r = struct.unpack('>B', cali_coeff[6:7])[0] #1
|
|
||||||
# hsrtia_5k = struct.unpack('>H', cali_coeff[7:9])[0] #2
|
|
||||||
# hsrtia_20k = struct.unpack('>H', cali_coeff[6:8])[0] #2
|
|
||||||
# hsrtia_160k = struct.unpack('>I', cali_coeff[8:12])[0] #4
|
|
||||||
|
|
||||||
index = 20
|
########################################
|
||||||
for i in range(index, index+16, 8):
|
# phase_coeff
|
||||||
phase_para_a.append(struct.unpack('>i', cali_coeff[i+1:i+5])[0])
|
# [[freq0, freq1, freq2, freq3] ----->gain0
|
||||||
phase_para_b.append(struct.unpack('>i', cali_coeff[i+5:i+9])[0])
|
# [freq0, freq1, freq2, freq3] ----->gain1
|
||||||
|
# [freq0, freq1, freq2, freq3] ----->gain2
|
||||||
|
# [freq0, freq1, freq2, freq3] ----->gain3
|
||||||
|
# ]
|
||||||
|
#######################################
|
||||||
|
|
||||||
index = 40
|
#hstia=0
|
||||||
for i in range(index, index+16, 8):
|
cis_cali_packet = 1
|
||||||
phase_para_a.append(struct.unpack('>i', cali_coeff[i+1:i+5])[0])
|
index = (cis_cali_packet - 1) * cis_data_len
|
||||||
phase_para_b.append(struct.unpack('>i', cali_coeff[i+5:i+9])[0])
|
hsrtia_a.append(struct.unpack('>i', cali_coeff[index+2:index+6])[0])
|
||||||
|
hsrtia_b.append(struct.unpack('>q', cali_coeff[index+6:index+14])[0])
|
||||||
|
rolloff.append(struct.unpack('>i', cali_coeff[index+14:index+18])[0])
|
||||||
|
|
||||||
#Lv[0] 160k
|
cis_cali_packet = 2
|
||||||
index = 60
|
index = (cis_cali_packet - 1) * cis_data_len
|
||||||
hsrtia_a.append(struct.unpack('>i', cali_coeff[index+1:index+5])[0]/1e8)
|
g = 0
|
||||||
hsrtia_b.append(struct.unpack('>i', cali_coeff[index+5:index+9])[0]/1e8)
|
phase_coeff[g][0] = struct.unpack('>i', cali_coeff[index+2:index+6])[0]
|
||||||
hsrtia_c.append(struct.unpack('>i', cali_coeff[index+9:index+13])[0]/1e4)
|
phase_offset[g][0] = struct.unpack('>i', cali_coeff[index+6:index+10])[0]
|
||||||
hsrtia_d.append(struct.unpack('>B', cali_coeff[index+13:index+14])[0])
|
phase_coeff[g][1] = struct.unpack('>i', cali_coeff[index+10:index+14])[0]
|
||||||
|
phase_offset[g][1] = struct.unpack('>i', cali_coeff[index+14:index+18])[0]
|
||||||
|
|
||||||
|
cis_cali_packet = 3
|
||||||
|
index = (cis_cali_packet - 1) * cis_data_len
|
||||||
|
g = 0
|
||||||
|
phase_coeff[g][2] = struct.unpack('>i', cali_coeff[index+2:index+6])[0]
|
||||||
|
phase_offset[g][2] = struct.unpack('>i', cali_coeff[index+6:index+10])[0]
|
||||||
|
phase_coeff[g][3] = struct.unpack('>i', cali_coeff[index+10:index+14])[0]
|
||||||
|
phase_offset[g][3] = struct.unpack('>i', cali_coeff[index+14:index+18])[0]
|
||||||
|
|
||||||
|
#hstia=1
|
||||||
|
cis_cali_packet = 4
|
||||||
|
index = (cis_cali_packet - 1) * cis_data_len
|
||||||
|
hsrtia_a.append(struct.unpack('>i', cali_coeff[index+2:index+6])[0])
|
||||||
|
hsrtia_b.append(struct.unpack('>q', cali_coeff[index+6:index+14])[0])
|
||||||
|
rolloff.append(struct.unpack('>i', cali_coeff[index+14:index+18])[0])
|
||||||
|
|
||||||
#Lv[1] 20k
|
cis_cali_packet = 5
|
||||||
index = 80
|
index = (cis_cali_packet - 1) * cis_data_len
|
||||||
hsrtia_a.append(struct.unpack('>i', cali_coeff[index+1:index+5])[0]/1e8)
|
g = 1
|
||||||
hsrtia_b.append(struct.unpack('>i', cali_coeff[index+5:index+9])[0]/1e8)
|
phase_coeff[g][0] = struct.unpack('>i', cali_coeff[index+2:index+6])[0]
|
||||||
hsrtia_c.append(struct.unpack('>i', cali_coeff[index+9:index+13])[0]/1e4)
|
phase_offset[g][0] = struct.unpack('>i', cali_coeff[index+6:index+10])[0]
|
||||||
hsrtia_d.append(struct.unpack('>B', cali_coeff[index+13:index+14])[0])
|
phase_coeff[g][1] = struct.unpack('>i', cali_coeff[index+10:index+14])[0]
|
||||||
|
phase_offset[g][1] = struct.unpack('>i', cali_coeff[index+14:index+18])[0]
|
||||||
|
|
||||||
|
cis_cali_packet = 6
|
||||||
|
index = (cis_cali_packet - 1) * cis_data_len
|
||||||
|
g = 1
|
||||||
|
phase_coeff[g][2] = struct.unpack('>i', cali_coeff[index+2:index+6])[0]
|
||||||
|
phase_offset[g][2] = struct.unpack('>i', cali_coeff[index+6:index+10])[0]
|
||||||
|
phase_coeff[g][3] = struct.unpack('>i', cali_coeff[index+10:index+14])[0]
|
||||||
|
phase_offset[g][3] = struct.unpack('>i', cali_coeff[index+14:index+18])[0]
|
||||||
|
|
||||||
#Lv[2] 5k
|
#hstia=2
|
||||||
index = 100
|
cis_cali_packet = 7
|
||||||
hsrtia_a.append(struct.unpack('>i', cali_coeff[index+1:index+5])[0]/1e8)
|
index = (cis_cali_packet - 1) * cis_data_len
|
||||||
hsrtia_b.append(struct.unpack('>i', cali_coeff[index+5:index+9])[0]/1e8)
|
hsrtia_a.append(struct.unpack('>i', cali_coeff[index+2:index+6])[0])
|
||||||
hsrtia_c.append(struct.unpack('>i', cali_coeff[index+9:index+13])[0]/1e4)
|
hsrtia_b.append(struct.unpack('>q', cali_coeff[index+6:index+14])[0])
|
||||||
hsrtia_d.append(struct.unpack('>B', cali_coeff[index+13:index+14])[0])
|
rolloff.append(struct.unpack('>i', cali_coeff[index+14:index+18])[0])
|
||||||
|
|
||||||
#Lv[3] 200R
|
cis_cali_packet = 8
|
||||||
index = 120
|
index = (cis_cali_packet - 1) * cis_data_len
|
||||||
hsrtia_a.append(struct.unpack('>i', cali_coeff[index+1:index+5])[0]/1e8)
|
g = 2
|
||||||
hsrtia_b.append(struct.unpack('>i', cali_coeff[index+5:index+9])[0]/1e8)
|
phase_coeff[g][0] = struct.unpack('>i', cali_coeff[index+2:index+6])[0]
|
||||||
hsrtia_c.append(struct.unpack('>i', cali_coeff[index+9:index+13])[0]/1e4)
|
phase_offset[g][0] = struct.unpack('>i', cali_coeff[index+6:index+10])[0]
|
||||||
hsrtia_d.append(struct.unpack('>B', cali_coeff[index+13:index+14])[0])
|
phase_coeff[g][1] = struct.unpack('>i', cali_coeff[index+10:index+14])[0]
|
||||||
|
phase_offset[g][1] = struct.unpack('>i', cali_coeff[index+14:index+18])[0]
|
||||||
|
|
||||||
|
cis_cali_packet = 9
|
||||||
|
index = (cis_cali_packet - 1) * cis_data_len
|
||||||
|
g = 2
|
||||||
|
phase_coeff[g][2] = struct.unpack('>i', cali_coeff[index+2:index+6])[0]
|
||||||
|
phase_offset[g][2] = struct.unpack('>i', cali_coeff[index+6:index+10])[0]
|
||||||
|
phase_coeff[g][3] = struct.unpack('>i', cali_coeff[index+10:index+14])[0]
|
||||||
|
phase_offset[g][3] = struct.unpack('>i', cali_coeff[index+14:index+18])[0]
|
||||||
|
|
||||||
# hsrtia_a.append(struct.unpack('>I', cali_coeff[index+1:index+5])[0])
|
#hstia=3
|
||||||
# hsrtia_b.append(struct.unpack('>I', cali_coeff[index+5:index+9])[0]/1e6)
|
cis_cali_packet = 10
|
||||||
# hsrtia_c.append(struct.unpack('>I', cali_coeff[index+9:index+13])[0]/1e5)
|
index = (cis_cali_packet - 1) * cis_data_len
|
||||||
# hsrtia_d.append(struct.unpack('>I', cali_coeff[index+13:index+17])[0]/1e6)
|
hsrtia_a.append(struct.unpack('>i', cali_coeff[index+2:index+6])[0])
|
||||||
|
hsrtia_b.append(struct.unpack('>q', cali_coeff[index+6:index+14])[0])
|
||||||
|
rolloff.append(struct.unpack('>i', cali_coeff[index+14:index+18])[0])
|
||||||
|
|
||||||
# print('cutoff_freq', cutoff_freq)
|
cis_cali_packet = 11
|
||||||
# print('hsrtia_a', hsrtia_a)
|
index = (cis_cali_packet - 1) * cis_data_len
|
||||||
# print('hsrtia_b', hsrtia_b)
|
g = 3
|
||||||
# print('hsrtia_c', hsrtia_c)
|
phase_coeff[g][0] = struct.unpack('>i', cali_coeff[index+2:index+6])[0]
|
||||||
# print('hsrtia_d', hsrtia_d)
|
phase_offset[g][0] = struct.unpack('>i', cali_coeff[index+6:index+10])[0]
|
||||||
# print('phase_para_a', phase_para_a)
|
phase_coeff[g][1] = struct.unpack('>i', cali_coeff[index+10:index+14])[0]
|
||||||
# print('phase_para_b', phase_para_b)
|
phase_offset[g][1] = struct.unpack('>i', cali_coeff[index+14:index+18])[0]
|
||||||
|
|
||||||
|
cis_cali_packet = 12
|
||||||
|
index = (cis_cali_packet - 1) * cis_data_len
|
||||||
|
g = 3
|
||||||
|
phase_coeff[g][2] = struct.unpack('>i', cali_coeff[index+2:index+6])[0]
|
||||||
|
phase_offset[g][2] = struct.unpack('>i', cali_coeff[index+6:index+10])[0]
|
||||||
|
phase_coeff[g][3] = struct.unpack('>i', cali_coeff[index+10:index+14])[0]
|
||||||
|
phase_offset[g][3] = struct.unpack('>i', cali_coeff[index+14:index+18])[0]
|
||||||
|
|
||||||
cali_table.append((cutoff_freq, phase_para_a, phase_para_b, hsrtia_a, hsrtia_b, hsrtia_c, hsrtia_d))
|
#hstia=4
|
||||||
|
cis_cali_packet = 13
|
||||||
|
index = (cis_cali_packet - 1) * cis_data_len
|
||||||
|
hsrtia_a.append(struct.unpack('>i', cali_coeff[index+2:index+6])[0])
|
||||||
|
hsrtia_b.append(struct.unpack('>q', cali_coeff[index+6:index+14])[0])
|
||||||
|
rolloff.append(struct.unpack('>i', cali_coeff[index+14:index+18])[0])
|
||||||
|
|
||||||
|
cis_cali_packet = 14
|
||||||
|
index = (cis_cali_packet - 1) * cis_data_len
|
||||||
|
g = 4
|
||||||
|
phase_coeff[g][0] = struct.unpack('>i', cali_coeff[index+2:index+6])[0]
|
||||||
|
phase_offset[g][0] = struct.unpack('>i', cali_coeff[index+6:index+10])[0]
|
||||||
|
phase_coeff[g][1] = struct.unpack('>i', cali_coeff[index+10:index+14])[0]
|
||||||
|
phase_offset[g][1] = struct.unpack('>i', cali_coeff[index+14:index+18])[0]
|
||||||
|
|
||||||
|
cis_cali_packet = 15
|
||||||
|
index = (cis_cali_packet - 1) * cis_data_len
|
||||||
|
g = 4
|
||||||
|
phase_coeff[g][2] = struct.unpack('>i', cali_coeff[index+2:index+6])[0]
|
||||||
|
phase_offset[g][2] = struct.unpack('>i', cali_coeff[index+6:index+10])[0]
|
||||||
|
phase_coeff[g][3] = struct.unpack('>i', cali_coeff[index+10:index+14])[0]
|
||||||
|
phase_offset[g][3] = struct.unpack('>i', cali_coeff[index+14:index+18])[0]
|
||||||
|
|
||||||
|
#hstia=5
|
||||||
|
cis_cali_packet = 16
|
||||||
|
index = (cis_cali_packet - 1) * cis_data_len
|
||||||
|
hsrtia_a.append(struct.unpack('>i', cali_coeff[index+2:index+6])[0])
|
||||||
|
hsrtia_b.append(struct.unpack('>q', cali_coeff[index+6:index+14])[0])
|
||||||
|
rolloff.append(struct.unpack('>i', cali_coeff[index+14:index+18])[0])
|
||||||
|
|
||||||
|
cis_cali_packet = 17
|
||||||
|
index = (cis_cali_packet - 1) * cis_data_len
|
||||||
|
g = 5
|
||||||
|
phase_coeff[g][0] = struct.unpack('>i', cali_coeff[index+2:index+6])[0]
|
||||||
|
phase_offset[g][0] = struct.unpack('>i', cali_coeff[index+6:index+10])[0]
|
||||||
|
phase_coeff[g][1] = struct.unpack('>i', cali_coeff[index+10:index+14])[0]
|
||||||
|
phase_offset[g][1] = struct.unpack('>i', cali_coeff[index+14:index+18])[0]
|
||||||
|
|
||||||
|
cis_cali_packet = 18
|
||||||
|
index = (cis_cali_packet - 1) * cis_data_len
|
||||||
|
g = 5
|
||||||
|
phase_coeff[g][2] = struct.unpack('>i', cali_coeff[index+2:index+6])[0]
|
||||||
|
phase_offset[g][2] = struct.unpack('>i', cali_coeff[index+6:index+10])[0]
|
||||||
|
phase_coeff[g][3] = struct.unpack('>i', cali_coeff[index+10:index+14])[0]
|
||||||
|
phase_offset[g][3] = struct.unpack('>i', cali_coeff[index+14:index+18])[0]
|
||||||
|
|
||||||
|
#hstia=6
|
||||||
|
cis_cali_packet = 19
|
||||||
|
index = (cis_cali_packet - 1) * cis_data_len
|
||||||
|
hsrtia_a.append(struct.unpack('>i', cali_coeff[index+2:index+6])[0])
|
||||||
|
hsrtia_b.append(struct.unpack('>q', cali_coeff[index+6:index+14])[0])
|
||||||
|
rolloff.append(struct.unpack('>i', cali_coeff[index+14:index+18])[0])
|
||||||
|
|
||||||
|
cis_cali_packet = 20
|
||||||
|
index = (cis_cali_packet - 1) * cis_data_len
|
||||||
|
g = 6
|
||||||
|
phase_coeff[g][0] = struct.unpack('>i', cali_coeff[index+2:index+6])[0]
|
||||||
|
phase_offset[g][0] = struct.unpack('>i', cali_coeff[index+6:index+10])[0]
|
||||||
|
phase_coeff[g][1] = struct.unpack('>i', cali_coeff[index+10:index+14])[0]
|
||||||
|
phase_offset[g][1] = struct.unpack('>i', cali_coeff[index+14:index+18])[0]
|
||||||
|
|
||||||
|
cis_cali_packet = 21
|
||||||
|
index = (cis_cali_packet - 1) * cis_data_len
|
||||||
|
g = 6
|
||||||
|
phase_coeff[g][2] = struct.unpack('>i', cali_coeff[index+2:index+6])[0]
|
||||||
|
phase_offset[g][2] = struct.unpack('>i', cali_coeff[index+6:index+10])[0]
|
||||||
|
phase_coeff[g][3] = struct.unpack('>i', cali_coeff[index+10:index+14])[0]
|
||||||
|
phase_offset[g][3] = struct.unpack('>i', cali_coeff[index+14:index+18])[0]
|
||||||
|
|
||||||
|
#hstia=7
|
||||||
|
cis_cali_packet = 22
|
||||||
|
index = (cis_cali_packet - 1) * cis_data_len
|
||||||
|
hsrtia_a.append(struct.unpack('>i', cali_coeff[index+2:index+6])[0])
|
||||||
|
hsrtia_b.append(struct.unpack('>q', cali_coeff[index+6:index+14])[0])
|
||||||
|
rolloff.append(struct.unpack('>i', cali_coeff[index+14:index+18])[0])
|
||||||
|
|
||||||
|
cis_cali_packet = 23
|
||||||
|
index = (cis_cali_packet - 1) * cis_data_len
|
||||||
|
g = 7
|
||||||
|
phase_coeff[g][0] = struct.unpack('>i', cali_coeff[index+2:index+6])[0]
|
||||||
|
phase_offset[g][0] = struct.unpack('>i', cali_coeff[index+6:index+10])[0]
|
||||||
|
phase_coeff[g][1] = struct.unpack('>i', cali_coeff[index+10:index+14])[0]
|
||||||
|
phase_offset[g][1] = struct.unpack('>i', cali_coeff[index+14:index+18])[0]
|
||||||
|
|
||||||
|
cis_cali_packet = 24
|
||||||
|
index = (cis_cali_packet - 1) * cis_data_len
|
||||||
|
g = 7
|
||||||
|
phase_coeff[g][2] = struct.unpack('>i', cali_coeff[index+2:index+6])[0]
|
||||||
|
phase_offset[g][2] = struct.unpack('>i', cali_coeff[index+6:index+10])[0]
|
||||||
|
phase_coeff[g][3] = struct.unpack('>i', cali_coeff[index+10:index+14])[0]
|
||||||
|
phase_offset[g][3] = struct.unpack('>i', cali_coeff[index+14:index+18])[0]
|
||||||
|
print('hsrtia_a', hsrtia_a)
|
||||||
|
print('hsrtia_b', hsrtia_b)
|
||||||
|
print('rolloff', rolloff)
|
||||||
|
print('phase_coeff')
|
||||||
|
print(phase_coeff)
|
||||||
|
print('phase_offset')
|
||||||
|
print(phase_offset)
|
||||||
|
|
||||||
|
cali_table.append((phase_coeff, phase_offset, hsrtia_a, hsrtia_b, rolloff))
|
||||||
|
|
||||||
return cali_table
|
return cali_table
|
||||||
else:
|
else:
|
||||||
@@ -1441,10 +1652,10 @@ class EISZeroOneDataDecoder(RecDataDecoder):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self) -> AnyStr:
|
def name(self) -> AnyStr:
|
||||||
if self._cali_coeff is None:
|
if self._cali_package is None:
|
||||||
return self.NAME
|
return self.NAME
|
||||||
else:
|
else:
|
||||||
return self.NAME.encode() + b':' + self._cali_coeff
|
return self.NAME.encode() + b':' + self._cali_package
|
||||||
|
|
||||||
def message(self) -> Optional[str]:
|
def message(self) -> Optional[str]:
|
||||||
ret = self._message
|
ret = self._message
|
||||||
@@ -1456,15 +1667,20 @@ class EISZeroOneDataDecoder(RecDataDecoder):
|
|||||||
if len(data) < 18:
|
if len(data) < 18:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
ch1 = struct.unpack('>i', data[1:5])[0] # unit: 1/1000 nA
|
ch1 = struct.unpack('>i', data[1+3:5+3])[0] # unit: 1/1000 nA
|
||||||
ch2 = struct.unpack('>i', data[5:9])[0] # unit: mV
|
ch2 = struct.unpack('>i', data[5+3:9+3])[0] # unit: mV
|
||||||
ch3 = struct.unpack('>i', data[9:13])[0] # unit: kOm
|
ch3 = struct.unpack('>i', data[9+3:13+3])[0] # unit: kOm
|
||||||
time_stamp: float = struct.unpack('<I', data[13:17])[0] # unit: ms
|
time_stamp: float = struct.unpack('<I', data[13+3:17+3])[0] # unit: ms
|
||||||
cycle_number = struct.unpack('>H', data[17:19])[0]
|
cycle_number = struct.unpack('>H', data[17+3:19+3])[0]
|
||||||
d19 = data[19]
|
d19 = data[19+3]
|
||||||
gain = (d19 & 0x0F)
|
gain = data[20+3]
|
||||||
finishMode = (d19 & 0x80) >> 7
|
finishMode = (d19 & 0x80) >> 7
|
||||||
|
ch4 = struct.unpack('<i', data[21+3:25+3])[0] # Amp[uV]
|
||||||
|
|
||||||
|
notify_one = struct.unpack('<i', data[25+3:29+3])[0]
|
||||||
|
notify_two = struct.unpack('<i', data[29+3:33+3])[0]
|
||||||
|
notify_three = struct.unpack('<i', data[33+3:37+3])[0]
|
||||||
|
|
||||||
if time_stamp == 0:
|
if time_stamp == 0:
|
||||||
self._start_return_data = True
|
self._start_return_data = True
|
||||||
|
|
||||||
@@ -1472,7 +1688,7 @@ class EISZeroOneDataDecoder(RecDataDecoder):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
if time_stamp != 0 and self._start_return_data == True:
|
if time_stamp != 0 and self._start_return_data == True:
|
||||||
if (self._mode == 0):
|
if (self._mode == 0 or self._mode == 5):
|
||||||
time_stamp, delta, ret_get_time_stamp = self.eis_get_time_stamp(time_stamp)
|
time_stamp, delta, ret_get_time_stamp = self.eis_get_time_stamp(time_stamp)
|
||||||
else:
|
else:
|
||||||
time_stamp, delta, ret_get_time_stamp = self.get_time_stamp(time_stamp)
|
time_stamp, delta, ret_get_time_stamp = self.get_time_stamp(time_stamp)
|
||||||
@@ -1481,101 +1697,83 @@ class EISZeroOneDataDecoder(RecDataDecoder):
|
|||||||
print("error timeStamp full data:", list(data), datetime.now(), '\n')
|
print("error timeStamp full data:", list(data), datetime.now(), '\n')
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
if self.cali_coeff is not None and self._mode == 0:
|
if self.cali_coeff is not None and (self._mode == 0 or self._mode == 5):
|
||||||
phase_para_a = []
|
|
||||||
phase_para_b = []
|
|
||||||
hsrtia_a = []
|
hsrtia_a = []
|
||||||
hsrtia_b = []
|
hsrtia_b = []
|
||||||
hsrtia_c = []
|
rolloff = []
|
||||||
hsrtia_d = []
|
phase_coeff, phase_offset, hsrtia_a, hsrtia_b, rolloff = self.cali_coeff[0]
|
||||||
cutoff_freq, phase_para_a, phase_para_b, hsrtia_a, hsrtia_b, hsrtia_c, hsrtia_d = self.cali_coeff[0]
|
|
||||||
voltage_amp = round(self._ac_amp * 800 / 2047) # use UI value
|
|
||||||
if (self._freq_start > self._freq_stop):
|
|
||||||
self._freq_direction = 0
|
|
||||||
else:
|
|
||||||
self._freq_direction = 1
|
|
||||||
|
|
||||||
if (self._mode == 0):
|
if (self._mode == 0 or self._mode == 5):
|
||||||
img = ch1
|
img = ch1
|
||||||
real = ch2
|
real = ch2
|
||||||
freq = ch3
|
freq = ch3
|
||||||
|
fre_idx = 0
|
||||||
|
voltage_amp = round(ch4 / 1000) # Amp[mV]
|
||||||
|
rolloff_cali = rolloff[gain]
|
||||||
|
|
||||||
voltage_mag = math.sqrt(img ** 2 + real ** 2) * (1 + freq ** 2 / cutoff_freq ** 2)
|
voltage_mag = math.sqrt(img ** 2 + real ** 2) * (1 + freq ** 2 / rolloff_cali ** 2 / 1e4)
|
||||||
|
current = (voltage_mag ** 2 * hsrtia_a[gain] + voltage_mag * hsrtia_b[gain]) / 1e8 #[nA]
|
||||||
# if (gain == 3):
|
|
||||||
# current = hsrtia_a[gain] * math.exp(hsrtia_b[gain] * voltage_mag) + hsrtia_c[gain] * math.exp(hsrtia_d[gain] * voltage_mag)
|
|
||||||
# else:
|
|
||||||
current = voltage_mag ** 2 * hsrtia_a[gain] + voltage_mag * hsrtia_b[gain] + hsrtia_c[gain]
|
|
||||||
# print(current)
|
|
||||||
# print(voltage_mag)
|
|
||||||
# print(hsrtia_a[gain])
|
|
||||||
# print(hsrtia_b[gain])
|
|
||||||
# print(hsrtia_c[gain])
|
|
||||||
|
|
||||||
if (current != 0):
|
if (current != 0):
|
||||||
# impedance = voltage_amp * 1000_000 / 1.414213 / current
|
# impedance[mOhm] = voltage_amp[mv] * 1000000 / 1.414213 / current[nA] #RMS=amp*SQRT(2), SQRT(2)=1.414213
|
||||||
impedance = voltage_amp * 707106.78 / current
|
impedance = voltage_amp * 707106.78 / current
|
||||||
else:
|
else:
|
||||||
impedance = 0
|
impedance = 0
|
||||||
|
|
||||||
if (real > 0):
|
raw_phase = math.atan2(img , real) * 180 / math.pi
|
||||||
raw_phase = math.atan(img / real) * 180 / math.pi
|
|
||||||
elif (real == 0):
|
|
||||||
raw_phase = 90
|
|
||||||
else:
|
|
||||||
raw_phase = math.atan(img / real) * 180 / math.pi + 180
|
|
||||||
|
|
||||||
if (freq >= 1000000): # 10000 Hz
|
if (freq >= 1000000): # 10000 Hz
|
||||||
i = 0
|
fre_idx = 0
|
||||||
elif (freq >= 10000): # 100 Hz
|
elif (freq >= 10000): # 100 Hz
|
||||||
i = 1
|
fre_idx = 1
|
||||||
elif (freq >= 1000): # 10 Hz
|
elif (freq >= 1000): # 10 Hz
|
||||||
i = 2
|
fre_idx = 2
|
||||||
elif (freq >= 1): # 0.01 Hz
|
elif (freq >= 1): # 0.01 Hz
|
||||||
i = 3
|
fre_idx = 3
|
||||||
|
|
||||||
ideal_raw_phase = phase_para_a[i] /1e10 * freq + phase_para_b[i] / 1e6
|
ideal_raw_phase = phase_coeff[gain][fre_idx] /1e10 * freq + phase_offset[gain][fre_idx] / 1e6
|
||||||
|
|
||||||
phase = raw_phase - ideal_raw_phase
|
phase = raw_phase - ideal_raw_phase
|
||||||
|
phase = phase % 180 if phase % 180<=90 else phase % 180-180
|
||||||
|
|
||||||
if (self._first_phase_flag):
|
imag_after_cal = round(impedance * math.sin(phase * math.pi / 180))
|
||||||
self._last_phase = phase
|
real_after_cal = round(impedance * math.cos(phase * math.pi / 180))
|
||||||
self._first_phase_flag = 0
|
|
||||||
elif (abs(phase - self._last_phase) >= 200):
|
|
||||||
phase -= 360
|
|
||||||
self._last_phase = phase
|
|
||||||
|
|
||||||
imag_after_cal = impedance * math.sin(round(phase) * math.pi / 180)
|
if self._show_data:
|
||||||
real_after_cal = impedance * math.cos(round(phase) * math.pi / 180)
|
if (self._mode == 0 or self._mode == 5):
|
||||||
|
print('|', '{:10}'.format(time_stamp),
|
||||||
|
'|', '{:5}'.format(delta),
|
||||||
|
'|', '{:5}'.format(ch1), #raw_img
|
||||||
|
'|', '{:5}'.format(ch2), #raw_real
|
||||||
|
'|', '{:8}'.format(ch3 * 10), '[mHz]', #Frequency [mHz]
|
||||||
|
'|', '{:5}'.format(cycle_number), #cycle
|
||||||
|
'|', '{:5}'.format(round(imag_after_cal)), '[Ohm]', #Z_imag [Ohm]
|
||||||
|
'|', '{:5}'.format(round(real_after_cal)), '[Ohm]', #Z_real [Ohm]
|
||||||
|
'|', '{:5}'.format(round(impedance)), '[Ohm]', #Impedance [Ohm]
|
||||||
|
'|', '{:5}'.format(round(phase*1000)), '[mdegree]', #Phase [millidegree]
|
||||||
|
'|', '{:5}'.format(round(current)), '[nA]', #Current [nA]
|
||||||
|
'|', '{:1}'.format(gain), #gain
|
||||||
|
'|', '{:1}'.format(finishMode), #finishMode
|
||||||
|
'@', str(self.device), '|', flush = True)
|
||||||
|
|
||||||
|
print('|', '{:10}'.format(time_stamp),
|
||||||
if (self._mode == 0):
|
'|', '{:5}'.format(delta),
|
||||||
# print('|', '{:10}'.format(time_stamp),
|
'|', '{:5}'.format(notify_one),
|
||||||
# '|', '{:5}'.format(delta),
|
'|', '{:5}'.format(notify_two),
|
||||||
# '|', '{:6}'.format(ch1),
|
'|', '{:5}'.format(notify_three),
|
||||||
# '|', '{:6}'.format(ch2),
|
'|', '{:5}'.format(voltage_amp), #amp[mV]
|
||||||
# '|', '{:8}'.format(ch3 / 100),
|
'|', flush = True)
|
||||||
# '|', '{:6}'.format(round(voltage_mag)),
|
pass
|
||||||
# '|', '{:5}'.format(int(imag_after_cal)),
|
else:
|
||||||
# '|', '{:5}'.format(int(real_after_cal)),
|
print('|', '{:10}'.format(time_stamp),
|
||||||
# '|', '{:5}'.format(round(impedance)),
|
'|', '{:5}'.format(delta),
|
||||||
# '|', '{:5}'.format(round(phase, 1)),
|
'|', '{:5}'.format(ch1),
|
||||||
# '|', '{:5}'.format(round(current, 3)),
|
'|', '{:5}'.format(ch2),
|
||||||
# '|', '{:1}'.format(gain),
|
'|', '{:5}'.format(ch3),
|
||||||
# '|', '{:1}'.format(finishMode),
|
'|', '{:5}'.format(cycle_number),
|
||||||
# '@', str(self.device), '|')
|
'|', '{:1}'.format(gain),
|
||||||
pass
|
'|', '{:1}'.format(finishMode),
|
||||||
else:
|
'@', str(self.device), '|', flush = True)
|
||||||
# print('|', '{:10}'.format(time_stamp),
|
pass
|
||||||
# '|', '{:5}'.format(delta),
|
|
||||||
# '|', '{:5}'.format(ch1),
|
|
||||||
# '|', '{:5}'.format(ch2),
|
|
||||||
# '|', '{:5}'.format(ch3),
|
|
||||||
# '|', '{:5}'.format(cycle_number),
|
|
||||||
# '|', '{:1}'.format(gain),
|
|
||||||
# '|', '{:1}'.format(finishMode),
|
|
||||||
# '@', str(self.device), '|')
|
|
||||||
pass
|
|
||||||
|
|
||||||
if finishMode == True:
|
if finishMode == True:
|
||||||
print("finishMode full data:", list(data), datetime.now())
|
print("finishMode full data:", list(data), datetime.now())
|
||||||
@@ -1584,23 +1782,29 @@ class EISZeroOneDataDecoder(RecDataDecoder):
|
|||||||
self._mode_stop = 0
|
self._mode_stop = 0
|
||||||
|
|
||||||
ret = RecordingData(self.device, int(time_stamp * 1000 / 2), 0)
|
ret = RecordingData(self.device, int(time_stamp * 1000 / 2), 0)
|
||||||
if (self._mode == 0): #EIS Mode
|
if self._mode == 0 or self._mode == 5:
|
||||||
ret.append_data(3, cycle_number)
|
ret.append_data(0, ch1) #raw_img
|
||||||
ret.append_data(0, ch1) #Raw Imag
|
ret.append_data(1, ch2) #raw_real
|
||||||
ret.append_data(1, ch2) #Raw Real
|
|
||||||
ret.append_data(2, ch3 * 10) #Frequency [mHz]
|
ret.append_data(2, ch3 * 10) #Frequency [mHz]
|
||||||
ret.append_data(4, round(imag_after_cal)) #Z_imag [Ohm]
|
ret.append_data(3, cycle_number) #cycle
|
||||||
ret.append_data(5, round(real_after_cal)) #Z_real [Ohm]
|
ret.append_data(4, imag_after_cal) #Z_imag [Ohm]
|
||||||
|
ret.append_data(5, real_after_cal) #Z_real [Ohm]
|
||||||
ret.append_data(6, round(impedance)) #Impedance [Ohm]
|
ret.append_data(6, round(impedance)) #Impedance [Ohm]
|
||||||
ret.append_data(7, round(phase)) #Phase [degree]
|
ret.append_data(7, round(phase*1000)) #Phase [millidegree]
|
||||||
ret.append_data(8, round(current)) #Current [nA]
|
ret.append_data(8, round(current)) #Current [nA]
|
||||||
ret.append_data(9, gain) #Gain Level
|
ret.append_data(9, gain) #gain
|
||||||
|
|
||||||
|
#debug data
|
||||||
|
ret.append_data(10, notify_one)
|
||||||
|
ret.append_data(11, notify_two)
|
||||||
|
ret.append_data(12, notify_three)
|
||||||
|
ret.append_data(13, voltage_amp) #amp[mV]
|
||||||
|
|
||||||
else: #CV Mode
|
else: #CV Mode
|
||||||
ret.append_data(3, cycle_number)
|
|
||||||
ret.append_data(0, ch1) #Iin [nA]
|
ret.append_data(0, ch1) #Iin [nA]
|
||||||
ret.append_data(1, ch2) #Vset [nV]
|
ret.append_data(1, ch2) #Vset [nV]
|
||||||
ret.append_data(2, ch3) #Vout [nV]
|
ret.append_data(2, ch3) #Vout [nV]
|
||||||
|
ret.append_data(3, cycle_number)
|
||||||
|
|
||||||
if cycle_number != self._cycle_number:
|
if cycle_number != self._cycle_number:
|
||||||
# notify cycle_number change
|
# notify cycle_number change
|
||||||
|
|||||||
@@ -651,17 +651,9 @@ class DeviceInstruction:
|
|||||||
VIS_DEVICE_DONE = 0x20
|
VIS_DEVICE_DONE = 0x20
|
||||||
"""identify device done"""
|
"""identify device done"""
|
||||||
|
|
||||||
VIS_CC_ZERO = 0x40
|
|
||||||
|
|
||||||
VIS_ASK = 0x30
|
|
||||||
"""ask in virtual instruction"""
|
|
||||||
|
|
||||||
VIS_STI = 0xC0
|
VIS_STI = 0xC0
|
||||||
"""stimulation on virtual instruction"""
|
"""stimulation on virtual instruction"""
|
||||||
|
|
||||||
VIS_FUH = 0x90
|
|
||||||
"""flush virtual instruction"""
|
|
||||||
|
|
||||||
VIS_INT = 0x60
|
VIS_INT = 0x60
|
||||||
"""interrupt virtual instruction"""
|
"""interrupt virtual instruction"""
|
||||||
|
|
||||||
@@ -732,7 +724,6 @@ class DeviceCommonInstruction:
|
|||||||
STOP_STIMULATE = "stop_stimulate"
|
STOP_STIMULATE = "stop_stimulate"
|
||||||
VIS_DEVICE_DETECT = 'VIS_DEVICE_DETECT'
|
VIS_DEVICE_DETECT = 'VIS_DEVICE_DETECT'
|
||||||
VIS_DEVICE_DONE = 'VIS_DEVICE_DONE'
|
VIS_DEVICE_DONE = 'VIS_DEVICE_DONE'
|
||||||
VIS_CC_ZERO = 'VIS_CC_ZERO'
|
|
||||||
CIS_VOLT = 'CIS_VOLT'
|
CIS_VOLT = 'CIS_VOLT'
|
||||||
CIS_VERSION = 'CIS_VERSION'
|
CIS_VERSION = 'CIS_VERSION'
|
||||||
|
|
||||||
@@ -747,19 +738,15 @@ class DeviceCommonInstruction:
|
|||||||
elif instruction == cls.START:
|
elif instruction == cls.START:
|
||||||
return '_data_format("TDC4VAF2")', '_notify(True)', 'VIS_STI', '_sync(True)'
|
return '_data_format("TDC4VAF2")', '_notify(True)', 'VIS_STI', '_sync(True)'
|
||||||
elif instruction == cls.INTERRUPT:
|
elif instruction == cls.INTERRUPT:
|
||||||
return '_sync(False)', '_notify(False)', 'VIS_INT'
|
return '_notify(False)', 'VIS_INT', '_sync(False)'
|
||||||
elif instruction == cls.CLOSE:
|
elif instruction == cls.CLOSE:
|
||||||
return '_sync(False)', '_notify(False)', 'VIS_INT'
|
return '_sync(False)', '_notify(False)', 'VIS_INT'
|
||||||
elif instruction == cls.FLUSH:
|
|
||||||
return 'VIS_FUH',
|
|
||||||
elif instruction == cls.CALL:
|
elif instruction == cls.CALL:
|
||||||
return 'VIS_CAL',
|
return 'VIS_CAL',
|
||||||
elif instruction == cls.VIS_DEVICE_DETECT:
|
elif instruction == cls.VIS_DEVICE_DETECT:
|
||||||
return 'VIS_DEVICE_DETECT',
|
return 'VIS_DEVICE_DETECT',
|
||||||
elif instruction == cls.VIS_DEVICE_DONE:
|
elif instruction == cls.VIS_DEVICE_DONE:
|
||||||
return 'VIS_DEVICE_DONE',
|
return 'VIS_DEVICE_DONE',
|
||||||
elif instruction == cls.VIS_CC_ZERO:
|
|
||||||
return 'VIS_CC_ZERO',
|
|
||||||
elif instruction == cls.RECORD:
|
elif instruction == cls.RECORD:
|
||||||
return 'VIS_STARTR',
|
return 'VIS_STARTR',
|
||||||
elif instruction == cls.RECORD_ALL:
|
elif instruction == cls.RECORD_ALL:
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from biopro.util.text import part_suffix
|
|||||||
from . import *
|
from . import *
|
||||||
from .expression import *
|
from .expression import *
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
class DeviceParameterError(RuntimeError):
|
class DeviceParameterError(RuntimeError):
|
||||||
__slots__ = ()
|
__slots__ = ()
|
||||||
@@ -309,6 +310,8 @@ class ParameterValueDomain(ParameterDomain, metaclass=abc.ABCMeta):
|
|||||||
return f
|
return f
|
||||||
|
|
||||||
def valid_para(self, value: Any) -> bool:
|
def valid_para(self, value: Any) -> bool:
|
||||||
|
if isinstance(value, list):
|
||||||
|
return True
|
||||||
f, t = self.range
|
f, t = self.range
|
||||||
return f <= float(value) < t
|
return f <= float(value) < t
|
||||||
|
|
||||||
@@ -489,8 +492,12 @@ class ParameterCollectionValueOperator(metaclass=abc.ABCMeta):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def parse(cls, expr: Union[int, str]) -> 'ParameterCollectionValueOperator':
|
def parse(cls, expr: Union[int, str]) -> 'ParameterCollectionValueOperator':
|
||||||
|
# parse epression then create value_operator
|
||||||
if isinstance(expr, int):
|
if isinstance(expr, int):
|
||||||
return SingleValueOperator(None, expr)
|
return SingleValueOperator(None, expr)
|
||||||
|
|
||||||
|
elif isinstance(expr, list):
|
||||||
|
return CollectValueOperator((0, len(expr)), expr)
|
||||||
|
|
||||||
elif expr == '*':
|
elif expr == '*':
|
||||||
return AddAllValueOperator
|
return AddAllValueOperator
|
||||||
@@ -498,6 +505,10 @@ class ParameterCollectionValueOperator(metaclass=abc.ABCMeta):
|
|||||||
elif expr == ':=':
|
elif expr == ':=':
|
||||||
return CollectValueOperator((None, None), [])
|
return CollectValueOperator((None, None), [])
|
||||||
|
|
||||||
|
elif '[' in expr and ']' in expr:
|
||||||
|
v = json.loads(expr)
|
||||||
|
return CollectValueOperator((0, len(v)), v)
|
||||||
|
|
||||||
elif '=' in expr:
|
elif '=' in expr:
|
||||||
a, v = part_suffix(expr, '=')
|
a, v = part_suffix(expr, '=')
|
||||||
|
|
||||||
@@ -508,6 +519,7 @@ class ParameterCollectionValueOperator(metaclass=abc.ABCMeta):
|
|||||||
return CollectValueOperator((None, None), v)
|
return CollectValueOperator((None, None), v)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
# get list length (old way)
|
||||||
a, b = part_suffix(a, ':')
|
a, b = part_suffix(a, ':')
|
||||||
a = int(a) if len(a) else None
|
a = int(a) if len(a) else None
|
||||||
b = int(b) if len(b) 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):
|
def __init__(self, domain: ParameterDomain):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
if isinstance(domain, ParameterCollectionDomain):
|
# if isinstance(domain, ParameterCollectionDomain):
|
||||||
raise RuntimeError('cannot compose with parameter collection domain')
|
# raise RuntimeError('cannot compose with parameter collection domain')
|
||||||
|
|
||||||
self._domain = domain
|
self._domain = domain
|
||||||
|
|
||||||
@@ -725,6 +737,7 @@ class ParameterListDomain(ParameterCollectionDomain):
|
|||||||
if oper == AddAllValueOperator:
|
if oper == AddAllValueOperator:
|
||||||
raise ValueError("list parameter cannot accept '*' (all) value")
|
raise ValueError("list parameter cannot accept '*' (all) value")
|
||||||
|
|
||||||
|
# d: domain, sz: lsit length, i: slice(a, b), v: list value
|
||||||
d = self.element_domain
|
d = self.element_domain
|
||||||
sz = len(target)
|
sz = len(target)
|
||||||
i = oper.index(sz)
|
i = oper.index(sz)
|
||||||
|
|||||||
@@ -119,7 +119,10 @@ class DeviceConfigurationEncoder:
|
|||||||
e.write(b'L\0')
|
e.write(b'L\0')
|
||||||
|
|
||||||
else:
|
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(b'L')
|
||||||
e.write(parameter_type.encode())
|
e.write(parameter_type.encode())
|
||||||
e.u8(sz)
|
e.u8(sz)
|
||||||
@@ -153,7 +156,8 @@ class DeviceConfigurationEncoder:
|
|||||||
if isinstance(value, bool):
|
if isinstance(value, bool):
|
||||||
e.u8(1 if value else 0)
|
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)
|
e.encode_string(value)
|
||||||
|
|
||||||
elif isinstance(value, int):
|
elif isinstance(value, int):
|
||||||
@@ -170,7 +174,7 @@ class DeviceConfigurationEncoder:
|
|||||||
if isinstance(value, bool):
|
if isinstance(value, bool):
|
||||||
return '?'
|
return '?'
|
||||||
|
|
||||||
elif isinstance(value, str):
|
elif isinstance(value, str) or isinstance(value, list):
|
||||||
return 'p'
|
return 'p'
|
||||||
|
|
||||||
elif isinstance(value, int):
|
elif isinstance(value, int):
|
||||||
|
|||||||
@@ -283,6 +283,7 @@ class InternalInstruction(SingleInstruction):
|
|||||||
PREDEFINED_SET = '_set'
|
PREDEFINED_SET = '_set'
|
||||||
PREDEFINED_CDR = '_cdr'
|
PREDEFINED_CDR = '_cdr'
|
||||||
PREDEFINED_DISABLE_CACHE = '_disable_cache'
|
PREDEFINED_DISABLE_CACHE = '_disable_cache'
|
||||||
|
PREDEFINED_IDLE = '_idle'
|
||||||
|
|
||||||
PREDEFINED = (
|
PREDEFINED = (
|
||||||
PREDEFINED_SLEEP,
|
PREDEFINED_SLEEP,
|
||||||
@@ -294,6 +295,7 @@ class InternalInstruction(SingleInstruction):
|
|||||||
PREDEFINED_SET,
|
PREDEFINED_SET,
|
||||||
PREDEFINED_CDR,
|
PREDEFINED_CDR,
|
||||||
PREDEFINED_DISABLE_CACHE,
|
PREDEFINED_DISABLE_CACHE,
|
||||||
|
PREDEFINED_IDLE,
|
||||||
)
|
)
|
||||||
|
|
||||||
__slots__ = ('_expr', '_para')
|
__slots__ = ('_expr', '_para')
|
||||||
@@ -792,6 +794,7 @@ class InstructionDataContent(InstructionContent):
|
|||||||
offset += 1
|
offset += 1
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
buffer.extend([0]*(self._width.size-len(buffer)))
|
||||||
for i in range(self._width.size):
|
for i in range(self._width.size):
|
||||||
if self._width.little_endian:
|
if self._width.little_endian:
|
||||||
value |= (buffer[offset] << (1 * i))
|
value |= (buffer[offset] << (1 * i))
|
||||||
@@ -1268,14 +1271,15 @@ class InstructionTable(DictNode['Instruction']):
|
|||||||
instruction: str):
|
instruction: str):
|
||||||
"""call instruction. chain context with :class:`DeviceInternalInstructionScope`
|
"""call instruction. chain context with :class:`DeviceInternalInstructionScope`
|
||||||
|
|
||||||
:param master: master device
|
:param master: DeviceManager
|
||||||
:param device: device
|
:param device: CompletedDevice
|
||||||
:param context: scope
|
:param context: scope
|
||||||
:param instruction: instruction name
|
:param instruction: instruction name
|
||||||
:raises InstructionNotFound: If instruction not found.
|
:raises InstructionNotFound: If instruction not found.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
# ex. start
|
||||||
ins = self[instruction]
|
ins = self[instruction]
|
||||||
|
|
||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
@@ -1284,6 +1288,7 @@ class InstructionTable(DictNode['Instruction']):
|
|||||||
else:
|
else:
|
||||||
context = context.chain(InstructionTableScope(self))
|
context = context.chain(InstructionTableScope(self))
|
||||||
|
|
||||||
|
# ex. _data_format, _sync, _notify
|
||||||
for single in ins.eval_instruction(context):
|
for single in ins.eval_instruction(context):
|
||||||
if isinstance(single, InternalInstruction):
|
if isinstance(single, InternalInstruction):
|
||||||
if not single.handle_internal_instruction(master, device, context):
|
if not single.handle_internal_instruction(master, device, context):
|
||||||
|
|||||||
@@ -510,9 +510,10 @@ class DeviceParameter(JsonSerialize):
|
|||||||
:param para: parameter name
|
:param para: parameter name
|
||||||
:param oper: operator expression
|
:param oper: operator expression
|
||||||
"""
|
"""
|
||||||
|
# parse operator return CollectValueOperator instance
|
||||||
if not isinstance(oper, ParameterCollectionValueOperator):
|
if not isinstance(oper, ParameterCollectionValueOperator):
|
||||||
oper = ParameterCollectionValueOperator.parse(oper)
|
oper = ParameterCollectionValueOperator.parse(oper)
|
||||||
|
|
||||||
table = self._library.parameter_table
|
table = self._library.parameter_table
|
||||||
info = table[para]
|
info = table[para]
|
||||||
domain = info.domain
|
domain = info.domain
|
||||||
@@ -528,6 +529,7 @@ class DeviceParameter(JsonSerialize):
|
|||||||
old = list(target)
|
old = list(target)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
# replace target with new oper
|
||||||
domain.oper_para(target, oper, self._context)
|
domain.oper_para(target, oper, self._context)
|
||||||
except RuntimeError as e:
|
except RuntimeError as e:
|
||||||
raise IllegalParameterValueError(para, str(oper)) from e
|
raise IllegalParameterValueError(para, str(oper)) from e
|
||||||
@@ -966,7 +968,7 @@ class CompletedDevice(Device):
|
|||||||
"""
|
"""
|
||||||
__slots__ = ('_master', '_device_id', '_device', '_library', '_context',
|
__slots__ = ('_master', '_device_id', '_device', '_library', '_context',
|
||||||
'_parameter', '_configuration', '_lock', '_feature_mask',
|
'_parameter', '_configuration', '_lock', '_feature_mask',
|
||||||
'_cache_battery', '_cache_battery_timestamp', '_coeff')
|
'_cache_battery', '_cache_battery_timestamp', '_coeff', '_status', '_occupied_by_project')
|
||||||
|
|
||||||
def __init__(self, master: MasterDevice, library: DeviceLibrary, device_id: int, device: Device):
|
def __init__(self, master: MasterDevice, library: DeviceLibrary, device_id: int, device: Device):
|
||||||
"""
|
"""
|
||||||
@@ -976,11 +978,17 @@ class CompletedDevice(Device):
|
|||||||
:param device_id: device id
|
:param device_id: device id
|
||||||
:param device: slave device implementation
|
:param device: slave device implementation
|
||||||
"""
|
"""
|
||||||
|
# DeviceManager
|
||||||
self._master = master
|
self._master = master
|
||||||
self._device = device
|
self._device = device
|
||||||
self._device_id = device_id
|
self._device_id = device_id
|
||||||
self._library = library
|
self._library = library
|
||||||
|
|
||||||
|
# device status ( 0: idle, 1: working, 2: error, 3: power off)
|
||||||
|
self._status = 0
|
||||||
|
# device be occupied by project
|
||||||
|
self._occupied_by_project = None
|
||||||
|
|
||||||
# context
|
# context
|
||||||
s1 = library.constant
|
s1 = library.constant
|
||||||
s2 = DeviceScope(self)
|
s2 = DeviceScope(self)
|
||||||
@@ -1008,6 +1016,10 @@ class CompletedDevice(Device):
|
|||||||
def device_id(self) -> int:
|
def device_id(self) -> int:
|
||||||
return self._device_id
|
return self._device_id
|
||||||
|
|
||||||
|
@property
|
||||||
|
def memory_board(self) -> int:
|
||||||
|
return self._device_id
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_name(self) -> str:
|
def device_name(self) -> str:
|
||||||
return self._device.device_name
|
return self._device.device_name
|
||||||
@@ -1020,6 +1032,10 @@ class CompletedDevice(Device):
|
|||||||
def mac_address(self) -> ADDRESS:
|
def mac_address(self) -> ADDRESS:
|
||||||
return self._device.mac_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).upper()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device(self) -> Device:
|
def device(self) -> Device:
|
||||||
return self._device
|
return self._device
|
||||||
@@ -1056,11 +1072,26 @@ class CompletedDevice(Device):
|
|||||||
return self._library
|
return self._library
|
||||||
|
|
||||||
# device lock
|
# device lock
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def lock(self) -> DeviceLock:
|
def lock(self) -> DeviceLock:
|
||||||
return self._lock
|
return self._lock
|
||||||
|
|
||||||
|
@property
|
||||||
|
def status(self) -> int:
|
||||||
|
return self._status
|
||||||
|
|
||||||
|
@status.setter
|
||||||
|
def status(self, new_status):
|
||||||
|
self._status = new_status
|
||||||
|
|
||||||
|
@property
|
||||||
|
def occupied_by_project(self) -> str:
|
||||||
|
return self._occupied_by_project
|
||||||
|
|
||||||
|
@occupied_by_project.setter
|
||||||
|
def occupied_by_project(self, new_occupied_by_project):
|
||||||
|
self._occupied_by_project = new_occupied_by_project
|
||||||
|
|
||||||
# device parameter getter/setter
|
# device parameter getter/setter
|
||||||
|
|
||||||
def parameters(self) -> List[str]:
|
def parameters(self) -> List[str]:
|
||||||
@@ -1084,6 +1115,8 @@ class CompletedDevice(Device):
|
|||||||
return self._configuration.get_parameter(name, False)
|
return self._configuration.get_parameter(name, False)
|
||||||
|
|
||||||
def set_multi_parameters(self, parameter):
|
def set_multi_parameters(self, parameter):
|
||||||
|
if len(parameter) == 0:
|
||||||
|
return
|
||||||
for (name, value) in parameter[0].items():
|
for (name, value) in parameter[0].items():
|
||||||
if name != 'target':
|
if name != 'target':
|
||||||
self.set_parameter(name, value)
|
self.set_parameter(name, value)
|
||||||
@@ -1107,6 +1140,11 @@ class CompletedDevice(Device):
|
|||||||
self._parameter.set_parameter(name, value)
|
self._parameter.set_parameter(name, value)
|
||||||
# raise RuntimeError('illegal parameter value : ' + value) from e
|
# raise RuntimeError('illegal parameter value : ' + value) from e
|
||||||
else:
|
else:
|
||||||
|
if name == 'MODE':
|
||||||
|
if self.library_name.startswith('Elite_EDC') or 'EIS' in self.library_name:
|
||||||
|
self.set_parameter('CTRL_HIGH_Z_15', self.get_parameter('HIGHZ_TABLE')[value])
|
||||||
|
self.set_parameter('TIME_DURATION', 0)
|
||||||
|
|
||||||
self._parameter.set_parameter(name, value)
|
self._parameter.set_parameter(name, value)
|
||||||
|
|
||||||
on_change = info.on_change
|
on_change = info.on_change
|
||||||
@@ -1115,7 +1153,8 @@ class CompletedDevice(Device):
|
|||||||
self._master.log_warn('on_change instruction not found : ' + on_change)
|
self._master.log_warn('on_change instruction not found : ' + on_change)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.call_instruction(on_change)
|
if self._status == 1:
|
||||||
|
self.call_instruction(on_change)
|
||||||
|
|
||||||
# device instruction call
|
# device instruction call
|
||||||
|
|
||||||
@@ -1258,16 +1297,23 @@ class CompletedDevice(Device):
|
|||||||
|
|
||||||
def as_json(self) -> JSON_OBJECT:
|
def as_json(self) -> JSON_OBJECT:
|
||||||
return {
|
return {
|
||||||
|
'id': self.device_id,
|
||||||
|
'name': self.device_name,
|
||||||
|
'status': self._status,
|
||||||
'device_id': self.device_id,
|
'device_id': self.device_id,
|
||||||
'device_name': self.device_name,
|
'device_name': self.device_name,
|
||||||
'device_address': list(self.mac_address),
|
'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,
|
'battery': self.battery,
|
||||||
'parent': self.parent,
|
'parent': self.parent,
|
||||||
'recording_file_name': self.recording_file_name,
|
'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_name': self._library.name,
|
||||||
'library_version': str(self._library.version),
|
'library_version': str(self._library.version),
|
||||||
|
'occupied_by_project': self._occupied_by_project,
|
||||||
'configuration': self.configuration.as_json(list_hide=True),
|
'configuration': self.configuration.as_json(list_hide=True),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1357,20 +1403,6 @@ class DebugDevice(CompletedDevice):
|
|||||||
def read_command_return_data(self) -> Optional[bytes]:
|
def read_command_return_data(self) -> Optional[bytes]:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def send_command(self, ins_type: int, ins_oper: int, *instruction: int):
|
|
||||||
length = len(instruction)
|
|
||||||
print('instruction send :',
|
|
||||||
'%02X' % ((ins_type & 0xF0) | (self.device_id & 0x0F)),
|
|
||||||
'%02X' % ((ins_oper & 0xF0) | (length & 0x0F)),
|
|
||||||
' '.join(map(lambda v: '%02X' % v, instruction)))
|
|
||||||
|
|
||||||
def send_instruction(self, ins_type: int, ins_oper: int, *instruction: int):
|
|
||||||
length = len(instruction)
|
|
||||||
print('instruction send :',
|
|
||||||
'%02X' % ((ins_type & 0xF0) | (self.device_id & 0x0F)),
|
|
||||||
'%02X' % ((ins_oper & 0xF0) | (length & 0x0F)),
|
|
||||||
' '.join(map(lambda v: '%02X' % v, instruction)))
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def battery(self) -> int:
|
def battery(self) -> int:
|
||||||
return 100
|
return 100
|
||||||
|
|||||||
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.
@@ -3697,7 +3697,6 @@ class CC2650Central(LoggerFlag):
|
|||||||
|
|
||||||
def recv(self, timeout: Optional[float] = None) -> Optional[list]:
|
def recv(self, timeout: Optional[float] = None) -> Optional[list]:
|
||||||
packet = self._recv_byte()
|
packet = self._recv_byte()
|
||||||
# print("packet = ", packet)
|
|
||||||
|
|
||||||
if packet is None:
|
if packet is None:
|
||||||
return None
|
return None
|
||||||
@@ -3709,6 +3708,8 @@ class CC2650Central(LoggerFlag):
|
|||||||
|
|
||||||
def _recv_byte(self) -> Optional[int]:
|
def _recv_byte(self) -> Optional[int]:
|
||||||
ret = self._recv_bytes(1)
|
ret = self._recv_bytes(1)
|
||||||
|
# if ret is not None:
|
||||||
|
# print('packet = {0}'.format(hex(ret[0]).upper()))
|
||||||
return ret[0] if ret is not None else None
|
return ret[0] if ret is not None else None
|
||||||
|
|
||||||
def _recv_bytes(self, size: int = 1) -> Union[None, bytes]:
|
def _recv_bytes(self, size: int = 1) -> Union[None, bytes]:
|
||||||
@@ -3724,27 +3725,28 @@ class CC2650Central(LoggerFlag):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def _recv_event(self, timeout: Optional[float] = 1) -> Optional[list]:
|
def _recv_event(self, timeout: Optional[float] = 1) -> Optional[list]:
|
||||||
code = self._recv_byte()
|
packet = self._recv_byte()
|
||||||
# print("code = ", code)
|
|
||||||
|
|
||||||
if code is None:
|
if packet is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
length = self._recv_byte()
|
length = self._recv_byte()
|
||||||
# print('code::',code,'length::',length)
|
len_b = _struct.pack("B", length)
|
||||||
|
|
||||||
_start = _time()
|
|
||||||
data = b''
|
data = b''
|
||||||
|
|
||||||
while len(data) < length:
|
_start = _time()
|
||||||
ret = self._recv_bytes(length - len(data))
|
|
||||||
# print("ret = ", ret)
|
|
||||||
|
|
||||||
if ret is not None:
|
while len(data) < length:
|
||||||
data += ret
|
packets = self._recv_bytes(length - len(data))
|
||||||
|
# hex_packets = ''.join(format(i, '02x') for i in packets)
|
||||||
|
# print("packets = ", hex_packets.upper())
|
||||||
|
|
||||||
|
if packets is not None:
|
||||||
|
data += packets
|
||||||
elif timeout is not None and _time() - _start > timeout:
|
elif timeout is not None and _time() - _start > timeout:
|
||||||
raise RecvTimeout()
|
raise RecvTimeout()
|
||||||
|
|
||||||
|
data = len_b + data
|
||||||
self._interface.flush()
|
self._interface.flush()
|
||||||
return list(data)
|
return list(data)
|
||||||
|
|
||||||
@@ -3760,5 +3762,7 @@ class CC2650Central(LoggerFlag):
|
|||||||
raise RecvTimeout()
|
raise RecvTimeout()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
uart_data_hex = ''.join(format(i, '02X') for i in uart_data)
|
||||||
|
# print('uart_data: 0x{0}'.format(uart_data_hex.upper()))
|
||||||
return uart_data
|
return uart_data
|
||||||
|
|
||||||
|
|||||||
+173
-68
@@ -13,7 +13,7 @@ MSM_REG_WRITE = 0x01
|
|||||||
MEM_INS_WRITE = 0x02
|
MEM_INS_WRITE = 0x02
|
||||||
MEM_INS_READ = 0x03
|
MEM_INS_READ = 0x03
|
||||||
MEM_REG_READ = 0x05
|
MEM_REG_READ = 0x05
|
||||||
DEFAULT_REGISTER_VALUE = 0b0100_0011 # 67
|
DEFAULT_REGISTER_VALUE = 0b0100_0001 # 0x41
|
||||||
MEM_SIZE = 0x1000
|
MEM_SIZE = 0x1000
|
||||||
|
|
||||||
_SLEEP_TIME_ = 0.001
|
_SLEEP_TIME_ = 0.001
|
||||||
@@ -24,8 +24,10 @@ def zero_buffer(size: int) -> List[int]:
|
|||||||
return [0] * size
|
return [0] * size
|
||||||
|
|
||||||
class MultiExtMemSpiInterface(LowLevelHardwareInterface):
|
class MultiExtMemSpiInterface(LowLevelHardwareInterface):
|
||||||
MEM_INS_MARKED = [MEM_INS_WRITE, 0, 2, 1, 1]
|
MEM_INS_MARKED1 = [MEM_INS_WRITE, 0, 2, 0x5A, 0xA5]
|
||||||
MEM_INS_RESET = [MEM_INS_WRITE, 0, 2, 1, 1, 0, 0xFF]
|
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',
|
__slots__ = ('_selector', '_wait_for_first_data', '_spi', '_tx_buffer_header', '_tx_buffer_data',
|
||||||
'pin_busy', 'pin_mem_req', 'pin_mem_sel', 'pin_ram_sel',
|
'pin_busy', 'pin_mem_req', 'pin_mem_sel', 'pin_ram_sel',
|
||||||
@@ -33,7 +35,7 @@ class MultiExtMemSpiInterface(LowLevelHardwareInterface):
|
|||||||
'_pin_ram_sel_value', '_pin_mem_sel_value', '_pin_mem_req_value',
|
'_pin_ram_sel_value', '_pin_mem_sel_value', '_pin_mem_req_value',
|
||||||
'_read_green_times','_read_red_times',
|
'_read_green_times','_read_red_times',
|
||||||
'_elite_data_len', '_mem_header_len', '_mem_tailer_len', '_single_data_len',
|
'_elite_data_len', '_mem_header_len', '_mem_tailer_len', '_single_data_len',
|
||||||
'_head_wrong_cnt')
|
'_head_wrong_cnt', '_pin_busy_value')
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
select: Selector,
|
select: Selector,
|
||||||
@@ -44,15 +46,15 @@ class MultiExtMemSpiInterface(LowLevelHardwareInterface):
|
|||||||
|
|
||||||
self._elite_data_len = 40
|
self._elite_data_len = 40
|
||||||
self._mem_header_len = 3
|
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
|
self._single_data_len = self._elite_data_len + self._mem_header_len + self._mem_tailer_len
|
||||||
|
|
||||||
# buffer
|
# buffer
|
||||||
self._tx_buffer_header = [0] * 11
|
self._tx_buffer_header = [0] * 64
|
||||||
self._tx_buffer_data = [0] * (self._single_data_len * 10 + 3)
|
self._tx_buffer_data = [0] * (self._single_data_len * 10 + 3)
|
||||||
|
|
||||||
# memory control pin
|
# memory control pin
|
||||||
self.pin_busy = OutputPin.get_used(P3Pin.MEM_BZY, True)
|
self.pin_busy: Optional[InputPin] = InputPin.get_used(P3Pin.MEM_BZY)
|
||||||
self.pin_mem_req = OutputPin.get_used(P3Pin.MEM_REQ, False)
|
self.pin_mem_req = OutputPin.get_used(P3Pin.MEM_REQ, False)
|
||||||
self.pin_mem_sel = OutputPin.get_used(P3Pin.MEM_RST, True) # MEM_RST -> actually which memory board is assign
|
self.pin_mem_sel = OutputPin.get_used(P3Pin.MEM_RST, True) # MEM_RST -> actually which memory board is assign
|
||||||
self.pin_ram_sel: Optional[InputPin] = InputPin.get_used(P3Pin.MEM_SEL) # MEM_SEL -> actually is RAM_SEL, which RAM is assign
|
self.pin_ram_sel: Optional[InputPin] = InputPin.get_used(P3Pin.MEM_SEL) # MEM_SEL -> actually is RAM_SEL, which RAM is assign
|
||||||
@@ -60,6 +62,7 @@ class MultiExtMemSpiInterface(LowLevelHardwareInterface):
|
|||||||
self._pin_ram_sel_value = [bool(self.pin_ram_sel) for _ in range(Selector.SIZE)]
|
self._pin_ram_sel_value = [bool(self.pin_ram_sel) for _ in range(Selector.SIZE)]
|
||||||
self._pin_mem_sel_value = [bool(self.pin_mem_sel) for _ in range(Selector.SIZE)]
|
self._pin_mem_sel_value = [bool(self.pin_mem_sel) for _ in range(Selector.SIZE)]
|
||||||
self._pin_mem_req_value = [bool(self.pin_mem_req) for _ in range(Selector.SIZE)]
|
self._pin_mem_req_value = [bool(self.pin_mem_req) for _ in range(Selector.SIZE)]
|
||||||
|
self._pin_busy_value = [bool(self.pin_busy) for _ in range(Selector.SIZE)]
|
||||||
|
|
||||||
self._read_green_times = 0
|
self._read_green_times = 0
|
||||||
self._read_red_times = 0
|
self._read_red_times = 0
|
||||||
@@ -74,6 +77,8 @@ class MultiExtMemSpiInterface(LowLevelHardwareInterface):
|
|||||||
|
|
||||||
def set_pin_mem_req(self, value: bool):
|
def set_pin_mem_req(self, value: bool):
|
||||||
channel = self.select
|
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.output(value)
|
||||||
self._pin_mem_req_value[channel] = value
|
self._pin_mem_req_value[channel] = value
|
||||||
|
|
||||||
@@ -94,6 +99,14 @@ class MultiExtMemSpiInterface(LowLevelHardwareInterface):
|
|||||||
self._pin_ram_sel_value[channel] = True
|
self._pin_ram_sel_value[channel] = True
|
||||||
return self._pin_ram_sel_value[channel]
|
return self._pin_ram_sel_value[channel]
|
||||||
|
|
||||||
|
def get_pin_busy(self):
|
||||||
|
channel = self.select
|
||||||
|
if self.pin_busy.input() == 0:
|
||||||
|
self._pin_busy_value[channel] = False
|
||||||
|
else:
|
||||||
|
self._pin_busy_value[channel] = True
|
||||||
|
return self._pin_busy_value[channel]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def select(self) -> int:
|
def select(self) -> int:
|
||||||
return self._selector.channel
|
return self._selector.channel
|
||||||
@@ -165,8 +178,56 @@ class MultiExtMemSpiInterface(LowLevelHardwareInterface):
|
|||||||
print("read red data times", self._read_red_times)
|
print("read red data times", self._read_red_times)
|
||||||
return data
|
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]:
|
def recv_memory(self, device: int) -> Optional[bytes]:
|
||||||
self.pin_busy.output(False)
|
# self.pin_busy.output(False)
|
||||||
|
|
||||||
|
# print('mem_req==ram_sel,[', self._pin_mem_req_value[device], ',', self._pin_ram_sel_value[device], ']')
|
||||||
|
|
||||||
rx = []
|
rx = []
|
||||||
|
|
||||||
@@ -191,7 +252,7 @@ class MultiExtMemSpiInterface(LowLevelHardwareInterface):
|
|||||||
self._head_wrong_cnt[device] = self._head_wrong_cnt[device] + 1
|
self._head_wrong_cnt[device] = self._head_wrong_cnt[device] + 1
|
||||||
if (self._head_wrong_cnt[device] <= 5): # print 5 times
|
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('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]
|
data[0:3] = [255, 255, 255]
|
||||||
# ----------------------------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------------------------
|
||||||
@@ -210,13 +271,13 @@ class MultiExtMemSpiInterface(LowLevelHardwareInterface):
|
|||||||
# self._head_wrong_cnt[device] = self._head_wrong_cnt[device] + 1
|
# self._head_wrong_cnt[device] = self._head_wrong_cnt[device] + 1
|
||||||
# if (self._head_wrong_cnt[device] < 10):
|
# if (self._head_wrong_cnt[device] < 10):
|
||||||
# print('data_first[0:3] != [255, 255, 255], device:', device, ',', self._head_wrong_cnt[device], 'times')
|
# 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):
|
# 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
|
# self._head_wrong_cnt[device] = self._head_wrong_cnt[device] + 1
|
||||||
# if (self._head_wrong_cnt[device] < 10):
|
# if (self._head_wrong_cnt[device] < 10):
|
||||||
# print('data_second[0:3] != [255, 255, 255], device:', device, ',', self._head_wrong_cnt[device], 'times')
|
# 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:]):
|
# if (data_first[3:] == data_second[3:]):
|
||||||
# data = data_first
|
# data = data_first
|
||||||
@@ -228,59 +289,50 @@ class MultiExtMemSpiInterface(LowLevelHardwareInterface):
|
|||||||
# data = self.compare_green_data(data_first, data_second, data_third, len(tx_h))
|
# data = self.compare_green_data(data_first, data_second, data_third, len(tx_h))
|
||||||
# ----------------------------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
# debug use
|
green_data_section = self._compare_green_data_addr_and_flag(data, device)
|
||||||
# green_data = []
|
|
||||||
# green_data = data
|
|
||||||
# print("_[Debug] @ spi green data = ", green_data)
|
|
||||||
|
|
||||||
length = (data[3] << 8) | data[4]
|
length = (green_data_section[0] << 8) | green_data_section[1]
|
||||||
header = data[7]
|
header = data[15]
|
||||||
elite_data_len = data[9]
|
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
|
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
|
# give a default length if the data header did not update
|
||||||
length = 7000
|
print("green data: is not [0xA5, 0x5A], = ", data[5:7])
|
||||||
print("green data: is not [0,0], = ", data[5:7])
|
|
||||||
print("green data print:", data, device, datetime.now())
|
print("green data print:", data, device, datetime.now())
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if (length >= 7000):
|
# print('data=', list(data))
|
||||||
|
# print('Ram:', data[62])
|
||||||
|
|
||||||
|
if (length >= 4000):
|
||||||
flag_print = True
|
flag_print = True
|
||||||
print("green data: big length:", length)
|
print("green data: big length:", length)
|
||||||
|
|
||||||
if (header != 255):
|
if (header != 255):
|
||||||
flag_print = True
|
flag_print = True
|
||||||
print("green data: header is not 255: ", header)
|
print("green data: header is not 255: ", header)
|
||||||
|
# self._print_ram_all_data()
|
||||||
|
|
||||||
if (elite_data_len != self._elite_data_len):
|
if (elite_data_len != self._elite_data_len):
|
||||||
flag_print = True
|
flag_print = True
|
||||||
print("green data: length is not", self._elite_data_len, ": ", elite_data_len)
|
print("green data: length is not", self._elite_data_len, ": ", elite_data_len)
|
||||||
|
|
||||||
if (flag_print):
|
if (flag_print):
|
||||||
print("green data print:", data, device, datetime.now())
|
print("green data print:", data, device, datetime.now(), '\n')
|
||||||
|
|
||||||
# neulive
|
address = 12
|
||||||
# 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
|
|
||||||
red_length = int(length / 2)
|
red_length = int(length / 2)
|
||||||
tx_d = [0] * red_length
|
tx_d = [0] * (red_length + 3)
|
||||||
|
|
||||||
# elite read len(_tx_buffer_data) byte
|
|
||||||
# address = 4
|
|
||||||
# tx_d = self._tx_buffer_data
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
tx_d[0] = MEM_INS_READ
|
tx_d[0] = MEM_INS_READ
|
||||||
@@ -319,29 +371,67 @@ class MultiExtMemSpiInterface(LowLevelHardwareInterface):
|
|||||||
address += len(data) - 3
|
address += len(data) - 3
|
||||||
del data
|
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):
|
# 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()
|
# print()
|
||||||
|
|
||||||
# /*
|
# /*
|
||||||
# * red data formate:
|
# * red data formate:
|
||||||
# * ramHdr, ramHdr, ramHdr, (3B)
|
# * ramHdr, ramHdr, ramHdr, (3B)
|
||||||
# * 255, #, data_length, (3B)
|
# * 255, #, data_length, (3B)
|
||||||
# * data, (20B)
|
# * data, (40B)
|
||||||
# * red_wrong, red_retry_cnt, green_wrong, green_retry_cnt, (4B)
|
# * 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
|
# 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:
|
except BaseException as e:
|
||||||
print(e)
|
print(e)
|
||||||
|
|
||||||
finally:
|
# finally:
|
||||||
# print("\n")
|
# # print("\n")
|
||||||
self.pin_busy.output(True)
|
# self.pin_busy.output(True)
|
||||||
|
|
||||||
return bytes(rx)
|
return bytes(rx)
|
||||||
|
|
||||||
@@ -367,6 +457,16 @@ class MultiExtMemSpiInterface(LowLevelHardwareInterface):
|
|||||||
|
|
||||||
self._spi.send_byte(tx)
|
self._spi.send_byte(tx)
|
||||||
|
|
||||||
|
def test_ram(self, channel: int):
|
||||||
|
spi_MOSI = [MEM_INS_WRITE, 0, 0, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
|
||||||
|
self._spi.send_byte(spi_MOSI)
|
||||||
|
print('device:', channel, 'spi_MOSI:',spi_MOSI)
|
||||||
|
|
||||||
|
spi_MISO = [0] * len(spi_MOSI)
|
||||||
|
spi_MISO[0:3] = [MEM_INS_READ, 0, 0]
|
||||||
|
spi_MISO = self._spi.send_byte(spi_MISO)
|
||||||
|
print('device:', channel, 'spi_MISO:', spi_MISO)
|
||||||
|
|
||||||
class ExtMemManager:
|
class ExtMemManager:
|
||||||
def __init__(self, ext_mem: MultiExtMemSpiInterface):
|
def __init__(self, ext_mem: MultiExtMemSpiInterface):
|
||||||
self._ext_mem = ext_mem
|
self._ext_mem = ext_mem
|
||||||
@@ -403,28 +503,31 @@ class ExtMemManager:
|
|||||||
|
|
||||||
ret[channel] = tuple(r)
|
ret[channel] = tuple(r)
|
||||||
|
|
||||||
|
print('ret=', ret)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def is_no_device(result: Tuple[Optional[int], Optional[int]]) -> bool:
|
def is_memory_test_fail(result: Tuple[Optional[int], Optional[int]], channel: int) -> int:
|
||||||
r1, r2 = result
|
r1, r2 = result
|
||||||
return (r1 is None or r2 is None) and (r1 is None or r1 == 0) and (r2 is None or r2 == 0)
|
r1_check = False
|
||||||
|
r2_check = False
|
||||||
|
|
||||||
@staticmethod
|
if r1 is not None and r1 != 0:
|
||||||
def is_memory_test_fail(result: Tuple[Optional[int], Optional[int]]) -> int:
|
if (r1 & 0b11000001 == DEFAULT_REGISTER_VALUE & 0b11000001):
|
||||||
r1, r2 = result
|
r1_check = True
|
||||||
|
print('device:', channel, 'ram0 ready')
|
||||||
|
|
||||||
|
if r2 is not None and r2 != 0:
|
||||||
|
if (r2 & 0b11000001 == DEFAULT_REGISTER_VALUE & 0b11000001):
|
||||||
|
r2_check = True
|
||||||
|
print('device:', channel, 'ram1 ready')
|
||||||
|
print('--------------------')
|
||||||
|
|
||||||
if r1 is None or r2 is None:
|
if r1_check and r2_check:
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
if r1 is not None and r1 > 0 and r1 != DEFAULT_REGISTER_VALUE:
|
|
||||||
return 2
|
|
||||||
|
|
||||||
if r2 is not None and r2 > 0 and r2 != DEFAULT_REGISTER_VALUE:
|
|
||||||
return 3
|
|
||||||
|
|
||||||
return 0
|
|
||||||
|
|
||||||
def get_available_channel(self, result: List[Tuple[Optional[int], Optional[int]]] = None) -> List[int]:
|
def get_available_channel(self, result: List[Tuple[Optional[int], Optional[int]]] = None) -> List[int]:
|
||||||
if result is None:
|
if result is None:
|
||||||
result = self.get_ext_mem_register()
|
result = self.get_ext_mem_register()
|
||||||
@@ -432,12 +535,14 @@ class ExtMemManager:
|
|||||||
ret = []
|
ret = []
|
||||||
|
|
||||||
for channel, result in enumerate(result):
|
for channel, result in enumerate(result):
|
||||||
if self.is_no_device(result):
|
if self.is_memory_test_fail(result, channel) != 0:
|
||||||
continue
|
|
||||||
|
|
||||||
if self.is_memory_test_fail(result) != 0:
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
ret.append(channel)
|
ret.append(channel)
|
||||||
|
|
||||||
|
# test ram
|
||||||
|
# for channel in self._ext_mem.foreach():
|
||||||
|
# if channel == 4 or channel == 5:
|
||||||
|
# self._ext_mem.test_ram(channel)
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class UARTInterface(LowLevelHardwareInterface):
|
|||||||
self._serial = serial.Serial(self._port,
|
self._serial = serial.Serial(self._port,
|
||||||
baudrate=self._baudrate,
|
baudrate=self._baudrate,
|
||||||
timeout=0,
|
timeout=0,
|
||||||
writeTimeout=0.01)
|
writeTimeout=1)
|
||||||
# deprecate function name which change at version 3.0
|
# deprecate function name which change at version 3.0
|
||||||
self._serial.flushInput()
|
self._serial.flushInput()
|
||||||
self._serial.flushOutput()
|
self._serial.flushOutput()
|
||||||
@@ -53,6 +53,8 @@ class UARTInterface(LowLevelHardwareInterface):
|
|||||||
:param data: raw byte instruction
|
:param data: raw byte instruction
|
||||||
:raises SerialTimeoutException:
|
:raises SerialTimeoutException:
|
||||||
"""
|
"""
|
||||||
|
data_hex = ''.join(format(i, '02X') for i in data)
|
||||||
|
# print('send_byte: 0x{0}'.format(data_hex.upper()))
|
||||||
self._serial.write(data)
|
self._serial.write(data)
|
||||||
|
|
||||||
def recv_byte(self, size: int) -> Optional[bytes]:
|
def recv_byte(self, size: int) -> Optional[bytes]:
|
||||||
|
|||||||
@@ -118,13 +118,13 @@ class Selector:
|
|||||||
self._p2.output(p[2])
|
self._p2.output(p[2])
|
||||||
|
|
||||||
# if (value == 4 and self._last_sel != 6):
|
# 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):
|
# 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):
|
# 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):
|
# 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
|
self._last_sel = value
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,65 +1,34 @@
|
|||||||
|
|
||||||
class Action():
|
class Action():
|
||||||
def __init__(self, task, action_id, action):
|
def __init__(self, action_id, action):
|
||||||
self._task = task
|
self._id: str = action_id
|
||||||
self._id:str = action_id
|
self._type: str = action['type']
|
||||||
self._type:str = action['type']
|
self._target: str = action['target']
|
||||||
self._target:str = action['target']
|
self._condition : list[str] = action['condition']
|
||||||
self._condition_list:list[str] = action['condition']
|
# self._duration = action.get('duration', None)
|
||||||
self._duration = action.get('duration', None)
|
# self._goto = action.get('goto', None)
|
||||||
self._goto = action.get('goto', None)
|
# self._cycle = action.get('cycle', None)
|
||||||
self._cycle = action.get('cycle', None)
|
|
||||||
|
|
||||||
self._instruction = None
|
|
||||||
|
|
||||||
self.update_instruction()
|
|
||||||
|
|
||||||
|
@property
|
||||||
|
def id(self):
|
||||||
|
return self._id
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def type(self):
|
def type(self):
|
||||||
return self._type
|
return self._type
|
||||||
|
|
||||||
def update_instruction(self):
|
@property
|
||||||
self._instruction = {
|
def target(self):
|
||||||
"device_instruction": {
|
return self._target
|
||||||
"header": "call_instruction",
|
|
||||||
"device": self._target,
|
@property
|
||||||
"arguments": {
|
def condition(self):
|
||||||
"instruction": self._type,
|
return self._condition
|
||||||
}
|
|
||||||
},
|
def as_json(self):
|
||||||
"device_parameter": {
|
return {
|
||||||
"header": "set_multi_parameters",
|
'id': self._id,
|
||||||
"device": self._target,
|
'type': self._type,
|
||||||
"arguments": {
|
'target': self._target,
|
||||||
"parameter": self._task.get_parameter_set_by_device(self._target),
|
'condition': self._condition
|
||||||
}
|
|
||||||
},
|
|
||||||
"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])
|
|
||||||
|
|||||||
@@ -3,73 +3,143 @@ from time import time
|
|||||||
|
|
||||||
class Condition():
|
class Condition():
|
||||||
def __init__(self, id, condition):
|
def __init__(self, id, condition):
|
||||||
print('condition', id, condition)
|
|
||||||
self._id = id
|
self._id = id
|
||||||
self._type = condition['type']
|
self._type = condition['type']
|
||||||
self._comparsion = condition['comparsion']
|
self._comparsion = condition['comparsion']
|
||||||
self._value = condition['value']
|
self._value = condition['value']
|
||||||
|
self._active = False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def id(self):
|
def id(self):
|
||||||
return self._id
|
return self._id
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def type(self):
|
def type(self):
|
||||||
return self._type
|
return self._type
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def comparsion(self):
|
def comparsion(self):
|
||||||
return self._comparsion
|
return self._comparsion
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def value(self):
|
def value(self):
|
||||||
return self._value
|
return self._value
|
||||||
|
|
||||||
def set_comparsion(self, comparsion):
|
@id.setter
|
||||||
self._comparsion = comparsion
|
def id(self, new_id):
|
||||||
|
self._id = new_id
|
||||||
def set_type(self, type):
|
|
||||||
self._type = type
|
|
||||||
|
|
||||||
def set_value(self, value):
|
@type.setter
|
||||||
self._value = value
|
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 = {
|
cases = {
|
||||||
"equal": lambda a, b: a == b,
|
"equal": lambda a, b: a == b,
|
||||||
"bigger": lambda a, b: a > b,
|
"bigger": lambda a, b: a >= b,
|
||||||
"smaller": 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)
|
return cases[operator](x, y)
|
||||||
|
|
||||||
def match_or_not(self, **kwargs):
|
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):
|
def absolute_time(self, **kwargs):
|
||||||
now = time()
|
# now = int(time())
|
||||||
time_condition = self.datetime_to_timestamp(self.str_to_datetime(self._value))
|
now = round(time(), 1)
|
||||||
|
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):
|
def after_project_run(self, **kwargs):
|
||||||
now = time()
|
project_start_time = kwargs['project_start_time']
|
||||||
|
delay_time = kwargs['delay_time']
|
||||||
|
|
||||||
|
# time_diff = int(time() - project_start_time - delay_time)
|
||||||
|
time_diff = round(time() - project_start_time - delay_time, 1)
|
||||||
|
return self.compareWith(self.comparsion, time_diff, round(int(self._value), 1))
|
||||||
|
|
||||||
|
def after_task_run(self, **kwargs):
|
||||||
|
# print('relative_time_from_task', kwargs['task_start_time'],kwargs['delay_time'])
|
||||||
|
if len(kwargs['task_start_time']) == 0:
|
||||||
|
return False
|
||||||
|
task = kwargs['self_task']
|
||||||
|
running_task = kwargs['running_task']
|
||||||
|
task_start_time = kwargs['task_start_time'][-1]
|
||||||
|
delay_time = kwargs['delay_time']
|
||||||
|
|
||||||
|
time_diff = round(time() - task_start_time - delay_time, 1)
|
||||||
|
# print('real_diff', time() - task_start_time - delay_time)
|
||||||
|
# print(task.name, task.uuid, time_diff, round(int(self._value), 1), running_task.name, running_task.uuid)
|
||||||
|
# if round(int(self._value), 1) == 0 and time_diff == 0.1:
|
||||||
|
# return True
|
||||||
|
if task.uuid != running_task.uuid:
|
||||||
|
return False
|
||||||
|
return self.compareWith('bigger', time_diff, round(int(self._value), 1))
|
||||||
|
# return self.compareWith(self.comparsion, time_diff, round(int(self._value), 1))
|
||||||
|
|
||||||
def device(self, **kwargs):
|
def device(self, **kwargs):
|
||||||
print('device')
|
print('device')
|
||||||
|
|
||||||
def task_status(self, **kwargs):
|
""" def previous_task_done(self, **kwargs):
|
||||||
print('task_status')
|
running_task = kwargs['running_task']
|
||||||
|
if running_task.status == 2 and self._active == False:
|
||||||
|
self._active = True
|
||||||
|
return True
|
||||||
|
return False """
|
||||||
|
|
||||||
def method_mapping(self, method_name):
|
def previous_task_done(self, **kwargs):
|
||||||
methods = {
|
running_task = kwargs['running_task']
|
||||||
"relative_time": self.relative_time,
|
self_task = kwargs['self_task']
|
||||||
"absolute_time": self.absolute_time,
|
# if running_task != None and self_task != None:
|
||||||
"device": self.device,
|
# print('\nprevious_task_done: ', running_task.status, ' ', self._active)
|
||||||
"task_status": self.task_status,
|
if running_task != self_task:
|
||||||
}
|
if running_task == None:
|
||||||
return methods[method_name]
|
return True
|
||||||
|
if running_task.status == 2 and self._active == False:
|
||||||
|
# self._active = True
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def until_button_trigger(self, **kwargs):
|
||||||
|
running_task = kwargs['running_task']
|
||||||
|
if running_task != None:
|
||||||
|
if running_task.button_trigger == True:
|
||||||
|
running_task.button_trigger = False
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
""" def cycle(self, **kwargs):
|
||||||
|
running_task = kwargs['running_task']
|
||||||
|
self_task = kwargs['self_task']
|
||||||
|
if running_task != self_task:
|
||||||
|
if running_task.status == 2 and self._active == False:
|
||||||
|
# self._active = True
|
||||||
|
return True
|
||||||
|
return False """
|
||||||
|
|
||||||
def str_to_datetime(self, time_str):
|
def str_to_datetime(self, time_str):
|
||||||
return datetime.strptime(time_str,'%Y-%m-%dT%H:%M')
|
return datetime.strptime(time_str,'%Y-%m-%dT%H:%M')
|
||||||
|
|
||||||
def datetime_to_timestamp(self, date):
|
def datetime_to_timestamp(self, date):
|
||||||
return datetime.timestamp(date)
|
return datetime.timestamp(date)
|
||||||
|
|
||||||
|
def as_json(self):
|
||||||
|
return {
|
||||||
|
'id': self._id,
|
||||||
|
'type': self._type,
|
||||||
|
'comparsion': self._comparsion,
|
||||||
|
'value': self._value,
|
||||||
|
'active': self._active
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
|
||||||
|
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']))
|
||||||
|
self._idle_instruction = []
|
||||||
|
|
||||||
|
@property
|
||||||
|
def start(self) -> list:
|
||||||
|
return self._start_instruction
|
||||||
|
|
||||||
|
@property
|
||||||
|
def stop(self) -> list:
|
||||||
|
return self._stop_instruction
|
||||||
|
|
||||||
|
@property
|
||||||
|
def idle(self) -> list:
|
||||||
|
return self.idle_instruction
|
||||||
@@ -1,78 +1,392 @@
|
|||||||
from .task import Task
|
|
||||||
from .task_manager import TaskManager
|
|
||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import threading
|
import threading
|
||||||
import time
|
import logging
|
||||||
|
|
||||||
|
from time import time, sleep
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from collections import deque
|
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.device.manager import DeviceManager
|
||||||
from biopro.text import *
|
from biopro.text import *
|
||||||
|
|
||||||
|
from biopro.db.base import Session
|
||||||
|
from biopro.db.collection import Collection
|
||||||
|
|
||||||
|
key_list = {
|
||||||
|
'deviceList': 'device',
|
||||||
|
}
|
||||||
|
|
||||||
class Project(threading.Thread):
|
class Project(threading.Thread):
|
||||||
def __init__(self, project, device_manager: DeviceManager, mqttThread = None, name="project"):
|
def __init__(self, project, device_manager: DeviceManager, mqttThread = None, log_verbose = None, name="project"):
|
||||||
super(Project, self).__init__(name = name)
|
super(Project, self).__init__(name = name)
|
||||||
self._project = project
|
self._project = project
|
||||||
self._device_manager = device_manager
|
self._device_manager = device_manager
|
||||||
self._mqtt_thread = mqttThread
|
self._mqtt_thread = mqttThread
|
||||||
self._time_interval = 1
|
self._time_interval = 0.1
|
||||||
self._start_time = None
|
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._start_time = None
|
self._instruction_set = Instruction()
|
||||||
|
self._stop_flag = False
|
||||||
|
|
||||||
|
self._task_manager = None
|
||||||
|
|
||||||
|
self._cycle = []
|
||||||
|
|
||||||
|
self._count = 1 #流水號
|
||||||
|
|
||||||
|
self.log_verbose = log_verbose
|
||||||
|
self._logger = logging.getLogger('project')
|
||||||
|
self._logger.setLevel('DEBUG')
|
||||||
|
|
||||||
|
self._formatter = logging.Formatter('[%(asctime)s.%(msecs)03d] %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
|
||||||
|
self._formatter_with_nothing = logging.Formatter('%(message)s')
|
||||||
|
|
||||||
|
self.setup_project(project)
|
||||||
|
self.setup_device(self._device)
|
||||||
|
|
||||||
|
# create log file handler
|
||||||
|
fh = logging.FileHandler(f'/home/pi/logger/project/{self.uuid}.log', mode="w")
|
||||||
|
fh.setFormatter(self._formatter)
|
||||||
|
self._logger.addHandler(fh)
|
||||||
|
|
||||||
|
default_name = 'admin'
|
||||||
|
default_parent = {"folder": [1]}
|
||||||
|
collection = Collection.find_collection(default_name, default_parent)
|
||||||
|
parent = {"folder": [collection.id]}
|
||||||
|
# create project folder
|
||||||
|
collection = Collection.create_collection(self.name, parent)
|
||||||
|
self.setup_collection(collection)
|
||||||
|
|
||||||
|
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'], project['cycle'])
|
||||||
|
elif key == 'uuid':
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
setattr(self, key, value)
|
||||||
|
|
||||||
|
def setup_device(self, device_list):
|
||||||
|
for device in device_list:
|
||||||
|
mac_address = device_list[device]['pair']
|
||||||
|
complete_device = self._device_manager.get_device(mac_address)
|
||||||
|
complete_device.occupied_by_project = self._uuid
|
||||||
|
self._complete_device[device] = complete_device
|
||||||
|
|
||||||
|
def setup_collection(self, collection):
|
||||||
|
self._task_manager.create_collection(collection)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def id(self) -> int:
|
||||||
|
return self._id
|
||||||
|
|
||||||
|
@id.setter
|
||||||
|
def id(self, new_id):
|
||||||
|
self._id = new_id
|
||||||
|
|
||||||
|
@property
|
||||||
|
def uuid(self) -> str:
|
||||||
|
return self._uuid
|
||||||
|
|
||||||
|
@uuid.setter
|
||||||
|
def uuid(self, new_uuid):
|
||||||
|
self._uuid = new_uuid
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self) -> str:
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
@name.setter
|
||||||
|
def name(self, new_name):
|
||||||
|
self._name = new_name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cycle(self) -> list:
|
||||||
|
return self._cycle
|
||||||
|
|
||||||
|
@cycle.setter
|
||||||
|
def cycle(self, new_cycle):
|
||||||
|
self._cycle = new_cycle
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def desc(self) -> str:
|
def desc(self) -> str:
|
||||||
return self._project['desc']
|
return self._desc
|
||||||
|
|
||||||
|
@desc.setter
|
||||||
|
def desc(self, new_desc):
|
||||||
|
self._desc = new_desc
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def status(self) -> str:
|
def status(self) -> str:
|
||||||
return self._project['status']
|
return self._status
|
||||||
|
|
||||||
|
@status.setter
|
||||||
|
def status(self, new_status):
|
||||||
|
self._status = new_status
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device(self) -> list:
|
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
|
@property
|
||||||
def task(self) -> list:
|
def mqtt_thread(self):
|
||||||
return self._task_manager.get()
|
return self._mqtt_thread
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def get_current_task(self) -> str:
|
def running_task(self):
|
||||||
return self._task_manager.get_current_task()
|
return self._task_manager.running_task
|
||||||
|
|
||||||
|
def get_device_parameter_set(self, device_address):
|
||||||
|
parameter_set = self._task_manager.running_task.parameter_set
|
||||||
|
return next((x for x in parameter_set if parameter_set[x]['target'] == device_address), None)
|
||||||
|
|
||||||
|
def get_cycle(self, task):
|
||||||
|
for index, _cycle in enumerate(self.cycle):
|
||||||
|
if task.uuid in _cycle['range']:
|
||||||
|
return _cycle
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self._start_time = time.time()
|
# project status change running (1)
|
||||||
|
self._status = 1
|
||||||
|
# save start time
|
||||||
|
self._start_time = time()
|
||||||
|
|
||||||
while True:
|
# saving & broadcast message
|
||||||
# current task
|
self._logger.info('Project ' + self.name + ' start')
|
||||||
for task in self._task_manager.get_check_task_list():
|
self.log_verbose('Project ' + self.name + ' start')
|
||||||
# [<match_condition>, ...]
|
self.mqtt_thread.broadcast_command('project:' + self._name + ' start at ' + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
|
||||||
match_condition_list = task.check_condition('time')
|
|
||||||
# [[<match_action>, ...], ...]
|
while not self._stop_flag :
|
||||||
match_action_list = task.get_match_action_list(match_condition_list)
|
# check running task first
|
||||||
|
delay_time = 0
|
||||||
for action_list in match_action_list:
|
check_list = copy(self._task_manager.check_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'])
|
|
||||||
|
|
||||||
if device is None:
|
for task in check_list:
|
||||||
raise RuntimeError(DEVICE_NOT_FOUND, device)
|
if task != None:
|
||||||
|
now = time()
|
||||||
# print(instruction['header'], *instruction['arguments'].values())
|
|
||||||
getattr(device, instruction['header'])(*instruction['arguments'].values())
|
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,
|
||||||
|
self_task = task
|
||||||
|
)
|
||||||
|
|
||||||
|
for condition in match_condition_list:
|
||||||
|
match_action_list = task.get_match_action(condition.id)
|
||||||
|
print('match_action_list', match_action_list, match_action_list)
|
||||||
|
for action in match_action_list:
|
||||||
|
if action.type == 'cycle' and condition.type == 'previous_task_done':
|
||||||
|
self.mqtt_thread.broadcast_command('project:task ' + task.name + ' start at ' + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
|
||||||
|
self._task_manager.set_running_task(task)
|
||||||
|
cycle_info = self.get_cycle(task)
|
||||||
|
if cycle_info['useID'] == False:
|
||||||
|
self._logger.info(f'---------- Cycle {task.name} Round {cycle_info["count"]} -----------')
|
||||||
|
if action.type == 'cycle' and condition.type == 'until_button_trigger':
|
||||||
|
self._task_manager.running_task.stop()
|
||||||
|
self._logger.info(f'---------- Cycle {cycle_info["id"]} Round {cycle_info["count"]} -----------')
|
||||||
|
|
||||||
|
if self._task_manager.running_task != None:
|
||||||
|
if self._task_manager.running_task.uuid == task.uuid and action.type == 'cycle' and condition.type == 'after_task_run':
|
||||||
|
self._task_manager.running_task.stop()
|
||||||
|
|
||||||
|
if action.type == 'start':
|
||||||
|
if task.status != 1:
|
||||||
|
self._task_manager.set_running_task(task)
|
||||||
|
self._logger.info(f'Task {str(self._task_manager.running_task.name)} start')
|
||||||
|
self.mqtt_thread.broadcast_command('project:task ' + task.name + ' start at ' + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
|
||||||
|
# elif action.type == '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._count += 1
|
||||||
|
# if self.check_running_task_not_run() == True:
|
||||||
|
# self._task_manager.running_task.stop()
|
||||||
|
|
||||||
|
elif action.type == 'idle':
|
||||||
|
self._task_manager.running_task.stop()
|
||||||
|
# elif action.type == 'stop':
|
||||||
|
# self._task_manager.running_task.stop()
|
||||||
|
|
||||||
|
instruction_set = None
|
||||||
|
|
||||||
|
if action.target is not None:
|
||||||
|
device = self._complete_device[action.target]
|
||||||
|
if ((action.type == 'start' and device.status == 0) or (action.type == 'stop' and device.status == 1)):
|
||||||
|
self._logger.info(f'Device {device.mac_address_in_str} {action.type}')
|
||||||
|
self.log_verbose('Project' + self.name + 'Task ' + task.name + ' match_condition ' + condition.type + ' trigger_action ' + action.type + ' ' + str(action.target))
|
||||||
|
task_info = task.get_task_info(action)
|
||||||
|
instruction_set = getattr(self._instruction_set, action.type, None)
|
||||||
|
|
||||||
|
# 檔名修正
|
||||||
|
# device
|
||||||
|
task_info['file_name'] += '#' + device.mac_address_in_str[12:].upper()
|
||||||
|
# 流水號
|
||||||
|
task_info['file_name'] += '#' + str(self._count)
|
||||||
|
|
||||||
|
# 添加cycle資訊
|
||||||
|
if len(self.cycle) > 0:
|
||||||
|
index = self._task_manager.get_index_by_task(task)
|
||||||
|
# get list of cycle determine by index of task
|
||||||
|
filtered = list(filter(lambda info: self._task_manager.get_index_by_uuid(info['range'][0]) < index and self._task_manager.get_index_by_uuid(info['range'][1]) > index, self.cycle))
|
||||||
|
|
||||||
|
if len(filtered) == 0:
|
||||||
|
pass
|
||||||
|
elif len(filtered) == 1:
|
||||||
|
if filtered[0]['useID'] == True:
|
||||||
|
task_info['file_name'] += '#' + str(filtered[0]['id'])
|
||||||
|
else:
|
||||||
|
task_info['file_name'] += '#' + str(filtered[0]['name']) + '-' + str(filtered[0]['count'])
|
||||||
|
else:
|
||||||
|
# if multi cycle, then sort by range from task index to cycle start index, then loop concat filename
|
||||||
|
filtered.sort(key=lambda info: abs(self._task_manager.get_index_by_uuid(info['range'][0]) - index))
|
||||||
|
for cycle_info in filtered:
|
||||||
|
if cycle_info['useID'] == True:
|
||||||
|
task_info['file_name'] += '#' + str(cycle_info['id'])
|
||||||
|
else:
|
||||||
|
task_info['file_name'] += '#' + str(cycle_info['name']) + '-' + str(cycle_info['count'])
|
||||||
|
self.log_verbose('file name ' + task_info['file_name'])
|
||||||
|
|
||||||
|
if instruction_set != None and self.get_device_parameter_set(action.target) != None:
|
||||||
|
for instruction in instruction_set:
|
||||||
|
print('instruction 1', device, instruction, datetime.now())
|
||||||
|
args = list(map(lambda arg: task_info[arg], instruction['arguments']))
|
||||||
|
target=getattr(device, instruction['method'])(*args)
|
||||||
|
print('instruction 2', device, instruction, datetime.now())
|
||||||
|
if action.type == 'start':
|
||||||
|
self._count += 1
|
||||||
|
|
||||||
|
delay_time += (time() - now)
|
||||||
|
|
||||||
|
# check task not running then stop
|
||||||
|
if self.check_running_task_not_run() == True:
|
||||||
|
# self._logger.info(f'taskType {self._task_manager.running_task.name} {self._task_manager.running_task.type}')
|
||||||
|
if self._task_manager.running_task.type == '':
|
||||||
|
self._logger.info(f'Task {self._task_manager.running_task.name} 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._task_manager.running_task.stop()
|
||||||
|
|
||||||
|
# check project done then close project
|
||||||
|
if self.check_project_done() == True:
|
||||||
|
print('project stop at', datetime.now())
|
||||||
|
self.stop()
|
||||||
|
|
||||||
|
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):
|
def stop(self):
|
||||||
return
|
for device in self._complete_device:
|
||||||
|
self._complete_device[device].occupied_by_project = None
|
||||||
|
self._task_manager.running_task.stop()
|
||||||
|
self.mqtt_thread.broadcast_command('project:task ' + str(self._task_manager.running_task.name) + ' stop at ' + datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
|
||||||
|
self._status = 2
|
||||||
|
self._end_time = time()
|
||||||
|
self._stop_flag = True
|
||||||
|
self._logger.info('Project ' + self.name + ' stop')
|
||||||
|
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):
|
def close(self):
|
||||||
return
|
for device in self._complete_device:
|
||||||
|
self._complete_device[device].occupied_by_project = None
|
||||||
|
self._status = 2
|
||||||
|
self._end_time = time()
|
||||||
|
self._stop_flag = True
|
||||||
|
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 set_content(self, content):
|
||||||
|
self.running_task.button_trigger = True
|
||||||
|
|
||||||
|
def set_cycle(self, index, content):
|
||||||
|
# change cycle name
|
||||||
|
for key in content:
|
||||||
|
self.cycle[index][key] = content[key]
|
||||||
|
|
||||||
|
# change task name
|
||||||
|
# self._task_manager.get_task_by_uuid(self.cycle[index]['range'][0]).name = content['name']
|
||||||
|
# self._task_manager.get_task_by_uuid(self.cycle[index]['range'][1]).name = content['name']
|
||||||
|
|
||||||
|
def check_running_task_not_run(self):
|
||||||
|
# if no running task
|
||||||
|
if self._task_manager.running_task == None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# if running is cycle then no need to stop by device
|
||||||
|
if self._task_manager.running_task.type == 'cycle':
|
||||||
|
return False
|
||||||
|
|
||||||
|
for key in self._task_manager.running_task.action:
|
||||||
|
# print('action key', key, self._task_manager.running_task, self._task_manager.running_task.action[key])
|
||||||
|
if len(self._task_manager.running_task.parameter_set) == 0 and self._task_manager.running_task.action[key]['type'] == 'stop':
|
||||||
|
return False
|
||||||
|
if len(self._task_manager.running_task.parameter_set) == 0 and self._task_manager.running_task.action[key]['type'] == 'idle':
|
||||||
|
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,
|
||||||
|
'cycle': self._cycle,
|
||||||
|
'count': self._count,
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
|
||||||
|
def info_pass_data_server(self):
|
||||||
|
if self._task_manager.running_task is not None:
|
||||||
|
running_task = self._task_manager.running_task.as_json()
|
||||||
|
data = {
|
||||||
|
'project': self._uuid,
|
||||||
|
'task': running_task,
|
||||||
|
'cycle': self._cycle,
|
||||||
|
'serial_number': self._count,
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
|||||||
@@ -9,25 +9,40 @@ def json_stringify(o: Any) -> str:
|
|||||||
return _json_stringify(o, separators=(',', ':'))
|
return _json_stringify(o, separators=(',', ':'))
|
||||||
|
|
||||||
class ProjectManager():
|
class ProjectManager():
|
||||||
def __init__(self, device_manager: DeviceManager, mqtt_thread=None) :
|
def __init__(self, device_manager: DeviceManager, mqtt_thread=None, log_verbose = None) :
|
||||||
self._project_list = []
|
self._project_list = []
|
||||||
self._mqtt_thread = mqtt_thread
|
self._mqtt_thread = mqtt_thread
|
||||||
self._device_manager = device_manager
|
self._device_manager = device_manager
|
||||||
|
self.log_verbose = log_verbose
|
||||||
|
|
||||||
def create(self, project):
|
def create(self, project):
|
||||||
new_project = Project(project, self._device_manager, self._mqtt_thread)
|
new_project = Project(project, self._device_manager, self._mqtt_thread, self.log_verbose)
|
||||||
self._project_list.append(new_project)
|
self._project_list.append(new_project)
|
||||||
return new_project
|
return new_project
|
||||||
|
|
||||||
def remove(self, index):
|
def remove(self, index):
|
||||||
self._project_list[index].stop()
|
self._project_list[index].stop()
|
||||||
del self._project_list[index]
|
del self._project_list[index]
|
||||||
|
|
||||||
def get(self):
|
def get(self, project_uuid = None):
|
||||||
return self._project_list
|
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()
|
project.start()
|
||||||
|
|
||||||
def stop(self, project):
|
def stop_project(self, project):
|
||||||
project.stop()
|
_project = self.get(project)
|
||||||
|
_project.stop()
|
||||||
|
|
||||||
|
def set_project(self, project_uuid, content):
|
||||||
|
_project = self.get(project_uuid)
|
||||||
|
_project.set_content(content)
|
||||||
|
|
||||||
|
def set_project_cycle(self, project_uuid, index, content):
|
||||||
|
_project = self.get(project_uuid)
|
||||||
|
_project.set_cycle(index, content)
|
||||||
|
|||||||
+261
-117
@@ -1,110 +1,238 @@
|
|||||||
|
from typing import List
|
||||||
from .condition import Condition
|
from .condition import Condition
|
||||||
from .action import Action
|
from .action import Action
|
||||||
from time import time
|
from time import time
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
key_list = {
|
||||||
|
'deviceList': 'device',
|
||||||
|
'parameterSet': 'parameter_set'
|
||||||
|
}
|
||||||
|
|
||||||
class Task:
|
class Task:
|
||||||
def __init__(self, task):
|
def __init__(self, task):
|
||||||
self._task = task
|
self._id = None
|
||||||
|
self._uuid = None
|
||||||
self._condition_list = []
|
self._type = None
|
||||||
self._action_list = []
|
self._name = None
|
||||||
|
self._parent = None
|
||||||
self._start_time = time()
|
self._cycle = None
|
||||||
self._idle_time = []
|
self._cycle_count = 0
|
||||||
self._period = None
|
self._cycle_next = None
|
||||||
self._next_time = None
|
self._cycle_next_uuid = None
|
||||||
self._last_time = None
|
self._device = None
|
||||||
|
self._event = None
|
||||||
|
self._trigger = None
|
||||||
|
self._parameter_set = None
|
||||||
|
self._condition = None
|
||||||
|
self._action = None
|
||||||
|
# -1: init 0: start(idle), 1: run, 2: close(idle)
|
||||||
|
self._status = 0
|
||||||
|
self._next = None
|
||||||
|
|
||||||
|
# action & condition info
|
||||||
|
self._condition_list: List[Condition] = []
|
||||||
|
self._action_list: List[Action] = []
|
||||||
self._instruction_list = []
|
self._instruction_list = []
|
||||||
|
self._record_list = []
|
||||||
|
|
||||||
self.setup()
|
# time info
|
||||||
|
self._start_time = []
|
||||||
|
self._idle_time = []
|
||||||
|
self._end_time = []
|
||||||
|
self._period = None
|
||||||
|
|
||||||
|
# trigger info
|
||||||
|
self._button_trigger = False
|
||||||
|
|
||||||
|
self.load_task(task)
|
||||||
|
|
||||||
def setup(self) -> None:
|
def load_task(self, task) -> None:
|
||||||
# add condition
|
# update task attribute
|
||||||
for key, condition in self._task['condition'].items():
|
for key, value in task.items():
|
||||||
new_condition = Condition(key, condition)
|
if key in key_list.keys():
|
||||||
self._condition_list.append(new_condition)
|
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
|
def update_condition_list(self, condition_dict):
|
||||||
for key, action in self._task['action'].items():
|
self._condition_list.clear()
|
||||||
new_action = Action(self, key, action)
|
for key, condition in condition_dict.items():
|
||||||
self._action_list.append(new_action)
|
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
|
@property
|
||||||
def id(self) -> str:
|
def id(self) -> str:
|
||||||
return self._task['id']
|
return self._id
|
||||||
|
|
||||||
@property
|
@id.setter
|
||||||
def file_name(self):
|
def id(self, new_id):
|
||||||
return self._task['name']
|
self._id = new_id
|
||||||
|
|
||||||
@property
|
|
||||||
def parent(self):
|
|
||||||
return self._task.get('parent', {"folder": [2]})
|
|
||||||
|
|
||||||
@property
|
|
||||||
def instruction_list(self):
|
|
||||||
return self._instruction_list
|
|
||||||
|
|
||||||
@property
|
|
||||||
def cycle(self) -> int:
|
|
||||||
return self._task['cycle']
|
|
||||||
|
|
||||||
@property
|
|
||||||
def order(self) -> int:
|
|
||||||
return self._task['order']
|
|
||||||
|
|
||||||
@property
|
|
||||||
def max_cycle(self) -> int:
|
|
||||||
return self._task['max_cycle']
|
|
||||||
|
|
||||||
@property
|
|
||||||
def devices(self) -> dict:
|
|
||||||
return self._task['devices']
|
|
||||||
|
|
||||||
@property
|
|
||||||
def devices_id(self) -> list:
|
|
||||||
return [device_id for device_id in self.devices]
|
|
||||||
|
|
||||||
@property
|
|
||||||
def events(self) -> list:
|
|
||||||
return self._task['events']
|
|
||||||
|
|
||||||
@property
|
|
||||||
def triggers(self) -> list:
|
|
||||||
return self._task['triggers']
|
|
||||||
|
|
||||||
@property
|
|
||||||
def parameter_set(self) -> list:
|
|
||||||
return self._task['parameterSet']
|
|
||||||
|
|
||||||
@property
|
|
||||||
def instructions(self) -> list:
|
|
||||||
return self._task['instructions']
|
|
||||||
|
|
||||||
@property
|
|
||||||
def conditions(self) -> list:
|
|
||||||
return self._task['conditions']
|
|
||||||
|
|
||||||
@property
|
|
||||||
def actions(self) -> list:
|
|
||||||
return self._task['actions']
|
|
||||||
|
|
||||||
@property
|
|
||||||
def condition_list(self) -> list:
|
|
||||||
return self._condition_list
|
|
||||||
|
|
||||||
@property
|
|
||||||
def status(self) -> str:
|
|
||||||
return self._task['status']
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def uuid(self) -> str:
|
def uuid(self) -> str:
|
||||||
return self._task['uuid']
|
return self._uuid
|
||||||
|
|
||||||
|
@uuid.setter
|
||||||
|
def uuid(self, new_uuid):
|
||||||
|
self._uuid = new_uuid
|
||||||
|
|
||||||
|
@property
|
||||||
|
def type(self):
|
||||||
|
return self._type
|
||||||
|
|
||||||
|
@type.setter
|
||||||
|
def type(self, new_type):
|
||||||
|
self._type = new_type
|
||||||
|
|
||||||
|
@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
|
||||||
|
|
||||||
|
# TODO: not sure needed?
|
||||||
|
@property
|
||||||
|
def cycle_count(self) -> int:
|
||||||
|
return self._cycle_count
|
||||||
|
|
||||||
|
@cycle_count.setter
|
||||||
|
def cycle_count(self, new_cycle_count):
|
||||||
|
self._cycle_count = new_cycle_count
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cycle_next(self) -> str:
|
||||||
|
return self._cycle_next
|
||||||
|
|
||||||
|
@cycle_next.setter
|
||||||
|
def cycle_next(self, new_cycle_next):
|
||||||
|
self._cycle_next = new_cycle_next
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cycle_next_uuid(self) -> str:
|
||||||
|
return self._cycle_next_uuid
|
||||||
|
|
||||||
|
@cycle_next_uuid.setter
|
||||||
|
def cycle_next_uuid(self, new_cycle_next_uuid):
|
||||||
|
self._cycle_next_uuid = new_cycle_next_uuid
|
||||||
|
|
||||||
|
@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
|
@property
|
||||||
def next(self) -> str:
|
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
|
||||||
|
|
||||||
|
@property
|
||||||
|
def button_trigger(self) -> List:
|
||||||
|
return self._button_trigger
|
||||||
|
|
||||||
|
@button_trigger.setter
|
||||||
|
def button_trigger(self, button_trigger):
|
||||||
|
self._button_trigger = button_trigger
|
||||||
|
|
||||||
|
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):
|
def get_parameter_set_by_device(self, device):
|
||||||
return [parameter_set for parameter_set in self.parameter_set.values() if device == parameter_set['target']]
|
return [parameter_set for parameter_set in self.parameter_set.values() if device == parameter_set['target']]
|
||||||
@@ -121,48 +249,64 @@ class Task:
|
|||||||
return '|'.join(name_list) if name_or_value == 'name' else '|'.join(value_list)
|
return '|'.join(name_list) if name_or_value == 'name' else '|'.join(value_list)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self._status = 'running'
|
print(self._name, 'run at', datetime.now())
|
||||||
self._start_time = time()
|
self._status = 1
|
||||||
|
self._start_time.append(time())
|
||||||
def pause(self):
|
|
||||||
self._status = 'pause'
|
|
||||||
|
|
||||||
def set_cycle(self, cycle):
|
|
||||||
self._cycle = cycle
|
|
||||||
|
|
||||||
def set_status(self, status):
|
|
||||||
self._status = status
|
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
self.set_status('running')
|
self.status = 1
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
if self.status == 'running':
|
self.status = 2
|
||||||
self.do_action('stop')
|
|
||||||
self.set_status('idle')
|
|
||||||
|
|
||||||
def done(self):
|
|
||||||
self.set_status('done')
|
|
||||||
|
|
||||||
def end(self):
|
def reset(self):
|
||||||
self.set_status('end')
|
self.status = -1
|
||||||
|
# self.status = 0
|
||||||
|
|
||||||
def get_match_action_list(self, match_condition_list):
|
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)
|
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):
|
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():
|
for instruction in action.get_instruction_list():
|
||||||
self._instruction_list.append(instruction)
|
self._instruction_list.append(instruction)
|
||||||
|
|
||||||
def status_mapping(self, status):
|
def check_condition(self, **kwargs):
|
||||||
statuses = {
|
kwargs['task_start_time'] = self._start_time
|
||||||
"start": self.task_start,
|
return [condition for condition in self._condition_list if condition.match_or_not(**kwargs)]
|
||||||
"done": self.task_done,
|
|
||||||
}
|
def get_task_info(self, action):
|
||||||
return statuses[status]
|
_type = action.type
|
||||||
|
if _type == 'stop':
|
||||||
|
_type = 'interrupt'
|
||||||
|
|
||||||
def check_condition(self, type):
|
return {
|
||||||
return [condition for condition in self._condition_list if condition.match_or_not()]
|
'device': action.target,
|
||||||
|
'parameter': self.get_parameter_set_by_device(action.target),
|
||||||
|
'file_name': self._name,
|
||||||
|
'parent': self.parent,
|
||||||
|
'instruction': _type
|
||||||
|
}
|
||||||
|
|
||||||
|
def as_json(self):
|
||||||
|
return {
|
||||||
|
'id': self.id,
|
||||||
|
'name': self.name,
|
||||||
|
'parent': self.parent,
|
||||||
|
'type': self.type,
|
||||||
|
'uuid': self.uuid,
|
||||||
|
'cycle': self.cycle,
|
||||||
|
'cycle_count': self.cycle_count,
|
||||||
|
'cycle_next': self.cycle_next,
|
||||||
|
'cycle_next_uuid': self.cycle_next_uuid,
|
||||||
|
'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,9 +1,11 @@
|
|||||||
from json import loads as json_parse, dumps as _json_stringify
|
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
|
from xml.dom.expatbuilder import parseString
|
||||||
import paho.mqtt.client as mqtt
|
import paho.mqtt.client as mqtt
|
||||||
from biopro.text import *
|
from biopro.text import *
|
||||||
from .task import Task
|
from .task import Task
|
||||||
|
from biopro.db.collection import Collection
|
||||||
|
|
||||||
_RUNTIME_COMPILE = False
|
_RUNTIME_COMPILE = False
|
||||||
|
|
||||||
@@ -11,46 +13,169 @@ def json_stringify(o: Any) -> str:
|
|||||||
return _json_stringify(o, separators=(',', ':'))
|
return _json_stringify(o, separators=(',', ':'))
|
||||||
|
|
||||||
class TaskManager():
|
class TaskManager():
|
||||||
def __init__(self, task_list):
|
def __init__(self, task_list, cycle_list):
|
||||||
self._current_task = None
|
|
||||||
self._task_list = []
|
self._task_list = []
|
||||||
self._need_to_check_task_list = []
|
self._next_task = []
|
||||||
|
self._prev_task = None
|
||||||
|
self._running_task = None
|
||||||
|
self._cycle_list = cycle_list
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
def get_task_by_index(self, index):
|
||||||
|
return self._task_list[index]
|
||||||
|
|
||||||
|
def get_task_by_uuid(self, uuid):
|
||||||
|
return next((x for x in self.task_list if x.uuid == uuid), None)
|
||||||
|
|
||||||
|
def get_index_by_task(self, task):
|
||||||
|
return next((i for i, x in enumerate(self.task_list) if x.uuid == task.uuid), None)
|
||||||
|
|
||||||
|
def get_index_by_uuid(self, uuid):
|
||||||
|
return next((i for i, x in enumerate(self.task_list) if x.uuid == uuid), None)
|
||||||
|
|
||||||
|
def check_task_is_cycle_start(self, task):
|
||||||
|
for index, cycle in enumerate(self._cycle_list):
|
||||||
|
if cycle['range'][0] == task.uuid:
|
||||||
|
return index
|
||||||
|
|
||||||
|
def check_task_is_cycle_end(self, task):
|
||||||
|
for index, cycle in enumerate(self._cycle_list):
|
||||||
|
if cycle['range'][1] == task.uuid:
|
||||||
|
return index
|
||||||
|
|
||||||
|
def check_task_in_cycle(self, task_index):
|
||||||
|
for index, cycle in enumerate(self._cycle_list):
|
||||||
|
if self.get_index_by_uuid(cycle['range'][0]) <= task_index:
|
||||||
|
if self.get_index_by_uuid(cycle['range'][1]) >= task_index:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
@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:
|
for task in task_list:
|
||||||
task = Task(task)
|
task = Task(task)
|
||||||
self._task_list.append(task)
|
self._task_list.append(task)
|
||||||
|
|
||||||
self.set_current_task(self._task_list[0])
|
|
||||||
self._current_task.run()
|
|
||||||
|
|
||||||
def remove(self, index):
|
# original version
|
||||||
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 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 task
|
||||||
|
self._prev_task = self._running_task
|
||||||
|
# clear next task list
|
||||||
|
self._next_task.clear()
|
||||||
|
# set task to running_task
|
||||||
|
self._running_task = task
|
||||||
|
self._running_task.run()
|
||||||
|
|
||||||
|
# if previous task is still running, then need to close
|
||||||
|
if self._prev_task != None:
|
||||||
|
if self._prev_task.status == 1:
|
||||||
|
self._prev_task.stop()
|
||||||
|
# if reach cycle end, count < max, then go to cycle start
|
||||||
|
cycle_start_index = self.check_task_is_cycle_start(task)
|
||||||
|
cycle_index = self.check_task_is_cycle_end(task)
|
||||||
|
if cycle_index is None:
|
||||||
|
# print('next', self._running_task.name, self._running_task.next)
|
||||||
|
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:
|
||||||
|
_task.reset()
|
||||||
|
self._next_task.append(_task)
|
||||||
|
# print('self._next_task', self._next_task)
|
||||||
|
else:
|
||||||
|
# print('cycle', self._cycle_list[cycle_index])
|
||||||
|
cycle = self._cycle_list[cycle_index]
|
||||||
|
if int(cycle['count']) < int(cycle['max']):
|
||||||
|
self._next_task.append(self.get_task_by_uuid(cycle['range'][0]))
|
||||||
|
# cycle['count'] += 1
|
||||||
|
else:
|
||||||
|
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:
|
||||||
|
_task.reset()
|
||||||
|
self._next_task.append(_task)
|
||||||
|
# cycle['count'] = 1
|
||||||
|
|
||||||
|
if cycle_start_index != None:
|
||||||
|
cycle = self._cycle_list[cycle_start_index]
|
||||||
|
if int(cycle['count']) < int(cycle['max']):
|
||||||
|
cycle['count'] += 1
|
||||||
|
else:
|
||||||
|
cycle['count'] = 1
|
||||||
|
|
||||||
|
except RuntimeError as e:
|
||||||
|
print(e)
|
||||||
|
|
||||||
def get_task(self, task_id):
|
def get_task(self, task_id):
|
||||||
return self._task_list[task_id]
|
return self._task_list[task_id]
|
||||||
|
|
||||||
def get_check_task_list(self):
|
def create_collection(self, parent):
|
||||||
return self._need_to_check_task_list
|
for index, task in enumerate(self._task_list):
|
||||||
|
if self.check_task_in_cycle(index) == True:
|
||||||
def get_current_task(self) -> Task:
|
if task.type == '':
|
||||||
return self._current_task
|
collection = Collection.create_collection(task.name, {"folder": [parent.id]})
|
||||||
|
task.parent = {"folder": [collection.id]}
|
||||||
def get_next_task(self):
|
else:
|
||||||
return self._current_task.next
|
task.parent = {"folder": [parent.id]}
|
||||||
|
|
||||||
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.
+136
-79
@@ -8,6 +8,7 @@ import gc
|
|||||||
|
|
||||||
from biopro.util.json import JSON
|
from biopro.util.json import JSON
|
||||||
from biopro.util.stack import print_exception
|
from biopro.util.stack import print_exception
|
||||||
|
from biopro.util.logger import calculate_time
|
||||||
from .data import RecordingData
|
from .data import RecordingData
|
||||||
from .loader import *
|
from .loader import *
|
||||||
|
|
||||||
@@ -19,6 +20,8 @@ from statistics import mean
|
|||||||
import random
|
import random
|
||||||
# from numba import jit
|
# from numba import jit
|
||||||
|
|
||||||
|
from copy import copy
|
||||||
|
|
||||||
def json_stringify(o) -> str:
|
def json_stringify(o) -> str:
|
||||||
return _json_stringify(o, separators=(',', ':'))
|
return _json_stringify(o, separators=(',', ':'))
|
||||||
|
|
||||||
@@ -115,7 +118,7 @@ class RecordingMetaFile(JsonSerialize):
|
|||||||
'_dirty', '_last_modify_time', '_file_size_cache',
|
'_dirty', '_last_modify_time', '_file_size_cache',
|
||||||
'_recording_file_ch', '_recording_sub_file', '_size',
|
'_recording_file_ch', '_recording_sub_file', '_size',
|
||||||
'_parameter', '_parent', '_recording_file_name', '_recording_sub_mini', '_recording_mini_ch',
|
'_parameter', '_parent', '_recording_file_name', '_recording_sub_mini', '_recording_mini_ch',
|
||||||
'_raw_serial_number', '_mini_serial_number', '_device_id')
|
'_raw_serial_number', '_mini_serial_number', '_device_id', '_project_id')
|
||||||
|
|
||||||
def __init__(self, filepath: Union[str, Path], data_format: bytes = None, id_db = 0, database = None):
|
def __init__(self, filepath: Union[str, Path], data_format: bytes = None, id_db = 0, database = None):
|
||||||
if isinstance(filepath, str):
|
if isinstance(filepath, str):
|
||||||
@@ -150,6 +153,7 @@ class RecordingMetaFile(JsonSerialize):
|
|||||||
self._parent = ''
|
self._parent = ''
|
||||||
self._recording_file_name = ''
|
self._recording_file_name = ''
|
||||||
self._device_id = -1
|
self._device_id = -1
|
||||||
|
self._project_id = None
|
||||||
|
|
||||||
# recording parameter
|
# recording parameter
|
||||||
self._configuration = None
|
self._configuration = None
|
||||||
@@ -294,6 +298,7 @@ class RecordingMetaFile(JsonSerialize):
|
|||||||
'uuid': str(self._file_uuid),
|
'uuid': str(self._file_uuid),
|
||||||
'data_format': 'rec',
|
'data_format': 'rec',
|
||||||
'device': self._device,
|
'device': self._device,
|
||||||
|
'project': self._project_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(self._parent) > 0:
|
if len(self._parent) > 0:
|
||||||
@@ -370,6 +375,45 @@ class RecordingMetaFile(JsonSerialize):
|
|||||||
self._database.put_queue(['data_meta_write', meta_data, self._device_id, str(self._file_uuid), self._id_db])
|
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])
|
# database.put_queue(['data_meta_write', self, meta_data, _path, self._id_db])
|
||||||
return None
|
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
|
@property
|
||||||
def filename(self) -> str:
|
def filename(self) -> str:
|
||||||
@@ -420,7 +464,7 @@ class RecordingMetaFile(JsonSerialize):
|
|||||||
def parameter(self) -> str:
|
def parameter(self) -> str:
|
||||||
return self._parameter
|
return self._parameter
|
||||||
|
|
||||||
@device.setter
|
@parameter.setter
|
||||||
def parameter(self, parameter):
|
def parameter(self, parameter):
|
||||||
self._parameter = parameter
|
self._parameter = parameter
|
||||||
return None
|
return None
|
||||||
@@ -429,7 +473,7 @@ class RecordingMetaFile(JsonSerialize):
|
|||||||
def parent(self) -> str:
|
def parent(self) -> str:
|
||||||
return self._parent
|
return self._parent
|
||||||
|
|
||||||
@device.setter
|
@parent.setter
|
||||||
def parent(self, parent):
|
def parent(self, parent):
|
||||||
self._parent = parent
|
self._parent = parent
|
||||||
|
|
||||||
@@ -437,7 +481,7 @@ class RecordingMetaFile(JsonSerialize):
|
|||||||
def recording_file_name(self) -> str:
|
def recording_file_name(self) -> str:
|
||||||
return self._recording_file_name
|
return self._recording_file_name
|
||||||
|
|
||||||
@device.setter
|
@recording_file_name.setter
|
||||||
def recording_file_name(self, recording_file_name):
|
def recording_file_name(self, recording_file_name):
|
||||||
self._recording_file_name = recording_file_name
|
self._recording_file_name = recording_file_name
|
||||||
|
|
||||||
@@ -450,6 +494,15 @@ class RecordingMetaFile(JsonSerialize):
|
|||||||
self._configuration = conf
|
self._configuration = conf
|
||||||
self._dirty = True
|
self._dirty = True
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def project_id(self) -> int:
|
||||||
|
return self._project_id
|
||||||
|
|
||||||
|
@project_id.setter
|
||||||
|
def project_id(self, project: int):
|
||||||
|
self._project_id = project
|
||||||
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def channels(self) -> List[int]:
|
def channels(self) -> List[int]:
|
||||||
@@ -517,11 +570,6 @@ class RecordingMetaFile(JsonSerialize):
|
|||||||
'start_time': str(_start_time),
|
'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
|
return f, raw_data
|
||||||
|
|
||||||
def new_recording_mini(self, _channel: int, _start_time, scale, database = None) -> 'RecordingMini':
|
def new_recording_mini(self, _channel: int, _start_time, scale, database = None) -> 'RecordingMini':
|
||||||
@@ -567,9 +615,6 @@ class RecordingMetaFile(JsonSerialize):
|
|||||||
'start_time': str(_start_time),
|
'start_time': str(_start_time),
|
||||||
}
|
}
|
||||||
|
|
||||||
# if database is not None:
|
|
||||||
# database.data_mini_create(self, f, mini_data, _channel, scale)
|
|
||||||
|
|
||||||
return f, mini_data
|
return f, mini_data
|
||||||
|
|
||||||
def clear_recording_file(self):
|
def clear_recording_file(self):
|
||||||
@@ -628,15 +673,6 @@ class RecordingMetaFile(JsonSerialize):
|
|||||||
'device': self._device,
|
'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
|
return ret
|
||||||
|
|
||||||
|
|
||||||
@@ -792,14 +828,10 @@ class RecordingFile:
|
|||||||
'end_time': str(_end_time),
|
'end_time': str(_end_time),
|
||||||
'size': str(self._size)
|
'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:
|
if self._meta_file._id_db != 0:
|
||||||
_data['parent'] = self._meta_file._id_db
|
_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._database.put_queue(['data_raw_update', self._id_db, self._channel, _data])
|
|
||||||
self._status = False
|
self._status = False
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -834,11 +866,13 @@ class RecordingFile:
|
|||||||
|
|
||||||
# def write(self, content: Union[bytes, RecordingData]) -> int:
|
# def write(self, content: Union[bytes, RecordingData]) -> int:
|
||||||
def write(self, content: str, channels: list) -> int:
|
def write(self, content: str, channels: list) -> int:
|
||||||
if not isinstance(content, str):
|
# print('count_size', content, channels)
|
||||||
raise RuntimeError('wrong data format : ' + repr(self._data_format))
|
# if not isinstance(content, str):
|
||||||
|
# raise RuntimeError('wrong data format : ' + repr(self._data_format))
|
||||||
|
|
||||||
self._meta_file.update_channels(channels)
|
self._meta_file.update_channels(channels)
|
||||||
sz = sys.getsizeof(content)
|
sz = sys.getsizeof(content)
|
||||||
|
# print('sz', sz)
|
||||||
self._size += sz
|
self._size += sz
|
||||||
return sz
|
return sz
|
||||||
|
|
||||||
@@ -965,10 +999,7 @@ class RecordingMini:
|
|||||||
'end_time': str(_end_time),
|
'end_time': str(_end_time),
|
||||||
'size': str(self._size)
|
'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:
|
if self._meta_file._id_db != 0:
|
||||||
_data['parent'] = self._meta_file._id_db
|
_data['parent'] = self._meta_file._id_db
|
||||||
self._database.put_queue(['data_mini_update', self._id_db, self._channel, _data])
|
self._database.put_queue(['data_mini_update', self._id_db, self._channel, _data])
|
||||||
@@ -996,7 +1027,8 @@ class RecordingFileWriter:
|
|||||||
'_data_value_ch', '_close', '_data_mini_ch',
|
'_data_value_ch', '_close', '_data_mini_ch',
|
||||||
'_mini_scale_list', '_time_real_time', '_data_rl', '_data_db',
|
'_mini_scale_list', '_time_real_time', '_data_rl', '_data_db',
|
||||||
'_raw_save', '_mini_save', '_data_time_ch', '_data_value_ch_for_rl',
|
'_raw_save', '_mini_save', '_data_time_ch', '_data_value_ch_for_rl',
|
||||||
'_data_time_ch_for_rl', '_device_id', '_send_data', '_data_mqtt_ch')
|
'_data_time_ch_for_rl', '_device_id', '_send_data', '_data_mqtt_ch', '_id_db_save', '_raw_create_not_done',
|
||||||
|
'_mini_create_not_done')
|
||||||
|
|
||||||
def __init__(self, meta: RecordingMetaFile, device_id, database = None):
|
def __init__(self, meta: RecordingMetaFile, device_id, database = None):
|
||||||
self._meta = meta
|
self._meta = meta
|
||||||
@@ -1017,7 +1049,9 @@ class RecordingFileWriter:
|
|||||||
|
|
||||||
self._raw_save = {
|
self._raw_save = {
|
||||||
'id': {},
|
'id': {},
|
||||||
'data': {}
|
'data': {},
|
||||||
|
'end_time': {},
|
||||||
|
'size': {}
|
||||||
}
|
}
|
||||||
self._mini_save = {
|
self._mini_save = {
|
||||||
'10': {
|
'10': {
|
||||||
@@ -1052,6 +1086,7 @@ class RecordingFileWriter:
|
|||||||
self._data_value_ch_for_rl = {}
|
self._data_value_ch_for_rl = {}
|
||||||
self._data_time_ch_for_rl = {}
|
self._data_time_ch_for_rl = {}
|
||||||
self._data_time_ch = {}
|
self._data_time_ch = {}
|
||||||
|
self._id_db_save = {}
|
||||||
|
|
||||||
# mini data
|
# mini data
|
||||||
self._data_mini_ch = {}
|
self._data_mini_ch = {}
|
||||||
@@ -1068,12 +1103,15 @@ class RecordingFileWriter:
|
|||||||
|
|
||||||
# splitting
|
# splitting
|
||||||
self.splitting_threshold_time = 30 * 60 * 1000 # one minute
|
self.splitting_threshold_time = 30 * 60 * 1000 # one minute
|
||||||
self.splitting_threshold_size = 16 * 16 * 1024 # 16 * 16KB
|
self.splitting_threshold_size = 16 * 1024 # 16 * 16KB
|
||||||
|
|
||||||
self._writer_batch_size = 8192
|
self._writer_batch_size = 8192
|
||||||
|
|
||||||
self._splitting_size = None
|
self._splitting_size = None
|
||||||
|
|
||||||
|
self._raw_create_not_done = True
|
||||||
|
self._mini_create_not_done = True
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def meta_file(self) -> RecordingMetaFile:
|
def meta_file(self) -> RecordingMetaFile:
|
||||||
@@ -1106,24 +1144,27 @@ class RecordingFileWriter:
|
|||||||
self._splitting_size = 0
|
self._splitting_size = 0
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def close(self):
|
def close(self, mqtt_thread):
|
||||||
# if self._recording_file is not None:
|
|
||||||
# self._recording_file.close()
|
|
||||||
# self._recording_file = None
|
|
||||||
print('close1')
|
|
||||||
self._close = True
|
self._close = True
|
||||||
if len(self._recording_file_dict) > 0:
|
if len(self._recording_file_dict) > 0:
|
||||||
for ch in self._data_db.keys():
|
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:
|
if self._recording_file_dict[ch]._status:
|
||||||
_data = ' '.join(self._data_db[ch])
|
_data = self._data_db[ch]
|
||||||
self._raw_save['data'][ch] = _data
|
self._raw_save['data'][ch] = copy(_data)
|
||||||
self._raw_save['id'][ch] = self._recording_file_dict[ch]._id_db
|
self._raw_save['id'][ch] = self._recording_file_dict[ch]._id_db
|
||||||
self._recording_file_dict[ch].write(_data, self._channel_list)
|
self._recording_file_dict[ch].write(_data, self._channel_list)
|
||||||
self._recording_file_dict[ch].close(self._time_now)
|
self._recording_file_dict[ch].close(self._time_now)
|
||||||
self._meta._size += self._recording_file_dict[ch]._size
|
self._meta._size += self._recording_file_dict[ch]._size
|
||||||
# self._data_db.clear()
|
# self._data_db.clear()
|
||||||
if self._database is not None:
|
if self._database is not None:
|
||||||
self._database.put_queue(['data_raw_recording', self._raw_save['id'], self._channel_list, self._raw_save['data']])
|
self._database.put_queue(['data_raw_recording_bytea', self._raw_save['id'], self._channel_list, self._raw_save['data'], self._id_db_save])
|
||||||
# self._database.put_queue(['data_raw_recording', self._raw_save['id'], self._channel_list, self._raw_save['data']])
|
# self._database.put_queue(['data_raw_recording', self._raw_save['id'], self._channel_list, self._raw_save['data']])
|
||||||
self._recording_file_dict.clear()
|
self._recording_file_dict.clear()
|
||||||
for scale in self._mini_scale_list:
|
for scale in self._mini_scale_list:
|
||||||
@@ -1285,11 +1326,12 @@ class RecordingFileWriter:
|
|||||||
# self._data_mini_ch[c]['10000']['random'].append( str(self._data_mini_ch[c]['1000']['random'][random.randint(-10,-1)]) )
|
# self._data_mini_ch[c]['10000']['random'].append( str(self._data_mini_ch[c]['1000']['random'][random.randint(-10,-1)]) )
|
||||||
# self._data_mini_ch[c]['1000']['dec'] = int(len(self._data_mini_ch[c]['1000']['mean']) / 10)
|
# self._data_mini_ch[c]['1000']['dec'] = int(len(self._data_mini_ch[c]['1000']['mean']) / 10)
|
||||||
# add normal data
|
# add normal data
|
||||||
self._data_db[c].append(str(int(t)))
|
self._data_db[c].append(int(t))
|
||||||
self._data_db[c].append(str(v))
|
self._data_db[c].append(v)
|
||||||
self._time_now = int(t)
|
self._time_now = int(t)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# @calculate_time(1)
|
||||||
def write(self, data: Union[bytes, RecordingData, List[bytes], List[RecordingData]], mqtt_thread) -> int:
|
def write(self, data: Union[bytes, RecordingData, List[bytes], List[RecordingData]], mqtt_thread) -> int:
|
||||||
# check size
|
# check size
|
||||||
ths = self.splitting_threshold_size
|
ths = self.splitting_threshold_size
|
||||||
@@ -1348,42 +1390,54 @@ class RecordingFileWriter:
|
|||||||
|
|
||||||
self.get_data_iter(d, mqtt_thread)
|
self.get_data_iter(d, mqtt_thread)
|
||||||
|
|
||||||
data_save = False
|
|
||||||
mini_save = False
|
|
||||||
if len(self._recording_file_dict) > 0:
|
if len(self._recording_file_dict) > 0:
|
||||||
for ch in self._data_db.keys():
|
for ch in self._data_db.keys():
|
||||||
if self._time_now - self._time_real_time[ch] > 1000000:
|
if self._time_now - self._time_real_time[ch] > 1000000:
|
||||||
self._send_data[ch] = True
|
self._send_data[ch] = True
|
||||||
self._time_real_time[ch] = self._time_now
|
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))
|
for ch in self._recording_file_dict:
|
||||||
# mes = ' '.join(self._data_rl[ch])
|
if self._recording_file_dict[ch]._id_db == 0:
|
||||||
# # print(mes)
|
return None
|
||||||
# # if mqtt_thread is not None:
|
|
||||||
# # mqtt_thread.publish('data_server/device_data_stream/' + str(self._device_id) + '/' + str(ch), mes)
|
for ch in self._data_db.keys():
|
||||||
# # mqtt_queue.put([self._device_id, ch, mes])
|
for scale in self._mini_scale_list:
|
||||||
# mqtt_thread[ch].on_message(mes)
|
if self._recording_mini_dict[str(scale)][ch]._id_db == 0:
|
||||||
# self._data_rl[ch].clear()
|
return None
|
||||||
# # self._time_real_time[ch] = self._time_now
|
|
||||||
|
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._time_now - self._time[ch] > 5000000:
|
||||||
if self._recording_file_dict[ch]._status:
|
if self._recording_file_dict[ch]._status:
|
||||||
_data = ' '.join(self._data_db[ch])
|
_data = self._data_db[ch]
|
||||||
write_sz = self._recording_file_dict[ch].write(_data, self._channel_list)
|
write_sz = self._recording_file_dict[ch].write(_data, self._channel_list)
|
||||||
sz = sz + write_sz
|
self._raw_save['data'][ch] = copy(_data)
|
||||||
self._raw_save['data'][ch] = _data
|
|
||||||
self._raw_save['id'][ch] = self._recording_file_dict[ch]._id_db
|
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._data_db[ch].clear()
|
||||||
self._time[ch] = self._time_now
|
self._time[ch] = self._time_now
|
||||||
self._splitting_size += sz
|
|
||||||
self._meta._last_time = self._time_now
|
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:
|
if len(self._data_mini_ch[ch]['1000']['mean']) >= 10:
|
||||||
mini_save = True
|
mini_save = True
|
||||||
for scale in self._mini_scale_list:
|
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)]['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)]['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_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._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])
|
self._recording_mini_dict[str(scale)][ch].write(self._mini_save[str(scale)]['data_mean'][ch])
|
||||||
@@ -1394,26 +1448,31 @@ class RecordingFileWriter:
|
|||||||
|
|
||||||
if data_save is True:
|
if data_save is True:
|
||||||
if self._database is not None:
|
if self._database is not None:
|
||||||
self._database.put_queue(['data_raw_recording', self._raw_save['id'], self._channel_list, self._raw_save['data']])
|
recording_input = ['data_raw_recording_bytea', 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._meta.update_subfile(database = self._database)
|
self._database.put_queue(recording_input)
|
||||||
|
self._meta.update_subfile_time_size(database = self._database)
|
||||||
|
|
||||||
|
# if data_save is True:
|
||||||
|
# if self._database is not None:
|
||||||
|
# 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)
|
||||||
|
|
||||||
if mini_save is True:
|
if mini_save is True:
|
||||||
if self._database is not None:
|
if self._database is not None:
|
||||||
for scale in self._mini_scale_list:
|
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._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(database = self._database)
|
self._meta.update_subfile_time_size(database = self._database)
|
||||||
|
|
||||||
|
|
||||||
del data
|
del data
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def _switch_recording_file(self):
|
def _switch_recording_file(self):
|
||||||
# if self._recording_file is not None:
|
self._raw_create_not_done = True
|
||||||
# self._recording_file.close()
|
|
||||||
|
|
||||||
if len(self._recording_file_dict) > 0:
|
if len(self._recording_file_dict) > 0:
|
||||||
for ch in self._recording_file_dict.keys():
|
for ch in self._recording_file_dict.keys():
|
||||||
|
self._id_db_save[ch] = self._recording_file_dict[ch]._id_db
|
||||||
self._recording_file_dict[ch].close(self._time_now)
|
self._recording_file_dict[ch].close(self._time_now)
|
||||||
self._meta._size += self._recording_file_dict[ch]._size
|
self._meta._size += self._recording_file_dict[ch]._size
|
||||||
|
|
||||||
@@ -1429,16 +1488,16 @@ class RecordingFileWriter:
|
|||||||
|
|
||||||
if self._database is not None:
|
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', 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._last_time = self._time_now
|
||||||
self._meta.update_subfile(database = self._database)
|
# self._meta.update_subfile(database = self._database)
|
||||||
|
|
||||||
self._splitting_size = 0
|
self._splitting_size = 0
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _switch_recording_mini(self, scale):
|
def _switch_recording_mini(self, scale):
|
||||||
|
self._mini_create_not_done = True
|
||||||
|
|
||||||
if len(self._recording_mini_dict[str(scale)]) > 0:
|
if len(self._recording_mini_dict[str(scale)]) > 0:
|
||||||
for ch in self._recording_mini_dict[str(scale)].keys():
|
for ch in self._recording_mini_dict[str(scale)].keys():
|
||||||
@@ -1456,14 +1515,12 @@ class RecordingFileWriter:
|
|||||||
|
|
||||||
if self._database is not None:
|
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', 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._last_time = self._time_now
|
||||||
self._meta.update_subfile(database = self._database)
|
# self._meta.update_subfile(database = self._database)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def update_meta_id(self, _id):
|
def update_meta_id(self, _id):
|
||||||
# print('update meta')
|
|
||||||
self._meta._id_db = _id
|
self._meta._id_db = _id
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user