forked from M-Labs/kirdy
Compare commits
364 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| da0d0ac2a8 | |||
| 6128f1e941 | |||
| 55adf3ab13 | |||
| 19e6ade824 | |||
| d72547a83e | |||
| a4526c9158 | |||
| 06d1a7f438 | |||
| 4ce9d87305 | |||
| ef873bd829 | |||
| 38ddd5ac94 | |||
| e35292e80d | |||
| 9563e91037 | |||
| 677ff1a29d | |||
| e6597e4c2e | |||
| c23db4467f | |||
| b9f16d4581 | |||
| 0db7775cbe | |||
| cb8b824e34 | |||
| 6367826223 | |||
| 481f5f56db | |||
| f1089e9736 | |||
| 3125e7cff0 | |||
| 10f79615e8 | |||
| 8f272023bb | |||
| 0a0274b183 | |||
| b536a22234 | |||
| f1fa89caa5 | |||
| 458e593c25 | |||
| 12697dedc1 | |||
| 49fed878dc | |||
| 044219f78f | |||
| e5cc5c4cb9 | |||
| 041b5ea159 | |||
| e9ceb41613 | |||
| 54e3e85815 | |||
| 5344cac0d6 | |||
| 15288dcefc | |||
| e1661ab023 | |||
| ac6f620d52 | |||
| 71be1093d6 | |||
| 7a43ece873 | |||
| 086fe70122 | |||
| 8fb94e68f9 | |||
| 7c447ed7c0 | |||
| 980f7364ac | |||
| 62ff2cb048 | |||
| 749f19b105 | |||
| bd83a8fc92 | |||
| c1855f6a08 | |||
| 46889ac330 | |||
| 6f273e85cc | |||
| fb6fd47c69 | |||
| 09827b4d44 | |||
| 5909ead681 | |||
| d8ddd5fb24 | |||
| 6db375d6b8 | |||
| 7267794e49 | |||
| 3affe47293 | |||
| 7bdb7e48df | |||
| b3a9f61648 | |||
| e1ee3ec959 | |||
| 7f9dc37c10 | |||
| 9bec46490d | |||
| 0e707e3d6b | |||
| c2806aee27 | |||
| 1b7f5bc3e4 | |||
| 227d9d4877 | |||
| 6ad41c8502 | |||
| 2a6db53dc8 | |||
| 7dd551201e | |||
| 753a16ab8e | |||
| 76a19cb65a | |||
| cd3347798c | |||
| 85f81ee8e4 | |||
| 5b00bd60c7 | |||
| 4d8e16771e | |||
| 4d332328c0 | |||
| edb8099a26 | |||
| 49dc8a9b96 | |||
| a1b7538295 | |||
| 8f5a294a53 | |||
| 87b0e1bf67 | |||
| 35f66c3516 | |||
| dd7e1bbbdd | |||
| a3b38fc6b7 | |||
| 388e6725ef | |||
| f4c761c5ca | |||
| e560d8f1eb | |||
| 0437c6e76e | |||
| bad21806f8 | |||
| cb2bc505c9 | |||
| 4f19d2c2be | |||
| e8d3858fc9 | |||
| 9bec56ed6c | |||
| 51b82e0447 | |||
| 31e108a4b5 | |||
| 253f4410ee | |||
| bd72c382b0 | |||
| a512614de5 | |||
| 76f7875e3a | |||
| 0d64d62fb0 | |||
| 0aeffdbf7b | |||
| 89a1270c02 | |||
| c2e78e6f17 | |||
| 86e6d3764e | |||
| 1111967a7b | |||
| 1896e2534b | |||
| 6d4b1b0574 | |||
| 0b5fda2cd9 | |||
| b763350a8b | |||
| 838592c812 | |||
| e632cbbfdd | |||
| 27bf573010 | |||
| c267c30b89 | |||
| c5826876a6 | |||
| 6782cda790 | |||
| 2fe2ef531b | |||
| f2ad06ecae | |||
| 5166bb7ba8 | |||
| 9c611fc861 | |||
| 51913f2e2f | |||
| c86d67b15c | |||
| 3d2294a90c | |||
| 3ba8b99084 | |||
| af73ac8127 | |||
| c214e4182d | |||
| fb69ae3306 | |||
| 8c8ed12522 | |||
| 572e2dbc5d | |||
| 82c46e04d0 | |||
| 28f8c3c497 | |||
| 47bf166ecb | |||
| 1dcac25574 | |||
| 3f9a4bf140 | |||
| 201148fb21 | |||
| a90031dd6c | |||
| 7b52072617 | |||
| c241d34434 | |||
| 20c3d42dd7 | |||
| aae89256c3 | |||
| 3344e7ab19 | |||
| a76b8de994 | |||
| 3410a271fd | |||
| 8f38acd0f2 | |||
| b95b9dcefa | |||
| 5e6a4c0646 | |||
| ec5bf1d6b6 | |||
| 3737c2ed59 | |||
| 4cd328d98c | |||
| af95de0f16 | |||
| db2f76771a | |||
| 6f87cba9a6 | |||
| 80d94270a2 | |||
| 456691f79f | |||
| 0f3db7fec5 | |||
| 9002ca6992 | |||
| 92f6b83b16 | |||
| da50f372d9 | |||
| 57bfd6d83c | |||
| dacf9f0fa5 | |||
| bfd8c0e43a | |||
| dc97f42bd0 | |||
| 3813b79623 | |||
| 83a764889c | |||
| c09da0db98 | |||
| d5a620c76b | |||
| d1660c6090 | |||
| f35546b070 | |||
| 0dceb8c3c6 | |||
| 266110ba14 | |||
| e8aaf5f66b | |||
| 70fed23c51 | |||
| b8241d1f27 | |||
| ded7dd7694 | |||
| 7fa4330797 | |||
| 7be35fe7f0 | |||
| c5efc6ca57 | |||
| b330f45260 | |||
| 554f292cab | |||
| f303ab639a | |||
| ba30575406 | |||
| bfdb1f5066 | |||
| 5b35f32a42 | |||
| 2df22d5dcb | |||
| b73eacd234 | |||
| 4a06a7579f | |||
| 9524601cb6 | |||
| 4116962175 | |||
| 0e087c6992 | |||
| 6b250aa1fd | |||
| de80aedafc | |||
| 31a97bdeb4 | |||
| 784b8a357b | |||
| ceb003e07e | |||
| 10873f4791 | |||
| e160316bfc | |||
| 0a992c1dc8 | |||
| ae74455f94 | |||
| 6bccbceb81 | |||
| eaebdb390d | |||
| 489333c43d | |||
| 4288d465c9 | |||
| 09863353cd | |||
| 6d107d55cf | |||
| d435dc06d8 | |||
| 898358f4e6 | |||
| a13c6fa86c | |||
| b1a1173075 | |||
| af68b0e90a | |||
| f8abfd4300 | |||
| 7d41edef20 | |||
| 607da8a822 | |||
| 7f06fc06fd | |||
| 67f9e65df8 | |||
| 7d2e14ef2f | |||
| e525a3f354 | |||
| 8431e9f43d | |||
| e9d5f4598a | |||
| 1867935047 | |||
| 99cf17f7e4 | |||
| 048245f674 | |||
| 0a01d299bc | |||
| dbbd438e92 | |||
| 3ad7c417f6 | |||
| c06491a8b2 | |||
| 0380c8d30b | |||
| ed5cda6364 | |||
| 61624b0bd6 | |||
| 1480305c16 | |||
| 74c465d16f | |||
| 574abc2c2f | |||
| a9dbff8250 | |||
| 8cd3f70721 | |||
| b7231f48ff | |||
| 7f6a385e1d | |||
| eff8adc184 | |||
| a579e5c5d5 | |||
| 65b757ac3c | |||
| 911d9a7bc9 | |||
| 111d9a4226 | |||
| a3885c365e | |||
| a58b0954ec | |||
| 92c6cf12d4 | |||
| ef2410f441 | |||
| adfa4f5fa3 | |||
| df939eb9a3 | |||
| 3aca712e1d | |||
| 4526536a48 | |||
| f488786e1c | |||
| 3528d8a68f | |||
| 46393bacdb | |||
| 6fc800e562 | |||
| 76477065be | |||
| b1fa0e51c8 | |||
| 9f82fa58f4 | |||
| 19341672a9 | |||
| 86a9fb039e | |||
| a2bb390ae2 | |||
| 18dd0a7963 | |||
| d1cc677668 | |||
| c09ccc29cd | |||
| c4135f6ac3 | |||
| 6ee45b4814 | |||
| a8787430b1 | |||
| ed785b7c85 | |||
| 30ab228b4b | |||
| 88cca12a60 | |||
| 8139ebdc1b | |||
| 5f83b73011 | |||
| 0642640da7 | |||
| 6dd1bf9301 | |||
| d2efc02b6a | |||
| 89d415194d | |||
| 09b3765877 | |||
| 7a76325288 | |||
| ffa5f4e8ff | |||
| e9a396f001 | |||
| 412f5ec58b | |||
| e29898f8f8 | |||
| 60a79d1780 | |||
| b0edd3dba2 | |||
| 4c331dd319 | |||
| 6b05b2d851 | |||
| f22ab430b8 | |||
| 4cd650367d | |||
| de262b849d | |||
| 4132bfacd3 | |||
| 6096711d2c | |||
| 3d3d6f5cb5 | |||
| 172c3e1dfc | |||
| ee0ed8ebe7 | |||
| 771f2813f7 | |||
| 4e0d14def2 | |||
| f6677d874c | |||
| d391e3a1fb | |||
| edd30e94a0 | |||
| ad731c2f15 | |||
| 9d8a553669 | |||
| e22f424531 | |||
| 6af0f992d5 | |||
| f50505feaf | |||
| 9ae867cd88 | |||
| 85b50bf824 | |||
| 07ea733b34 | |||
| 5bea3f0e5f | |||
| af283b17ac | |||
| c3022e9db1 | |||
| c02181c80c | |||
| 095fe8ea69 | |||
| a0b67cdb09 | |||
| 381f25f036 | |||
| c768bdc93a | |||
| 0d12c902fc | |||
| 3cfdee917a | |||
| 5f582be143 | |||
| 2f7ca2a706 | |||
| ff3d9b790a | |||
| bc7bf9a6e7 | |||
| ca110962f7 | |||
| d0f226ce03 | |||
| f49fd08c69 | |||
| ccaf728c75 | |||
| 3ac287ace2 | |||
| cdf900a5b6 | |||
| af8d361b95 | |||
| e355e83d28 | |||
| 285fc9b5d6 | |||
| 8c612fc0c9 | |||
| 42cd55645c | |||
| d190b8b192 | |||
| 74325a3cee | |||
| 709eae8566 | |||
| d3e3451d37 | |||
| 33ff0c3678 | |||
| 33d9cb45c4 | |||
| 8ae27725c6 | |||
| 20fc6d6fac | |||
| 654964831a | |||
| 27c7b5929e | |||
| e48f1979f0 | |||
| 59f2385ecf | |||
| d4e074cbd4 | |||
| 277796d2a4 | |||
| be8bf0a8b6 | |||
| b1123047c7 | |||
| 707fac0775 | |||
| a99dde8b38 | |||
| d1f7a20c15 | |||
| 58a8b15c40 | |||
| 590ba8171c | |||
| 0807f66b3c | |||
| 2953d4edde | |||
| f2c026ffdd | |||
| c7d36bc8d5 | |||
| 784fc03957 | |||
| 6cc2bc32c5 | |||
| 23ee568ea7 | |||
| d3f3608136 | |||
| 4cf7b7fdf9 | |||
| 0179e7641a | |||
| f6767b147b | |||
| 475fe28604 | |||
| 764a203dd8 | |||
| f2b419f8d0 |
@@ -1,12 +0,0 @@
|
||||
[target.thumbv7em-none-eabihf]
|
||||
runner = "gdb -q -x openocd.gdb"
|
||||
rustflags = [
|
||||
"-C", "link-arg=-Tlink.x",
|
||||
]
|
||||
|
||||
[build]
|
||||
# Pick ONE of these compilation targets
|
||||
# target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+
|
||||
# target = "thumbv7m-none-eabi" # Cortex-M3
|
||||
# target = "thumbv7em-none-eabi" # Cortex-M4 and Cortex-M7 (no FPU)
|
||||
target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
|
||||
8
.cargo/config.toml
Normal file
8
.cargo/config.toml
Normal file
@@ -0,0 +1,8 @@
|
||||
[target.thumbv7em-none-eabihf]
|
||||
runner = "gdb -q -x openocd.gdb"
|
||||
rustflags = [
|
||||
"-C", "link-arg=-Tlink.x",
|
||||
]
|
||||
|
||||
[build]
|
||||
target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,4 +1,7 @@
|
||||
target/
|
||||
result
|
||||
|
||||
*.pyc
|
||||
*.jdebug*
|
||||
.venv/
|
||||
env
|
||||
pykirdy.egg-info/
|
||||
60
BSD.md
Normal file
60
BSD.md
Normal file
@@ -0,0 +1,60 @@
|
||||
# Building Rust embedded firmware on BSD
|
||||
|
||||
Using the Rust stable compiler from the BSD ports is mostly a matter of removing the arbitrary limitations that have been built into the Rust toolchain.
|
||||
|
||||
Get rid of the "nightly toolchain" check in cargo-xbuild:
|
||||
```
|
||||
diff --git a/src/lib.rs b/src/lib.rs
|
||||
index 204ad8f..9c61e39 100644
|
||||
--- a/src/lib.rs
|
||||
+++ b/src/lib.rs
|
||||
@@ -157,28 +157,11 @@ pub fn build(args: Args, command_name: &str, crate_config: Option<Config>) -> Re
|
||||
})
|
||||
})?;
|
||||
|
||||
- // We can't build sysroot with stable or beta due to unstable features
|
||||
let sysroot = rustc::sysroot(verbose)?;
|
||||
- let src = match meta.channel {
|
||||
- Channel::Dev => rustc::Src::from_env().ok_or(anyhow!(
|
||||
+ let src = rustc::Src::from_env().ok_or(anyhow!(
|
||||
"The XARGO_RUST_SRC env variable must be set and point to the \
|
||||
- Rust source directory when working with the 'dev' channel",
|
||||
- ))?,
|
||||
- Channel::Nightly => {
|
||||
- if let Some(src) = rustc::Src::from_env() {
|
||||
- src
|
||||
- } else {
|
||||
- sysroot.src()?
|
||||
- }
|
||||
- }
|
||||
- Channel::Stable | Channel::Beta => {
|
||||
- bail!(
|
||||
- "The sysroot can't be built for the {:?} channel. \
|
||||
- Switch to nightly.",
|
||||
- meta.channel
|
||||
- );
|
||||
- }
|
||||
- };
|
||||
+ Rust source directory",
|
||||
+ ))?;
|
||||
|
||||
let cmode = if let Some(triple) = args.target() {
|
||||
if triple == meta.host {
|
||||
```
|
||||
|
||||
Run ``cargo install --path .`` to install the modified cargo-xbuild
|
||||
|
||||
Get a copy of the Rust sources that corresponds to the installed compiler binary, and set up the environment accordingly:
|
||||
```
|
||||
> rustc --version
|
||||
rustc 1.72.1 (d5c2e9c34 2023-09-13) (built from a source tarball)
|
||||
> git clone --depth=1 --recurse-submodules --shallow-submodules https://github.com/rust-lang/rust --branch 1.72.1
|
||||
> export XARGO_RUST_SRC=`pwd`/rust/library
|
||||
```
|
||||
|
||||
Disable other arbitrary checks in the Rust compiler:
|
||||
```
|
||||
> export RUSTC_BOOTSTRAP=1
|
||||
```
|
||||
|
||||
And you can now simply run ``cargo xbuild`` to build the firmware.
|
||||
799
Cargo.lock
generated
799
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
25
Cargo.toml
25
Cargo.toml
@@ -15,23 +15,30 @@ default-target = "thumbv7em-none-eabihf"
|
||||
|
||||
[dependencies]
|
||||
panic-halt = "0.2.0"
|
||||
cortex-m = "0.7.6"
|
||||
cortex-m-rt = { version = "0.7.1", features = ["device"] }
|
||||
cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] }
|
||||
cortex-m-rt = { version = "0.7.3", features = ["device"] }
|
||||
cortex-m-semihosting = "0.5.0"
|
||||
log = "0.4.17"
|
||||
bare-metal = "1"
|
||||
nb = "1"
|
||||
cortex-m-log = { version = "0.7.0", features = ["log-integration", "semihosting"] }
|
||||
stm32f4xx-hal = { version = "0.13.2", features = ["rt", "stm32f407", "usb_fs"] }
|
||||
stm32-eth = { version = "0.3.0", features = ["stm32f407"] }
|
||||
smoltcp = { version = "0.8.0", default-features = false, features = ["proto-ipv4", "socket-tcp", "log", "medium-ethernet"] }
|
||||
stm32f4xx-hal = { version = "0.20.0", features = ["stm32f407", "otg-fs", "usb_fs"] }
|
||||
stm32-eth = { version = "0.6.0", features = ["stm32f407", "smoltcp-phy", "smoltcp"] }
|
||||
ieee802_3_miim = "0.8.0"
|
||||
smoltcp = { version = "0.11.0", default-features = false, features = ["proto-ipv4", "socket-tcp", "medium-ethernet", "iface-neighbor-cache-count-16"] }
|
||||
uom = { version = "0.30", default-features = false, features = ["autoconvert", "si", "f32", "use_serde"] }
|
||||
num-traits = { version = "0.2.15", default-features = false, features = ["libm"] }
|
||||
usb-device = "0.2.9"
|
||||
usbd-serial = "0.1.1"
|
||||
usb-device = "0.3.2"
|
||||
usbd-serial = "0.2.1"
|
||||
fugit = "0.3.6"
|
||||
rtt-target = { version = "0.3.1", features = ["cortex-m"] }
|
||||
|
||||
|
||||
miniconf = "0.9.0"
|
||||
serde = { version = "1.0.158", features = ["derive"], default-features = false }
|
||||
sfkv = "0.1"
|
||||
bit_field = "0.10"
|
||||
crc = "3.0.1"
|
||||
byteorder = { version = "1", default-features = false }
|
||||
const_format = "0.2.34"
|
||||
[features]
|
||||
semihosting = ["cortex-m-log/semihosting"]
|
||||
RTT = []
|
||||
|
||||
79
README.md
Normal file
79
README.md
Normal file
@@ -0,0 +1,79 @@
|
||||
# Testing Firmware for the Sinara 1550 Kirdy
|
||||
|
||||
- This repo is for testing only. Not intended for production use.
|
||||
|
||||
## Building
|
||||
|
||||
### Reproducible build with Nix
|
||||
|
||||
kirdy firmware is packaged using the [Nix](https://nixos.org) Flakes system. Install Nix 2.4+ and enable flakes by adding ``experimental-features = nix-command flakes`` to ``nix.conf`` (e.g. ``~/.config/nix/nix.conf``).
|
||||
|
||||
Once you have Flakes enabled, you can use ``nix build`` to build the firmware.
|
||||
|
||||
### Development environment
|
||||
|
||||
Clone this repository and with Nix Flakes enabled, use the following commands:
|
||||
|
||||
```shell
|
||||
nix develop
|
||||
cargo build
|
||||
```
|
||||
|
||||
The resulting ELF file will be located under `target/thumbv7em-none-eabihf/release/kirdy`.
|
||||
|
||||
Alternatively, you can install the Rust toolchain without Nix using rustup; see the Rust manifest file pulled in `flake.nix` to determine which Rust version to use.
|
||||
|
||||
For building on FreeBSD or OpenBSD, see BSD.md.
|
||||
|
||||
## Debugging
|
||||
|
||||
Connect SWDIO/SWCLK/RST/GND to a programmer such as ST-Link v2.1. Run OpenOCD:
|
||||
```shell
|
||||
openocd -f interface/stlink.cfg -f target/stm32f4x.cfg
|
||||
```
|
||||
|
||||
You may need to power up the programmer before powering the device.
|
||||
Leave OpenOCD running. Run the GNU debugger:
|
||||
```shell
|
||||
gdb target/thumbv7em-none-eabihf/release/kirdy
|
||||
|
||||
(gdb) source openocd.gdb
|
||||
```
|
||||
|
||||
## Flashing
|
||||
If the firmware to be flashed involves an update on the flash settings, it is required to erase the flash settings before flashing the new firmware to avoid unexpected hardware behavior. There are several options for flashing kirdy. DFU requires only a USB-C cable or RJ45 cable, whereas OpenOCD needs a JTAG/SWD adapter.
|
||||
|
||||
### dfu-util on Linux
|
||||
* Install the DFU USB tool (dfu-util).
|
||||
* Convert firmware from ELF to BIN: `arm-none-eabi-objcopy -O binary kirdy kirdy.bin` (you can skip this step if using the BIN from Hydra)
|
||||
* Put STM32 into DFU Mode. You can either
|
||||
* Connect to the USB Type C cable to kirdy next to the RJ45 Jack. After that, add BOOT0 jumper to kirdy near programming headers and then cycle board power to put it in DFU mode. OR
|
||||
* Plug in RJ45 cable, which connect to a network that is accessible by your computer and send the corresponding dfu json command via TCP Socket to kirdy. Please see the python test script for the command.
|
||||
* Push firmware to flash: `dfu-util -a 0 -s 0x08000000:leave -D kirdy.bin`
|
||||
* If you plugged in the BOOT0 jumper, you will need to
|
||||
1. Remove BOOT0 jumper
|
||||
2. Cycle power to leave DFU update mode
|
||||
* If you plugged in the RJ45 cable, the MCU would start its application code automatically. No power cycle is needed.
|
||||
|
||||
### st.com DfuSe tool on Windows
|
||||
On a Windows machine install [st.com](https://st.com) DfuSe USB device firmware upgrade (DFU) software. [link](https://www.st.com/en/development-tools/stsw-stm32080.html).
|
||||
- add jumper to kirdy across 2-pin jumper adjacent to JTAG connector
|
||||
- cycle board power to put it in DFU update mode
|
||||
- connect USB Type C to PC
|
||||
- use st.com software to upload firmware
|
||||
- remove jumper
|
||||
- cycle power to leave DFU update mode
|
||||
|
||||
### OpenOCD
|
||||
```shell
|
||||
openocd -f interface/stlink.cfg -f target/stm32f4x.cfg -c "program target/thumbv7em-none-eabihf/debug/kirdy verify reset; exit"
|
||||
```
|
||||
|
||||
## Erasing Flash Settings
|
||||
The flash settings are stored in the last flash sector(ID: 11) of bank 0 of stm32f405. You can erase it with JTAG/SWD adapter. You may find it useful if you have set network settings incorrectly.
|
||||
|
||||
With JTAG/SWD adapter connected, issue the following command:
|
||||
|
||||
```shell
|
||||
openocd -f interface/stlink.cfg -f target/stm32f4x.cfg -c "flash init; init; halt; flash erase_sector 0 11 last; reset; exit"
|
||||
```
|
||||
35
build.rs
35
build.rs
@@ -1,7 +1,4 @@
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
use std::{env, fs::File, io::Write, path::PathBuf, process::Command};
|
||||
|
||||
fn main() {
|
||||
// Put the linker script somewhere the linker can find it
|
||||
@@ -15,4 +12,34 @@ fn main() {
|
||||
// Only re-run the build script when memory.x is changed,
|
||||
// instead of when any part of the source code changes.
|
||||
println!("cargo:rerun-if-changed=memory.x");
|
||||
|
||||
let revision = env::var("BUILD_REVISION");
|
||||
match revision {
|
||||
Ok(r) => {
|
||||
// Skip if the environment variable is already set
|
||||
println!("cargo:rustc-env=BUILD_REVISION={}", r);
|
||||
}
|
||||
Err(_) => {
|
||||
let output = Command::new("git")
|
||||
.args(&["rev-parse", "--short=7", "HEAD"])
|
||||
.output()
|
||||
.expect("Failed to execute git command");
|
||||
|
||||
let dirty = !Command::new("git")
|
||||
.args(&["status", "-s"])
|
||||
.output()
|
||||
.expect("Failed to execute git command").stdout.is_empty();
|
||||
|
||||
let build_revision: String;
|
||||
if dirty {
|
||||
build_revision = String::from_utf8(output.stdout)
|
||||
.expect("Invalid UTF-8 sequence") + "-dirty";
|
||||
} else {
|
||||
build_revision = String::from_utf8(output.stdout)
|
||||
.expect("Invalid UTF-8 sequence");
|
||||
}
|
||||
|
||||
println!("cargo:rustc-env=BUILD_REVISION={}", build_revision.trim());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
51
flake.lock
generated
51
flake.lock
generated
@@ -3,11 +3,11 @@
|
||||
"mozilla-overlay": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1664789696,
|
||||
"narHash": "sha256-UGWJHQShiwLCr4/DysMVFrYdYYHcOqAOVsWNUu+l6YU=",
|
||||
"lastModified": 1704373101,
|
||||
"narHash": "sha256-+gi59LRWRQmwROrmE1E2b3mtocwueCQqZ60CwLG+gbg=",
|
||||
"owner": "mozilla",
|
||||
"repo": "nixpkgs-mozilla",
|
||||
"rev": "80627b282705101e7b38e19ca6e8df105031b072",
|
||||
"rev": "9b11a87c0cc54e308fa83aac5b4ee1816d5418a2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -18,16 +18,32 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1666164185,
|
||||
"narHash": "sha256-5v+YB4ijeUfg5LCz9ck4gIpCPhIS+qn02OyPJO48bCE=",
|
||||
"lastModified": 1742669843,
|
||||
"narHash": "sha256-G5n+FOXLXcRx+3hCJ6Rt6ZQyF1zqQ0DL0sWAMn2Nk0w=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "c5203abb1329f7ea084c04acda330ca75d5b9fb5",
|
||||
"rev": "1e5b653dff12029333a6546c11e108ede13052eb",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-22.05",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "1e5b653dff12029333a6546c11e108ede13052eb",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1736320768,
|
||||
"narHash": "sha256-nIYdTAiKIGnFNugbomgBJR+Xv5F1ZQU+HfaBqJKroC0=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "4bc9c909d9ac828a039f288cf872d16d38185db8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
@@ -35,7 +51,26 @@
|
||||
"root": {
|
||||
"inputs": {
|
||||
"mozilla-overlay": "mozilla-overlay",
|
||||
"nixpkgs": "nixpkgs"
|
||||
"nixpkgs": "nixpkgs",
|
||||
"rust-overlay": "rust-overlay"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1741314698,
|
||||
"narHash": "sha256-6Yp0CTwAY/jq/F81Sa8NM0Zi1EwxAdASO6y4A5neGuc=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "4e9af61c1a631886cdc7e13032af4fc9e75bb76b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
82
flake.nix
82
flake.nix
@@ -1,28 +1,18 @@
|
||||
{
|
||||
description = "Firmware for kirdy";
|
||||
|
||||
inputs.nixpkgs.url = github:NixOS/nixpkgs/nixos-22.05;
|
||||
inputs.nixpkgs.url = github:NixOS/nixpkgs/1e5b653dff12029333a6546c11e108ede13052eb;
|
||||
inputs.mozilla-overlay = { url = github:mozilla/nixpkgs-mozilla; flake = false; };
|
||||
inputs.rust-overlay.url = "github:oxalica/rust-overlay";
|
||||
|
||||
outputs = { self, nixpkgs, mozilla-overlay }:
|
||||
outputs = { self, nixpkgs, mozilla-overlay, rust-overlay}:
|
||||
let
|
||||
pkgs = import nixpkgs { system = "x86_64-linux"; overlays = [ (import mozilla-overlay) ]; };
|
||||
rustManifest = pkgs.fetchurl {
|
||||
url = "https://static.rust-lang.org/dist/2022-09-22/channel-rust-stable.toml";
|
||||
sha256 = "f257a7de2f284f025238964ca2c1865c704be4156e1909d6393d92b796005055";
|
||||
pkgs = import nixpkgs { system = "x86_64-linux"; overlays = [ (import mozilla-overlay) (import rust-overlay)]; };
|
||||
rust = pkgs.rust-bin.nightly."2024-03-21".default.override{
|
||||
extensions = [ "rust-src" ];
|
||||
targets = [ "thumbv7em-none-eabihf" ];
|
||||
};
|
||||
|
||||
targets = [
|
||||
"thumbv7em-none-eabihf"
|
||||
];
|
||||
rustChannelOfTargets = _channel: _date: targets:
|
||||
(pkgs.lib.rustLib.fromManifestFile rustManifest {
|
||||
inherit (pkgs) stdenv lib fetchurl patchelf;
|
||||
}).rust.override {
|
||||
inherit targets;
|
||||
extensions = ["rust-src"];
|
||||
};
|
||||
rust = rustChannelOfTargets "stable" null targets;
|
||||
rustPlatform = pkgs.recurseIntoAttrs (pkgs.makeRustPlatform {
|
||||
rustc = rust;
|
||||
cargo = rust;
|
||||
@@ -39,6 +29,7 @@
|
||||
nativeBuildInputs = [ pkgs.llvm ];
|
||||
|
||||
buildPhase = ''
|
||||
export BUILD_REVISION=${toString (self.shortRev or self.dirtyShortRev or "unknown")}
|
||||
cargo build --release --bin kirdy
|
||||
'';
|
||||
|
||||
@@ -51,10 +42,55 @@
|
||||
'';
|
||||
|
||||
dontFixup = true;
|
||||
auditable = false;
|
||||
};
|
||||
|
||||
pglive = pkgs.python3Packages.buildPythonPackage rec {
|
||||
pname = "pglive";
|
||||
version = "0.8.3";
|
||||
format = "pyproject";
|
||||
src = pkgs.fetchPypi {
|
||||
inherit pname version;
|
||||
hash = "sha256-b41ATaYmkt5BtRhhr2qwiwV46a7e2taqJVt93cVSa2k=";
|
||||
};
|
||||
buildInputs = [ pkgs.python3Packages.poetry-core ];
|
||||
propagatedBuildInputs = with pkgs.python3Packages; [ pyqtgraph numpy ];
|
||||
};
|
||||
|
||||
pykirdy = pkgs.python3Packages.buildPythonPackage {
|
||||
pname = "pykirdy";
|
||||
version = "0.0.0";
|
||||
format = "pyproject";
|
||||
src = "${self}/pykirdy";
|
||||
|
||||
nativeBuildInputs = [ pkgs.qt6.wrapQtAppsHook pkgs.python3Packages.setuptools ];
|
||||
propagatedBuildInputs =
|
||||
[ pkgs.qt6.qtbase ]
|
||||
++ (with pkgs.python3Packages; [
|
||||
aenum
|
||||
numpy
|
||||
pyqtgraph
|
||||
pyqt6
|
||||
qasync
|
||||
pglive
|
||||
jsonschema
|
||||
]);
|
||||
|
||||
dontWrapQtApps = true;
|
||||
postFixup = ''
|
||||
wrapQtApp "$out/bin/kirdy_qt"
|
||||
'';
|
||||
};
|
||||
|
||||
in {
|
||||
packages.x86_64-linux = {
|
||||
inherit kirdy;
|
||||
inherit kirdy pykirdy;
|
||||
default = kirdy;
|
||||
};
|
||||
|
||||
apps.x86_64-linux.kirdy_gui = {
|
||||
type = "app";
|
||||
program = "${self.packages.x86_64-linux.pykirdy}/bin/kirdy_qt";
|
||||
};
|
||||
|
||||
hydraJobs = {
|
||||
@@ -64,16 +100,14 @@
|
||||
devShell.x86_64-linux = pkgs.mkShell {
|
||||
name = "kirdy-dev-shell";
|
||||
buildInputs = with pkgs; [
|
||||
rustPlatform.rust.rustc
|
||||
rustPlatform.rust.cargo
|
||||
openocd dfu-util glibc
|
||||
rust openocd dfu-util glibc
|
||||
] ++ (with python3Packages; [
|
||||
numpy matplotlib pyqtgraph
|
||||
numpy matplotlib pyqtgraph setuptools pyqt6 qasync pglive aenum sipyco jsonschema
|
||||
]);
|
||||
shellHook=
|
||||
''
|
||||
export QT_PLUGIN_PATH=${pkgs.qt5.qtbase}/${pkgs.qt5.qtbase.dev.qtPluginPrefix}
|
||||
export QML2_IMPORT_PATH=${pkgs.qt5.qtbase}/${pkgs.qt5.qtbase.dev.qtQmlPrefix}
|
||||
export QT_PLUGIN_PATH=${pkgs.qt6.qtbase}/${pkgs.qt6.qtbase.dev.qtPluginPrefix}
|
||||
export QML2_IMPORT_PATH=${pkgs.qt6.qtbase}/${pkgs.qt6.qtbase.dev.qtQmlPrefix}
|
||||
'';
|
||||
};
|
||||
defaultPackage.x86_64-linux = kirdy;
|
||||
|
||||
6
memory.x
6
memory.x
@@ -2,9 +2,8 @@
|
||||
|
||||
MEMORY
|
||||
{
|
||||
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K
|
||||
/* reserved for config data */
|
||||
CONFIG (rx) : ORIGIN = 0x8100000, LENGTH = 16K
|
||||
/* The last flash sector is reserved for config */
|
||||
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 896K
|
||||
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 112K - 4
|
||||
/* reserved for DFU trigger message */
|
||||
DFU_MSG (wrx) : ORIGIN = 0x2001BFFC, LENGTH = 4
|
||||
@@ -14,6 +13,5 @@ MEMORY
|
||||
}
|
||||
|
||||
_flash_start = ORIGIN(FLASH);
|
||||
_config_start = ORIGIN(CONFIG);
|
||||
_dfu_msg = ORIGIN(DFU_MSG);
|
||||
_stack_start = ORIGIN(CCMRAM) + LENGTH(CCMRAM);
|
||||
|
||||
2
pykirdy/MANIFEST.in
Normal file
2
pykirdy/MANIFEST.in
Normal file
@@ -0,0 +1,2 @@
|
||||
include pykirdy/ui/*
|
||||
include pykirdy/settings.schema.json
|
||||
128
pykirdy/asyncio_example.py
Normal file
128
pykirdy/asyncio_example.py
Normal file
@@ -0,0 +1,128 @@
|
||||
from pprint import pp
|
||||
from pykirdy.aioclient import Kirdy, FilterConfig
|
||||
import signal
|
||||
import time
|
||||
import asyncio
|
||||
|
||||
async def enter_dfu_mode(kirdy: Kirdy):
|
||||
"""
|
||||
Enter Device Firmware Upgrade(Dfu) mode
|
||||
Please refer to README.md for firmware update instructions.
|
||||
"""
|
||||
await kirdy.device.dfu()
|
||||
|
||||
async def device_cfg(kirdy: Kirdy):
|
||||
"""
|
||||
Configure Kirdy's network and board specific transconductance settings.
|
||||
These configs are saved to flash immediately after command is processed.
|
||||
"""
|
||||
# Kirdy rev0_3's gain and transconductance varies between boards to maximize the
|
||||
# PD current range resolution.
|
||||
await kirdy.device.set_pd_mon_fin_gain(1.0)
|
||||
await kirdy.device.set_pd_mon_transconductance(1/1000.0)
|
||||
|
||||
# Network Settings will be updated on next reboot.
|
||||
await kirdy.device.set_ip_settings(
|
||||
addr="192.168.1.128",
|
||||
port=1550,
|
||||
prefix_len=24,
|
||||
gateway="192.168.1.1"
|
||||
)
|
||||
# Hard reset Kirdy.
|
||||
await kirdy.device.hard_reset()
|
||||
|
||||
async def ld_thermostat_cfg(kirdy: Kirdy):
|
||||
"""
|
||||
Control and config laser diode and thermostat parameters.
|
||||
"""
|
||||
# Load the laser diode and thermostat settings from flash memory.
|
||||
await kirdy.device.restore_settings_from_flash()
|
||||
|
||||
# Power off the laser diode & thermostat and clear any asserted alarm
|
||||
await kirdy.laser.set_power_on(False)
|
||||
await kirdy.laser.clear_alarm()
|
||||
await kirdy.thermostat.set_power_on(False)
|
||||
await kirdy.thermostat.clear_alarm()
|
||||
|
||||
# Set the laser diode terminals not to be shorted
|
||||
await kirdy.laser.set_ld_terms_short(False)
|
||||
|
||||
# Do not power up the laser & thermostat during initial startup
|
||||
await kirdy.laser.set_default_pwr_on(False)
|
||||
await kirdy.thermostat.set_default_pwr_on(False)
|
||||
|
||||
await kirdy.laser.set_i(0)
|
||||
|
||||
# Configure the laser diode output power limit and photodiode parameters
|
||||
# Exceeding the power limit triggers overpower protection alarm.
|
||||
# The laser diode power will be cut off upon alarm assertion while the thermostat power remains unchanged.
|
||||
await kirdy.laser.set_ld_pwr_limit(0.0)
|
||||
await kirdy.laser.set_pd_mon_dark_current(0.0)
|
||||
await kirdy.laser.set_pd_mon_responsitivity(0.0)
|
||||
|
||||
# Configure the thermostat NTC thermistor parameters.
|
||||
await kirdy.thermostat.set_sh_r0(10.0 * 1000)
|
||||
await kirdy.thermostat.set_sh_t0(25)
|
||||
await kirdy.thermostat.set_sh_beta(3900)
|
||||
|
||||
# Configure the thermostat TEC settings.
|
||||
# The actual output current is limited by value set below.
|
||||
await kirdy.thermostat.set_tec_max_cooling_i(1.0)
|
||||
await kirdy.thermostat.set_tec_max_heating_i(1.0)
|
||||
await kirdy.thermostat.set_tec_max_v(4.0)
|
||||
|
||||
# Configure the thermostat temperature monitor limits.
|
||||
# Exceeding the temperature limits trigger over temperature protection alarm.
|
||||
# Both laser diode and thermostat power will be cut off upon alarm assertion.
|
||||
await kirdy.thermostat.set_temp_mon_upper_limit(70)
|
||||
await kirdy.thermostat.set_temp_mon_lower_limit(0)
|
||||
|
||||
# Configure the thermostat ADC Filter Setting / PID Update Rate / Report Rate.
|
||||
# The ADC sampling rate determines the report and pid update rate.
|
||||
# The chosen filter and sampling rate affects the noise of the readings.
|
||||
# For details, please refer to the AD7172 datasheet.
|
||||
await kirdy.thermostat.config_temp_adc_filter(FilterConfig.Sinc5Sinc1With50hz60HzRejection.f16sps)
|
||||
|
||||
# Configure the thermostat PID parameters.
|
||||
# You can configure the PID parameter by the included autotune script.
|
||||
# You should configure the filter sampling rate first before applying pid parameters.
|
||||
await kirdy.thermostat.set_temperature_setpoint(25)
|
||||
await kirdy.thermostat.set_pid_kp(0.15668282198105507)
|
||||
await kirdy.thermostat.set_pid_ki(0.0001281321)
|
||||
await kirdy.thermostat.set_pid_kd(13.82367)
|
||||
await kirdy.thermostat.set_pid_output_max(1.0)
|
||||
await kirdy.thermostat.set_pid_output_min(-1.0)
|
||||
|
||||
# Configure thermostat to run in PID control mode
|
||||
await kirdy.thermostat.set_pid_control_mode()
|
||||
|
||||
# When control mode is switched from PID to constant current(CC) control mode,
|
||||
# thermostat keeps its instantaneous output current unchanged.
|
||||
# Thermostat output current should only be set if it is in CC control mode
|
||||
# or the value set will be overwritten by PID output.
|
||||
await kirdy.thermostat.set_constant_current_control_mode()
|
||||
await kirdy.thermostat.set_tec_i_out(0.0)
|
||||
|
||||
# Save the current settings to flash memory
|
||||
await kirdy.device.save_current_settings_to_flash()
|
||||
|
||||
# Power on the laser diode and thermostat
|
||||
await kirdy.laser.set_power_on(True)
|
||||
await kirdy.thermostat.set_power_on(True)
|
||||
|
||||
pp(await kirdy.device.get_settings_summary())
|
||||
pp(await kirdy.device.get_status_report())
|
||||
|
||||
async def main():
|
||||
kirdy = Kirdy()
|
||||
kirdy.start_session(host='192.168.1.128', port=1550)
|
||||
await kirdy.wait_until_connected()
|
||||
|
||||
await ld_thermostat_cfg(kirdy)
|
||||
# await device_cfg(kirdy)
|
||||
# await enter_dfu_mode(kirdy)
|
||||
|
||||
await kirdy.end_session()
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
108
pykirdy/autotune_example.py
Normal file
108
pykirdy/autotune_example.py
Normal file
@@ -0,0 +1,108 @@
|
||||
from pykirdy.aioclient import Kirdy, FilterConfig
|
||||
from pykirdy.autotune import PIDAutotune
|
||||
import asyncio
|
||||
import signal
|
||||
import json
|
||||
from sipyco.asyncio_tools import SignalHandler
|
||||
|
||||
async def main():
|
||||
"""
|
||||
PID AutoTune Tools for Kirdy
|
||||
The obtained temperature works best at the target temperature specified.
|
||||
Before running PID AutoTune, please
|
||||
1. Secure the laser diode onto the LD adapter and copper heat sink
|
||||
2. Make sure Kirdy has warmed up and reached thermal equilibrium state
|
||||
|
||||
In case of PID Autotune Failure, you can
|
||||
1. Run the PID Autotune again
|
||||
2. Or increase the lookback period
|
||||
3. Or increase the sampling rate
|
||||
"""
|
||||
|
||||
# Target temperature of the autotune routine, celsius
|
||||
target_temperature = 20
|
||||
# Value by which output will be increased/decreased from zero, amps
|
||||
output_step = 1
|
||||
# Reference period for local minima/maxima, seconds
|
||||
lookback = 2.0
|
||||
# Determines by how much the input value must
|
||||
# overshoot/undershoot the setpoint, celsius
|
||||
noiseband = 2.0
|
||||
|
||||
kirdy = Kirdy()
|
||||
kirdy.start_session(host='192.168.1.134', port=1550)
|
||||
|
||||
await kirdy.wait_until_connected()
|
||||
|
||||
while not(kirdy.connected()):
|
||||
pass
|
||||
|
||||
await kirdy.laser.set_power_on(False)
|
||||
await kirdy.laser.set_i(0)
|
||||
|
||||
await kirdy.thermostat.set_power_on(False)
|
||||
await kirdy.thermostat.set_constant_current_control_mode()
|
||||
await kirdy.thermostat.set_tec_i_out(0)
|
||||
await kirdy.thermostat.clear_alarm()
|
||||
|
||||
|
||||
signal_handler = SignalHandler()
|
||||
signal_handler.setup()
|
||||
async def sig_handling():
|
||||
await signal_handler.wait_terminate()
|
||||
tuner.setFailed()
|
||||
asyncio.create_task(sig_handling())
|
||||
|
||||
# Configure the Thermistor Parameters
|
||||
await kirdy.thermostat.set_sh_beta(3950)
|
||||
await kirdy.thermostat.set_sh_r0(10.0 * 1000)
|
||||
await kirdy.thermostat.set_sh_t0(25)
|
||||
|
||||
# Set a large enough temperature range so that it won't trigger overtemperature protection
|
||||
await kirdy.thermostat.set_temp_mon_upper_limit(target_temperature + 20)
|
||||
await kirdy.thermostat.set_temp_mon_lower_limit(target_temperature - 20)
|
||||
|
||||
await kirdy.thermostat.set_tec_max_cooling_i(output_step)
|
||||
await kirdy.thermostat.set_tec_max_heating_i(output_step)
|
||||
|
||||
# The Polling Rate of Temperature Adc is equal to the PID Update Interval
|
||||
await kirdy.thermostat.config_temp_adc_filter(FilterConfig.Sinc5Sinc1With50hz60HzRejection.f16sps)
|
||||
settings = await kirdy.device.get_settings_summary()
|
||||
sampling_rate = settings["thermostat"]["temp_adc_settings"]["rate"]
|
||||
|
||||
print("Settings: {0}".format(settings))
|
||||
|
||||
tuner = PIDAutotune(target_temperature, output_step,
|
||||
lookback, noiseband, 1/sampling_rate)
|
||||
|
||||
await kirdy.thermostat.set_power_on(True)
|
||||
|
||||
while True:
|
||||
status_report = await kirdy.device.get_status_report()
|
||||
|
||||
temperature = status_report["thermostat"]["temperature"]
|
||||
ts = status_report['ts']
|
||||
print("Ts: {0} Current Temperature: {1} degree".format(ts, temperature))
|
||||
|
||||
if (tuner.run(temperature, ts / 1000.0)):
|
||||
print(tuner._state)
|
||||
break
|
||||
|
||||
tuner_out = tuner.output()
|
||||
await kirdy.thermostat.set_tec_i_out(float(tuner_out))
|
||||
|
||||
await kirdy.thermostat.set_tec_i_out(0)
|
||||
await kirdy.thermostat.set_power_on(False)
|
||||
|
||||
# if tuner.state() == PIDAutotuneState.STATE_SUCCEEDED:
|
||||
# pid_params = tuner.get_pid_parameters(tuning_rule="tyreus-luyben")
|
||||
# await kirdy.thermostat.set_pid_kp(pid_params.Kp)
|
||||
# await kirdy.thermostat.set_pid_ki(pid_params.Ki)
|
||||
# await kirdy.thermostat.set_pid_kd(pid_params.Kd)
|
||||
# await kirdy.thermostat.set_pid_output_max(1.0)
|
||||
# await kirdy.thermostat.set_pid_output_min(1.0)
|
||||
|
||||
await kirdy.end_session()
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
1197
pykirdy/pykirdy/aioclient.py
Normal file
1197
pykirdy/pykirdy/aioclient.py
Normal file
File diff suppressed because it is too large
Load Diff
250
pykirdy/pykirdy/autotune.py
Normal file
250
pykirdy/pykirdy/autotune.py
Normal file
@@ -0,0 +1,250 @@
|
||||
import math
|
||||
import logging
|
||||
from collections import deque, namedtuple
|
||||
from enum import Enum
|
||||
import socket
|
||||
import time
|
||||
from pykirdy.aioclient import Kirdy, FilterConfig
|
||||
import asyncio
|
||||
|
||||
# Based on hirshmann pid-autotune libiary
|
||||
# See https://github.com/hirschmann/pid-autotune
|
||||
# Which is in turn based on a fork of Arduino PID AutoTune Library
|
||||
# See https://github.com/t0mpr1c3/Arduino-PID-AutoTune-Library
|
||||
|
||||
|
||||
class PIDAutotuneState(Enum):
|
||||
STATE_OFF = 'off'
|
||||
STATE_RELAY_STEP_UP = 'relay step up'
|
||||
STATE_RELAY_STEP_DOWN = 'relay step down'
|
||||
STATE_SUCCEEDED = 'succeeded'
|
||||
STATE_FAILED = 'failed'
|
||||
STATE_READY = 'ready'
|
||||
|
||||
|
||||
class PIDAutotune:
|
||||
PIDParams = namedtuple('PIDParams', ['Kp', 'Ki', 'Kd'])
|
||||
|
||||
PEAK_AMPLITUDE_TOLERANCE = 0.05
|
||||
|
||||
_tuning_rules = {
|
||||
"ziegler-nichols": [0.6, 1.2, 0.075],
|
||||
"tyreus-luyben": [0.4545, 0.2066, 0.07214],
|
||||
"ciancone-marlin": [0.303, 0.1364, 0.0481],
|
||||
"pessen-integral": [0.7, 1.75, 0.105],
|
||||
"some-overshoot": [0.333, 0.667, 0.111],
|
||||
"no-overshoot": [0.2, 0.4, 0.0667]
|
||||
}
|
||||
|
||||
def __init__(self, setpoint, out_step=10, lookback=60,
|
||||
noiseband=0.5, sampletime=1.2):
|
||||
if setpoint is None:
|
||||
raise ValueError('setpoint must be specified')
|
||||
|
||||
self._inputs = deque(maxlen=round(lookback / sampletime))
|
||||
self._sampletime = sampletime
|
||||
self._setpoint = setpoint
|
||||
self._outputstep = out_step
|
||||
self._noiseband = noiseband
|
||||
self._out_min = -out_step
|
||||
self._out_max = out_step
|
||||
self._state = PIDAutotuneState.STATE_OFF
|
||||
self._peak_timestamps = deque(maxlen=5)
|
||||
self._peaks = deque(maxlen=5)
|
||||
self._output = 0
|
||||
self._last_run_timestamp = 0
|
||||
self._peak_type = 0
|
||||
self._peak_count = 0
|
||||
self._initial_output = 0
|
||||
self._induced_amplitude = 0
|
||||
self._Ku = 0
|
||||
self._Pu = 0
|
||||
|
||||
def setParam(self, target, step, noiseband, sampletime, lookback):
|
||||
self._setpoint = target
|
||||
self._outputstep = step
|
||||
self._out_max = step
|
||||
self._out_min = -step
|
||||
self._noiseband = noiseband
|
||||
self._inputs = deque(maxlen=round(lookback / sampletime))
|
||||
self._sampletime = sampletime
|
||||
|
||||
def setReady(self):
|
||||
self._state = PIDAutotuneState.STATE_READY
|
||||
self._peak_count = 0
|
||||
|
||||
def setOff(self):
|
||||
self._state = PIDAutotuneState.STATE_OFF
|
||||
|
||||
def setFailed(self):
|
||||
self._state = PIDAutotuneState.STATE_FAILED
|
||||
self._peak_count = 30
|
||||
|
||||
def state(self):
|
||||
"""Get the current state."""
|
||||
return self._state
|
||||
|
||||
def output(self):
|
||||
"""Get the last output value."""
|
||||
return self._output
|
||||
|
||||
def tuning_rules(self):
|
||||
"""Get a list of all available tuning rules."""
|
||||
return self._tuning_rules.keys()
|
||||
|
||||
def get_tec_pid (self):
|
||||
divisors = self._tuning_rules["tyreus-luyben"]
|
||||
kp = self._Ku * divisors[0]
|
||||
ki = divisors[1] * self._Ku / self._Pu / (1 / self._sampletime)
|
||||
kd = divisors[2] * self._Ku * self._Pu * (1 / self._sampletime)
|
||||
return kp, ki, kd
|
||||
|
||||
def get_pid_parameters(self, tuning_rule='ziegler-nichols'):
|
||||
"""Get PID parameters.
|
||||
|
||||
Args:
|
||||
tuning_rule (str): Sets the rule which should be used to calculate
|
||||
the parameters.
|
||||
"""
|
||||
divisors = self._tuning_rules[tuning_rule]
|
||||
kp = self._Ku * divisors[0]
|
||||
ki = divisors[1] * self._Ku / self._Pu / (1 / self._sampletime)
|
||||
kd = divisors[2] * self._Ku * self._Pu * (1 / self._sampletime)
|
||||
return PIDAutotune.PIDParams(kp, ki, kd)
|
||||
|
||||
def run(self, input_val, time_input):
|
||||
"""To autotune a system, this method must be called periodically.
|
||||
|
||||
Args:
|
||||
input_val (float): The temperature input value.
|
||||
time_input (float): Current time in seconds.
|
||||
|
||||
Returns:
|
||||
`true` if tuning is finished, otherwise `false`.
|
||||
"""
|
||||
now = time_input * 1000
|
||||
|
||||
if (self._state == PIDAutotuneState.STATE_OFF
|
||||
or self._state == PIDAutotuneState.STATE_SUCCEEDED
|
||||
or self._state == PIDAutotuneState.STATE_FAILED
|
||||
or self._state == PIDAutotuneState.STATE_READY):
|
||||
self._state = PIDAutotuneState.STATE_RELAY_STEP_UP
|
||||
|
||||
self._last_run_timestamp = now
|
||||
|
||||
# check input and change relay state if necessary
|
||||
if (self._state == PIDAutotuneState.STATE_RELAY_STEP_UP
|
||||
and input_val > self._setpoint + self._noiseband):
|
||||
self._state = PIDAutotuneState.STATE_RELAY_STEP_DOWN
|
||||
logging.debug('switched state: {0}'.format(self._state))
|
||||
logging.debug('input: {0}'.format(input_val))
|
||||
elif (self._state == PIDAutotuneState.STATE_RELAY_STEP_DOWN
|
||||
and input_val < self._setpoint - self._noiseband):
|
||||
self._state = PIDAutotuneState.STATE_RELAY_STEP_UP
|
||||
logging.debug('switched state: {0}'.format(self._state))
|
||||
logging.debug('input: {0}'.format(input_val))
|
||||
|
||||
# set output
|
||||
if (self._state == PIDAutotuneState.STATE_RELAY_STEP_UP):
|
||||
self._output = self._initial_output - self._outputstep
|
||||
elif self._state == PIDAutotuneState.STATE_RELAY_STEP_DOWN:
|
||||
self._output = self._initial_output + self._outputstep
|
||||
|
||||
# respect output limits
|
||||
self._output = min(self._output, self._out_max)
|
||||
self._output = max(self._output, self._out_min)
|
||||
|
||||
# identify peaks
|
||||
is_max = True
|
||||
is_min = True
|
||||
|
||||
for val in self._inputs:
|
||||
is_max = is_max and (input_val >= val)
|
||||
is_min = is_min and (input_val <= val)
|
||||
|
||||
self._inputs.append(input_val)
|
||||
|
||||
# we don't trust the maxes or mins until the input array is full
|
||||
if len(self._inputs) < self._inputs.maxlen:
|
||||
return False
|
||||
|
||||
# increment peak count and record peak time for maxima and minima
|
||||
inflection = False
|
||||
|
||||
# peak types:
|
||||
# -1: minimum
|
||||
# +1: maximum
|
||||
if is_max:
|
||||
if self._peak_type == -1:
|
||||
inflection = True
|
||||
self._peak_type = 1
|
||||
elif is_min:
|
||||
if self._peak_type == 1:
|
||||
inflection = True
|
||||
self._peak_type = -1
|
||||
|
||||
# update peak times and values
|
||||
if inflection:
|
||||
self._peak_count += 1
|
||||
self._peaks.append(input_val)
|
||||
self._peak_timestamps.append(now)
|
||||
logging.debug('found peak: {0}'.format(input_val))
|
||||
logging.debug('peak count: {0}'.format(self._peak_count))
|
||||
|
||||
# check for convergence of induced oscillation
|
||||
# convergence of amplitude assessed on last 4 peaks (1.5 cycles)
|
||||
self._induced_amplitude = 0
|
||||
|
||||
if inflection and (self._peak_count > 4):
|
||||
abs_max = self._peaks[-2]
|
||||
abs_min = self._peaks[-2]
|
||||
for i in range(0, len(self._peaks) - 2):
|
||||
self._induced_amplitude += abs(self._peaks[i]
|
||||
- self._peaks[i+1])
|
||||
abs_max = max(self._peaks[i], abs_max)
|
||||
abs_min = min(self._peaks[i], abs_min)
|
||||
|
||||
self._induced_amplitude /= 6.0
|
||||
|
||||
# check convergence criterion for amplitude of induced oscillation
|
||||
amplitude_dev = ((0.5 * (abs_max - abs_min)
|
||||
- self._induced_amplitude)
|
||||
/ self._induced_amplitude)
|
||||
|
||||
logging.debug('amplitude: {0}'.format(self._induced_amplitude))
|
||||
logging.debug('amplitude deviation: {0}'.format(amplitude_dev))
|
||||
|
||||
if amplitude_dev < PIDAutotune.PEAK_AMPLITUDE_TOLERANCE:
|
||||
self._state = PIDAutotuneState.STATE_SUCCEEDED
|
||||
|
||||
# if the autotune has not already converged
|
||||
# terminate after 10 cycles
|
||||
if self._peak_count >= 20:
|
||||
self._output = 0
|
||||
self._state = PIDAutotuneState.STATE_FAILED
|
||||
return True
|
||||
|
||||
if self._state == PIDAutotuneState.STATE_SUCCEEDED:
|
||||
self._output = 0
|
||||
logging.debug('peak finding successful')
|
||||
|
||||
# calculate ultimate gain
|
||||
self._Ku = 4.0 * self._outputstep / \
|
||||
(self._induced_amplitude * math.pi)
|
||||
print('Ku: {0}'.format(self._Ku))
|
||||
|
||||
# calculate ultimate period in seconds
|
||||
period1 = self._peak_timestamps[3] - self._peak_timestamps[1]
|
||||
period2 = self._peak_timestamps[4] - self._peak_timestamps[2]
|
||||
self._Pu = 0.5 * (period1 + period2) / 1000.0
|
||||
print('Pu: {0}'.format(self._Pu))
|
||||
|
||||
for rule in self._tuning_rules:
|
||||
params = self.get_pid_parameters(rule)
|
||||
print('rule: {0}'.format(rule))
|
||||
print('Kp: {0}'.format(params.Kp))
|
||||
print('Ki: {0}'.format(params.Ki))
|
||||
print('Kd: {0}'.format(params.Kd))
|
||||
|
||||
return True
|
||||
return False
|
||||
1394
pykirdy/pykirdy/kirdy_qt.py
Normal file
1394
pykirdy/pykirdy/kirdy_qt.py
Normal file
File diff suppressed because it is too large
Load Diff
390
pykirdy/pykirdy/settings.schema.json
Normal file
390
pykirdy/pykirdy/settings.schema.json
Normal file
@@ -0,0 +1,390 @@
|
||||
{
|
||||
"$id": "https://m-labs.hk/kasli_generic.schema.json",
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Kirdy Settings Description",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_description": {
|
||||
"type": "string",
|
||||
"description": "Free-form description text"
|
||||
},
|
||||
"hw_rev": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"major": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
},
|
||||
"minor": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"major",
|
||||
"minor"
|
||||
]
|
||||
},
|
||||
"network_settings": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"addr": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 255
|
||||
},
|
||||
"minItems": 4,
|
||||
"maxItems": 4
|
||||
},
|
||||
"port": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 65535
|
||||
},
|
||||
"prefix_len": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 32
|
||||
},
|
||||
"gateway": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 255
|
||||
},
|
||||
"minItems": 4,
|
||||
"maxItems": 4
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"addr",
|
||||
"port",
|
||||
"prefix_len",
|
||||
"gateway"
|
||||
]
|
||||
},
|
||||
"laser": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"hw_variant": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"LC",
|
||||
"MC",
|
||||
"HC"
|
||||
]
|
||||
},
|
||||
"default_pwr_on": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"ld_pwr_limit": {
|
||||
"type": "number",
|
||||
"minimum": 0.0
|
||||
},
|
||||
"ld_terms_short": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"pd_mon_params": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"i_dark": {
|
||||
"type": "number"
|
||||
},
|
||||
"responsitivity": {
|
||||
"type": "number"
|
||||
},
|
||||
"transconductance": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"i_dark",
|
||||
"responsitivity",
|
||||
"transconductance"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"hw_variant",
|
||||
"default_pwr_on",
|
||||
"ld_drive_current",
|
||||
"ld_pwr_limit",
|
||||
"ld_terms_short",
|
||||
"pd_mon_params"
|
||||
],
|
||||
"allOf": [
|
||||
{
|
||||
"if": {
|
||||
"properties": {
|
||||
"hw_variant": {
|
||||
"const": "LC"
|
||||
}
|
||||
}
|
||||
},
|
||||
"then": {
|
||||
"properties": {
|
||||
"ld_drive_current": {
|
||||
"type": "number",
|
||||
"minimum": 0.0,
|
||||
"maximum": 0.3072
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"properties": {
|
||||
"hw_variant": {
|
||||
"const": "MC"
|
||||
}
|
||||
}
|
||||
},
|
||||
"then": {
|
||||
"properties": {
|
||||
"ld_drive_current": {
|
||||
"type": "number",
|
||||
"minimum": 0.0,
|
||||
"maximum": 0.6144
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"properties": {
|
||||
"hw_variant": {
|
||||
"const": "HC"
|
||||
}
|
||||
}
|
||||
},
|
||||
"then": {
|
||||
"properties": {
|
||||
"ld_drive_current": {
|
||||
"type": "number",
|
||||
"minimum": 0.0,
|
||||
"maximum": 1.2288
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"thermostat": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"default_pwr_on": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"control_mode": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Constant Current",
|
||||
"PID"
|
||||
]
|
||||
},
|
||||
"pid_params": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"kd": {
|
||||
"type": "number"
|
||||
},
|
||||
"ki": {
|
||||
"type": "number"
|
||||
},
|
||||
"kp": {
|
||||
"type": "number"
|
||||
},
|
||||
"output_max": {
|
||||
"type": "number"
|
||||
},
|
||||
"output_min": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"kd",
|
||||
"ki",
|
||||
"kp",
|
||||
"output_max",
|
||||
"output_min"
|
||||
]
|
||||
},
|
||||
"tec_settings": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"i_set": {
|
||||
"type": "number",
|
||||
"minimum": -3.0,
|
||||
"maximum": 3.0,
|
||||
"default": 0.0
|
||||
},
|
||||
"max_i_neg": {
|
||||
"type": "number",
|
||||
"minimum": 0.0,
|
||||
"maximum": 3.0
|
||||
},
|
||||
"max_i_pos": {
|
||||
"type": "number",
|
||||
"minimum": 0.0,
|
||||
"maximum": 3.0
|
||||
},
|
||||
"max_v": {
|
||||
"type": "number",
|
||||
"minimum": 0.0,
|
||||
"maximum": 4.3
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"i_set",
|
||||
"max_i_neg",
|
||||
"max_i_pos",
|
||||
"max_v"
|
||||
]
|
||||
},
|
||||
"temp_adc_filter_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Sinc5Sinc1With50hz60HzRejection",
|
||||
"Sinc5Sinc1",
|
||||
"Sinc3",
|
||||
"Sinc3WithFineODR"
|
||||
]
|
||||
},
|
||||
"temp_mon_settings": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"lower_limit": {
|
||||
"type": "number"
|
||||
},
|
||||
"upper_limit": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"lower_limit",
|
||||
"upper_limit"
|
||||
]
|
||||
},
|
||||
"temperature_setpoint": {
|
||||
"type": "number"
|
||||
},
|
||||
"thermistor_params": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"b": {
|
||||
"type": "number"
|
||||
},
|
||||
"r0": {
|
||||
"type": "number"
|
||||
},
|
||||
"t0": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"b",
|
||||
"r0",
|
||||
"t0"
|
||||
]
|
||||
}
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"if": {
|
||||
"properties": {
|
||||
"temp_adc_filter_type": {
|
||||
"const": "Sinc5Sinc1With50hz60HzRejection"
|
||||
}
|
||||
}
|
||||
},
|
||||
"then": {
|
||||
"properties": {
|
||||
"sinc5sinc1postfilter": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"F27SPS",
|
||||
"F25SPS",
|
||||
"F20SPS",
|
||||
"F16SPS"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"properties": {
|
||||
"temp_adc_filter_type": {
|
||||
"const": "Sinc5Sinc1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"then": {
|
||||
"properties": {
|
||||
"sinc5sinc1odr": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"F31250_0SPS",
|
||||
"F15625_0SPS",
|
||||
"F10417_0SPS",
|
||||
"F5208_0SPS",
|
||||
"F2597_0SPS",
|
||||
"F1007_0SPS",
|
||||
"F503_8SPS",
|
||||
"F381_0SPS",
|
||||
"F200_3SPS",
|
||||
"F100_2SPS",
|
||||
"F59_52SPS",
|
||||
"F49_68SPS",
|
||||
"F20_01SPS",
|
||||
"F16_63SPS",
|
||||
"F10_0SPS",
|
||||
"F5_0SPS",
|
||||
"F2_5SPS",
|
||||
"F1_25SPS"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"properties": {
|
||||
"temp_adc_filter_type": {
|
||||
"const": "Sinc3"
|
||||
}
|
||||
}
|
||||
},
|
||||
"then": {
|
||||
"properties": {
|
||||
"sinc3fineodr": {
|
||||
"type": "number",
|
||||
"minimum": 1.907465,
|
||||
"maximum": 31250.0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"required": [
|
||||
"default_pwr_on",
|
||||
"control_mode",
|
||||
"pid_params",
|
||||
"tec_settings",
|
||||
"temp_adc_filter_type",
|
||||
"temp_mon_settings",
|
||||
"temperature_setpoint",
|
||||
"thermistor_params"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"hw_rev",
|
||||
"network_settings",
|
||||
"laser",
|
||||
"thermostat"
|
||||
]
|
||||
}
|
||||
210
pykirdy/pykirdy/ui/config_adc_filter_form.ui
Normal file
210
pykirdy/pykirdy/ui/config_adc_filter_form.ui
Normal file
@@ -0,0 +1,210 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Cfg_Adc_Filter_Form</class>
|
||||
<widget class="QDialog" name="Cfg_Adc_Filter_Form">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>786</width>
|
||||
<height>303</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Config Temperature ADC Filter</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="verticalLayoutWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
<y>20</y>
|
||||
<width>731</width>
|
||||
<height>251</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="3,4,4">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Values</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Current Settings</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="filter_type_layout" stretch="3,4,4">
|
||||
<item>
|
||||
<widget class="QLabel" name="filter_type_lbl">
|
||||
<property name="text">
|
||||
<string>Filter Type</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="filter_type_cbox">
|
||||
<property name="editable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="filter_type_reading_lbl">
|
||||
<property name="text">
|
||||
<string>Sinc5Sinc1With50hz60HzRejection</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="filter_sampling_rate_layout" stretch="3,4,4,4">
|
||||
<item>
|
||||
<widget class="QLabel" name="filter_sampling_rate_lbl">
|
||||
<property name="text">
|
||||
<string>Filter Sampling Rate</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="filter_sampling_rate_cbox"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="fine_filter_sampling_rate_spinbox">
|
||||
<property name="maximum">
|
||||
<double>1000.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>16.670000000000002</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="filter_sampling_rate_reading_lbl">
|
||||
<property name="text">
|
||||
<string>F16SPS</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="recorded_sampling_rate_layout" stretch="3,4,4">
|
||||
<item>
|
||||
<widget class="QLabel" name="recorded_sampling_rate_lbl">
|
||||
<property name="text">
|
||||
<string>Recorded Sampling Rate</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="recorded_sampling_rate_reading_lbl">
|
||||
<property name="text">
|
||||
<string>16.67</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="apply_btn_layout" stretch="3,2,3,2">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="apply_btn">
|
||||
<property name="text">
|
||||
<string>Apply</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="close_btn">
|
||||
<property name="text">
|
||||
<string>Close</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>close_btn</sender>
|
||||
<signal>clicked()</signal>
|
||||
<receiver>Cfg_Adc_Filter_Form</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>677</x>
|
||||
<y>246</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>392</x>
|
||||
<y>151</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
768
pykirdy/pykirdy/ui/config_pd_mon_form.ui
Normal file
768
pykirdy/pykirdy/ui/config_pd_mon_form.ui
Normal file
@@ -0,0 +1,768 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Cfg_Pd_Mon_Form</class>
|
||||
<widget class="QDialog" name="Cfg_Pd_Mon_Form">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>660</width>
|
||||
<height>795</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>660</width>
|
||||
<height>795</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>660</width>
|
||||
<height>795</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>config_pd_mon_form</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="verticalLayoutWidget_2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>10</y>
|
||||
<width>641</width>
|
||||
<height>772</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="cfg_pd_mon_form_layout" stretch="3,2,2,3,2,2,2,1">
|
||||
<item>
|
||||
<widget class="QLabel" name="title_lbl">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>22</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Configure Photodiode Monitor</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="pwr_off_layout" stretch="5,4">
|
||||
<property name="spacing">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SizeConstraint::SetDefaultConstraint</enum>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="pwr_off_lbl">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>14</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string> Step 1: Turn off Laser Power</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pwr_off_btn">
|
||||
<property name="text">
|
||||
<string>Power Off</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="rst_ld_pwr_limit_layout" stretch="5,4">
|
||||
<item>
|
||||
<widget class="QLabel" name="rst_ld_pwr_limit_lbl">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>14</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string> Step 2: Reset Ld Pwr Limit to 0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="rst_ld_pwr_limit_btn">
|
||||
<property name="text">
|
||||
<string>Reset Ld Pwr Limit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="cfg_pd_transconductance_layout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="cfg_pd_transconductance_lbl_2">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>14</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string> Step 3: (Optional) Configure Transimpedance Amplifier Circuit Parameters</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6" stretch="1,12">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_13">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="cfg_pd_transconductance_lbl">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>14</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Leave them unchanged if the TIA Circuit is NOT Modified</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4" stretch="5,2,2">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_10">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string> Values</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Current Settings</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="cfg_pd_fin_gain_layout" stretch="5,2,2">
|
||||
<item>
|
||||
<widget class="QLabel" name="cfg_pd_fin_gain_lbl">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TIA Final Stage Gain:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="cfg_pd_fin_gain_spinbox">
|
||||
<property name="decimals">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.001000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_11">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="pd_fb_resistance_layout" stretch="5,2,2">
|
||||
<item>
|
||||
<widget class="QLabel" name="cfg_pd_fb_resistance_lbl">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TIA Feedback Resistance:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="cfg_pd_fb_resistance_spinbox">
|
||||
<property name="decimals">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.000100000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1000000.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.001000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_12">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="resulting_pd_transconductance_layout" stretch="5,2,2">
|
||||
<property name="spacing">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="resulting_pd_transconductance_lbl">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Resulting TIA Transconductance:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="resulting_pd_transconductance_value">
|
||||
<property name="text">
|
||||
<string>0.0000</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="resulting_pd_transconductance_reading">
|
||||
<property name="text">
|
||||
<string>0.0000</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="allowed_photodiode_current_range_layout" stretch="5,2,2">
|
||||
<property name="spacing">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="allowed_photodiode_current_range_lbl">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Allowed Photodiode Current Range:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="allowed_photodiode_current_range_value">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>28</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>(PD Current Range)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="allowed_photodiode_current_range_reading">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>28</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>(PD Current Range)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="apply_pd_transconductance_layout_2" stretch="5,4">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_9">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="apply_pd_transconductance_btn">
|
||||
<property name="text">
|
||||
<string>Apply</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="cfg_pd_params_layout">
|
||||
<item>
|
||||
<widget class="QLabel" name="cfg_pd_params_lbl">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>14</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string> Step 4: Configure Photodiode Parameters</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="5,2,2">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string> Values</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Current Settings</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="cfg_responsitivity_layout" stretch="5,2,2">
|
||||
<item>
|
||||
<widget class="QLabel" name="cfg_responsitivity_lbl">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Responsitivity: </string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="cfg_responsitivity_spinbox">
|
||||
<property name="suffix">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1000.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.001000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="cfg_responsitivity_reading">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>0.0000</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="cfg_dark_current_layout" stretch="5,2,2">
|
||||
<item>
|
||||
<widget class="QLabel" name="cfg_dark_current_lbl">
|
||||
<property name="text">
|
||||
<string>Dark Current: </string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="cfg_dark_current_spinbox">
|
||||
<property name="decimals">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.001000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="cfg_dark_current_reading">
|
||||
<property name="text">
|
||||
<string>0.0000</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="apply_pd_params_layout" stretch="5,4">
|
||||
<property name="spacing">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>10</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="apply_pd_params_btn">
|
||||
<property name="text">
|
||||
<string>Apply</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="cfg_pwr_limit_layout">
|
||||
<item>
|
||||
<widget class="QLabel" name="cfg_pd_pwr_limit_lbl">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>14</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string> Step 5: Configure Laser Diode Power Limit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="5,2,2">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string> Values</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Current Settings</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="pwr_limit_layout" stretch="5,2,2">
|
||||
<item>
|
||||
<widget class="QLabel" name="cfg_pwr_limit_lbl">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Power Limit:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="cfg_pwr_limit_spinbox">
|
||||
<property name="decimals">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.001000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="cfg_pwr_limit_reading">
|
||||
<property name="text">
|
||||
<string>0.0000</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="settable_pwr_range_layout" stretch="5,4">
|
||||
<property name="spacing">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="settable_pwr_range_lbl">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Settable Power Range:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="settable_pwr_range_display_lbl">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>28</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>( Power Range )</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="apply_pwr_limit_layout" stretch="2,3,4">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="apply_pwr_limit_max_btn">
|
||||
<property name="text">
|
||||
<string>Apply Max Pwr Limit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="apply_pwr_limit_btn">
|
||||
<property name="text">
|
||||
<string>Apply</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="pwr_on_layout" stretch="5,4">
|
||||
<property name="spacing">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="pwr_on_lbl">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>14</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string> Step 6: Turn On Laser Power</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pwr_on_btn">
|
||||
<property name="text">
|
||||
<string>Clear Alarm and Power On</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="close_btn_layout" stretch="5,4">
|
||||
<property name="spacing">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="close_btn">
|
||||
<property name="text">
|
||||
<string>Close</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>close_btn</sender>
|
||||
<signal>clicked()</signal>
|
||||
<receiver>Cfg_Pd_Mon_Form</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>141</x>
|
||||
<y>456</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>281</x>
|
||||
<y>355</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
376
pykirdy/pykirdy/ui/conn_settings_form.ui
Normal file
376
pykirdy/pykirdy/ui/conn_settings_form.ui
Normal file
@@ -0,0 +1,376 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Conn_Settings_Form</class>
|
||||
<widget class="QDialog" name="Conn_Settings_Form">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>415</width>
|
||||
<height>145</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>415</width>
|
||||
<height>145</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>415</width>
|
||||
<height>145</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Connection Settings</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="horizontalLayoutWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
<y>10</y>
|
||||
<width>371</width>
|
||||
<height>41</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="ip_addr_layout">
|
||||
<item>
|
||||
<widget class="QLabel" name="ip_addr_label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>IP Address:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="addr_in_0">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>192</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="dot_0_label">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>10</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
<bold>false</bold>
|
||||
<kerning>true</kerning>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>.</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="addr_in_1">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>168</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="dot_1_label">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>10</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
<bold>false</bold>
|
||||
<kerning>true</kerning>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>.</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="addr_in_2">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>1</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="dot_2_label">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>10</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
<bold>false</bold>
|
||||
<kerning>true</kerning>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>.</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="addr_in_3">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>128</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="horizontalLayoutWidget_2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
<y>50</y>
|
||||
<width>371</width>
|
||||
<height>41</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="port_layout" stretch="3,0,6">
|
||||
<item>
|
||||
<widget class="QLabel" name="port_no_label">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>97</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Port:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="port_in">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>1550</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="port_layout_spacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Preferred</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="horizontalLayoutWidget_4">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
<y>90</y>
|
||||
<width>371</width>
|
||||
<height>47</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="buttons_layout">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="connect_btn">
|
||||
<property name="text">
|
||||
<string>Connect</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="cancel_btn">
|
||||
<property name="text">
|
||||
<string>Cancel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>addr_in_0</tabstop>
|
||||
<tabstop>addr_in_1</tabstop>
|
||||
<tabstop>addr_in_2</tabstop>
|
||||
<tabstop>addr_in_3</tabstop>
|
||||
<tabstop>port_in</tabstop>
|
||||
<tabstop>connect_btn</tabstop>
|
||||
<tabstop>cancel_btn</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>cancel_btn</sender>
|
||||
<signal>clicked()</signal>
|
||||
<receiver>Conn_Settings_Form</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>340</x>
|
||||
<y>140</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>364</x>
|
||||
<y>96</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>connect_btn</sender>
|
||||
<signal>clicked()</signal>
|
||||
<receiver>Conn_Settings_Form</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>258</x>
|
||||
<y>147</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>237</x>
|
||||
<y>99</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
7
pykirdy/pykirdy/ui/main_window.qss
Normal file
7
pykirdy/pykirdy/ui/main_window.qss
Normal file
@@ -0,0 +1,7 @@
|
||||
QPushButton:disabled { color: gray }
|
||||
ParameterTree:disabled { color: gray }
|
||||
QToolButton:disabled { color: gray }
|
||||
QDoubleSpinBox:disabled { color: gray }
|
||||
QCheckBox:disabled { color: gray }
|
||||
QMenu:disabled { color: gray }
|
||||
QLabel:disabled { color: gray }
|
||||
757
pykirdy/pykirdy/ui/main_window.ui
Normal file
757
pykirdy/pykirdy/ui/main_window.ui
Normal file
@@ -0,0 +1,757 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1280</width>
|
||||
<height>720</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>1280</width>
|
||||
<height>720</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>3840</width>
|
||||
<height>2160</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Kirdy Control Panel</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset theme="application-x-executable"/>
|
||||
</property>
|
||||
<widget class="QWidget" name="main_widget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>1</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="main_layout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,2">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SizeConstraint::SetDefaultConstraint</enum>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="ctrl_vertical_layout" stretch="1,1,10,1,1,1,10,1">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SizeConstraint::SetMaximumSize</enum>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="ld_section_label">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>14</pointsize>
|
||||
<bold>true</bold>
|
||||
<underline>false</underline>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string> Laser Diode </string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="ld_status">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string> Status: Power Off</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="ParameterTree" name="ld_tree" native="true">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="ld_btns_layout">
|
||||
<property name="spacing">
|
||||
<number>30</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="ld_pwr_on_btn">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>POWER ON</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="ld_pwr_off_btn">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>POWER OFF</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="ld_clear_alarm_btn">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>CLEAR ALARM</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="tec_section_label">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>14</pointsize>
|
||||
<bold>true</bold>
|
||||
<underline>false</underline>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string> Thermostat </string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QLabel" name="tec_status">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string> Status: Power Off</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="ParameterTree" name="tec_tree" native="true">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="tec_btns_layout">
|
||||
<property name="spacing">
|
||||
<number>30</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="tec_pwr_on_btn">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>POWER ON</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="tec_pwr_off_btn">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>POWER OFF</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="tec_clear_alarm_btn">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>CLEAR ALARM</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="graphgroup">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SizeConstraint::SetNoConstraint</enum>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="1" column="0">
|
||||
<widget class="LivePlotWidget" name="tec_temp_graph" native="true">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="LivePlotWidget" name="tec_i_graph" native="true">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="LivePlotWidget" name="pd_mon_pwr_graph" native="true">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="LivePlotWidget" name="ld_i_set_graph" native="true">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="bottom_settings_group">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="settings_layout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="connect_btn">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Connect</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="status_icon_front">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="status_lbl">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>440</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>440</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="baseSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>50</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Disconnected</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="plot_settings">
|
||||
<property name="toolTip">
|
||||
<string>Plot Settings</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>📉</string>
|
||||
</property>
|
||||
<property name="popupMode">
|
||||
<enum>QToolButton::ToolButtonPopupMode::InstantPopup</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="background_task_lbl_icon_front">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTipDuration">
|
||||
<number>1000000000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="background_task_lbl">
|
||||
<property name="text">
|
||||
<string>Ready.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QtWaitingSpinner" name="loading_spinner" native="true"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="polling_rate_lbl">
|
||||
<property name="text">
|
||||
<string>Polling Rate (Hz): </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="report_group" native="true">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="polling_rate_spinbox">
|
||||
<property name="maximum">
|
||||
<double>1000.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>20.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menuBar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1280</width>
|
||||
<height>24</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuKirdy">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Kirdy</string>
|
||||
</property>
|
||||
<addaction name="menu_action_about_kirdy"/>
|
||||
<addaction name="menu_action_update_net_settings"/>
|
||||
<addaction name="menu_action_dfu_mode"/>
|
||||
<addaction name="menu_action_hard_reset"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuAbout">
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>About</string>
|
||||
</property>
|
||||
<addaction name="menu_action_about_gui"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuSettings">
|
||||
<property name="title">
|
||||
<string>Settings</string>
|
||||
</property>
|
||||
<addaction name="menu_action_save_to_flash"/>
|
||||
<addaction name="menu_action_restore_from_flash"/>
|
||||
<addaction name="menu_action_import"/>
|
||||
<addaction name="menu_action_export"/>
|
||||
</widget>
|
||||
<addaction name="menuKirdy"/>
|
||||
<addaction name="menuSettings"/>
|
||||
<addaction name="menuAbout"/>
|
||||
</widget>
|
||||
<action name="actionReset">
|
||||
<property name="text">
|
||||
<string>Reset</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Reset the Kirdy</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::MenuRole::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionEnter_DFU_Mode">
|
||||
<property name="text">
|
||||
<string>Enter DFU Mode</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Reset kirdy and enter USB device firmware update (DFU) mode</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::MenuRole::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionNetwork_Settings">
|
||||
<property name="text">
|
||||
<string>Network Settings</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Configure IPv4 address, netmask length, and optional default gateway</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::MenuRole::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionAbout_Kirdy">
|
||||
<property name="text">
|
||||
<string>About Kirdy</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Show Kirdy hardware revision, and settings related to i</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::MenuRole::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionLoad_all_configs">
|
||||
<property name="text">
|
||||
<string>Load all channel configs from flash</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Restore configuration for all channels from flash</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::MenuRole::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSave_all_configs">
|
||||
<property name="text">
|
||||
<string>Save all channel configs to flash</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Save configuration for all channels to flash</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::MenuRole::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionConnection_Settings">
|
||||
<property name="text">
|
||||
<string>Connect</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="menu_action_update_net_settings">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Update Network Settings</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="menu_action_dfu_mode">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enter DFU Mode</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="menu_action_hard_reset">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Hard Reset</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="menu_action_connect">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Connect</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="menu_action_disconnect">
|
||||
<property name="text">
|
||||
<string>Disconnect</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="menu_action_about_gui">
|
||||
<property name="text">
|
||||
<string>About GUI</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action">
|
||||
<property name="text">
|
||||
<string>test</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="menu_action_about_kirdy">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>About Kirdy</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="menu_action_save_to_flash">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Save to Flash</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="menu_action_import">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Import</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="menu_action_restore_from_flash">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Restore from Flash</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="menu_action_export">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Export</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>ParameterTree</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>pyqtgraph.parametertree</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>LivePlotWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>pglive.sources.live_plot_widget</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>QtWaitingSpinner</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>pykirdy.ui.waitingspinnerwidget</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
614
pykirdy/pykirdy/ui/update_network_settings_form.ui
Normal file
614
pykirdy/pykirdy/ui/update_network_settings_form.ui
Normal file
@@ -0,0 +1,614 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Update_Network_Settings_Form</class>
|
||||
<widget class="QDialog" name="Update_Network_Settings_Form">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>415</width>
|
||||
<height>180</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>415</width>
|
||||
<height>180</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>415</width>
|
||||
<height>180</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Update Network Settings</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="horizontalLayoutWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
<y>10</y>
|
||||
<width>371</width>
|
||||
<height>41</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="ip_addr_layout">
|
||||
<item>
|
||||
<widget class="QLabel" name="ip_addr_label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>IP Address:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="addr_in_0">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>192</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="dot_0_lbl">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>10</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
<bold>false</bold>
|
||||
<kerning>true</kerning>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>.</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="addr_in_1">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>168</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="dot_1_lbl">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>10</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
<bold>false</bold>
|
||||
<kerning>true</kerning>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>.</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="addr_in_2">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>1</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="dot_2_lbl">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>10</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
<bold>false</bold>
|
||||
<kerning>true</kerning>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>.</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="addr_in_3">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>128</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="horizontalLayoutWidget_4">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
<y>130</y>
|
||||
<width>371</width>
|
||||
<height>47</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="buttons_layout">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="update_btn">
|
||||
<property name="text">
|
||||
<string>Update</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="cancel_btn">
|
||||
<property name="text">
|
||||
<string>Cancel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="horizontalLayoutWidget_3">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
<y>90</y>
|
||||
<width>371</width>
|
||||
<height>41</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="port_layout_2" stretch="0,0,0,0,0">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="prefix_len_lbl">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>98</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Prefix Length:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="prefix_len_in">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>24</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="port_no_lbl">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>82</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Port:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="port_in">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>1550</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="horizontalLayoutWidget_5">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>20</x>
|
||||
<y>50</y>
|
||||
<width>371</width>
|
||||
<height>41</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="gateway_layout">
|
||||
<item>
|
||||
<widget class="QLabel" name="gateway_lbl">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Gateway:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="gateway_in_0">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>192</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="dot_0_lbl_2">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>10</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
<bold>false</bold>
|
||||
<kerning>true</kerning>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>.</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="gateway_in_1">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>168</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="dot_1_lbl_2">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>10</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
<bold>false</bold>
|
||||
<kerning>true</kerning>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>.</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="gateway_in_2">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>1</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="dot_2_lbl_2">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>10</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
<bold>false</bold>
|
||||
<kerning>true</kerning>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>.</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="gateway_in_3">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>1</string>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>addr_in_0</tabstop>
|
||||
<tabstop>addr_in_1</tabstop>
|
||||
<tabstop>addr_in_2</tabstop>
|
||||
<tabstop>addr_in_3</tabstop>
|
||||
<tabstop>gateway_in_0</tabstop>
|
||||
<tabstop>gateway_in_1</tabstop>
|
||||
<tabstop>gateway_in_2</tabstop>
|
||||
<tabstop>gateway_in_3</tabstop>
|
||||
<tabstop>prefix_len_in</tabstop>
|
||||
<tabstop>port_in</tabstop>
|
||||
<tabstop>update_btn</tabstop>
|
||||
<tabstop>cancel_btn</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>cancel_btn</sender>
|
||||
<signal>clicked()</signal>
|
||||
<receiver>Update_Network_Settings_Form</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>340</x>
|
||||
<y>140</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>364</x>
|
||||
<y>96</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>update_btn</sender>
|
||||
<signal>clicked()</signal>
|
||||
<receiver>Update_Network_Settings_Form</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>258</x>
|
||||
<y>147</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>237</x>
|
||||
<y>99</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
194
pykirdy/pykirdy/ui/waitingspinnerwidget.py
Normal file
194
pykirdy/pykirdy/ui/waitingspinnerwidget.py
Normal file
@@ -0,0 +1,194 @@
|
||||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2012-2014 Alexander Turkin
|
||||
Copyright (c) 2014 William Hallatt
|
||||
Copyright (c) 2015 Jacob Dawid
|
||||
Copyright (c) 2016 Luca Weiss
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
"""
|
||||
|
||||
import math
|
||||
|
||||
from PyQt6.QtCore import *
|
||||
from PyQt6.QtGui import *
|
||||
from PyQt6.QtWidgets import *
|
||||
|
||||
|
||||
class QtWaitingSpinner(QWidget):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
# WAS IN initialize()
|
||||
self._color = QColor(Qt.GlobalColor.black)
|
||||
self._roundness = 100.0
|
||||
self._minimumTrailOpacity = 3.14159265358979323846
|
||||
self._trailFadePercentage = 80.0
|
||||
self._revolutionsPerSecond = 1.57079632679489661923
|
||||
self._numberOfLines = 20
|
||||
self._lineLength = 5
|
||||
self._lineWidth = 2
|
||||
self._innerRadius = 5
|
||||
self._currentCounter = 0
|
||||
|
||||
self._timer = QTimer(self)
|
||||
self._timer.timeout.connect(self.rotate)
|
||||
self.updateSize()
|
||||
self.updateTimer()
|
||||
# END initialize()
|
||||
|
||||
self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
|
||||
|
||||
def paintEvent(self, QPaintEvent):
|
||||
painter = QPainter(self)
|
||||
painter.fillRect(self.rect(), Qt.GlobalColor.transparent)
|
||||
painter.setRenderHint(QPainter.RenderHint.Antialiasing, True)
|
||||
|
||||
if self._currentCounter >= self._numberOfLines:
|
||||
self._currentCounter = 0
|
||||
|
||||
painter.setPen(Qt.PenStyle.NoPen)
|
||||
for i in range(0, self._numberOfLines):
|
||||
painter.save()
|
||||
painter.translate(self._innerRadius + self._lineLength, self._innerRadius + self._lineLength)
|
||||
rotateAngle = float(360 * i) / float(self._numberOfLines)
|
||||
painter.rotate(rotateAngle)
|
||||
painter.translate(self._innerRadius, 0)
|
||||
distance = self.lineCountDistanceFromPrimary(i, self._currentCounter, self._numberOfLines)
|
||||
color = self.currentLineColor(distance, self._numberOfLines, self._trailFadePercentage,
|
||||
self._minimumTrailOpacity, self._color)
|
||||
painter.setBrush(color)
|
||||
painter.drawRoundedRect(QRect(0, int(-self._lineWidth / 2), self._lineLength, self._lineWidth), self._roundness,
|
||||
self._roundness, Qt.SizeMode.RelativeSize)
|
||||
painter.restore()
|
||||
|
||||
def start(self):
|
||||
if not self._timer.isActive():
|
||||
self._timer.start()
|
||||
self._currentCounter = 0
|
||||
|
||||
def stop(self):
|
||||
if self._timer.isActive():
|
||||
self._timer.stop()
|
||||
self._currentCounter = 0
|
||||
|
||||
def setNumberOfLines(self, lines):
|
||||
self._numberOfLines = lines
|
||||
self._currentCounter = 0
|
||||
self.updateTimer()
|
||||
|
||||
def setLineLength(self, length):
|
||||
self._lineLength = length
|
||||
self.updateSize()
|
||||
|
||||
def setLineWidth(self, width):
|
||||
self._lineWidth = width
|
||||
self.updateSize()
|
||||
|
||||
def setInnerRadius(self, radius):
|
||||
self._innerRadius = radius
|
||||
self.updateSize()
|
||||
|
||||
def color(self):
|
||||
return self._color
|
||||
|
||||
def roundness(self):
|
||||
return self._roundness
|
||||
|
||||
def minimumTrailOpacity(self):
|
||||
return self._minimumTrailOpacity
|
||||
|
||||
def trailFadePercentage(self):
|
||||
return self._trailFadePercentage
|
||||
|
||||
def revolutionsPersSecond(self):
|
||||
return self._revolutionsPerSecond
|
||||
|
||||
def numberOfLines(self):
|
||||
return self._numberOfLines
|
||||
|
||||
def lineLength(self):
|
||||
return self._lineLength
|
||||
|
||||
def lineWidth(self):
|
||||
return self._lineWidth
|
||||
|
||||
def innerRadius(self):
|
||||
return self._innerRadius
|
||||
|
||||
def setRoundness(self, roundness):
|
||||
self._roundness = max(0.0, min(100.0, roundness))
|
||||
|
||||
def setColor(self, color=Qt.GlobalColor.black):
|
||||
self._color = QColor(color)
|
||||
|
||||
def setRevolutionsPerSecond(self, revolutionsPerSecond):
|
||||
self._revolutionsPerSecond = revolutionsPerSecond
|
||||
self.updateTimer()
|
||||
|
||||
def setTrailFadePercentage(self, trail):
|
||||
self._trailFadePercentage = trail
|
||||
|
||||
def setMinimumTrailOpacity(self, minimumTrailOpacity):
|
||||
self._minimumTrailOpacity = minimumTrailOpacity
|
||||
|
||||
def rotate(self):
|
||||
self._currentCounter += 1
|
||||
if self._currentCounter >= self._numberOfLines:
|
||||
self._currentCounter = 0
|
||||
self.update()
|
||||
|
||||
def updateSize(self):
|
||||
self.size = (self._innerRadius + self._lineLength) * 2
|
||||
self.setFixedSize(self.size, self.size)
|
||||
|
||||
def updateTimer(self):
|
||||
self._timer.setInterval(int(1000 / (self._numberOfLines * self._revolutionsPerSecond)))
|
||||
|
||||
def lineCountDistanceFromPrimary(self, current, primary, totalNrOfLines):
|
||||
distance = primary - current
|
||||
if distance < 0:
|
||||
distance += totalNrOfLines
|
||||
return distance
|
||||
|
||||
def currentLineColor(self, countDistance, totalNrOfLines, trailFadePerc, minOpacity, colorinput):
|
||||
color = QColor(colorinput)
|
||||
if countDistance == 0:
|
||||
return color
|
||||
minAlphaF = minOpacity / 100.0
|
||||
distanceThreshold = int(math.ceil((totalNrOfLines - 1) * trailFadePerc / 100.0))
|
||||
if countDistance > distanceThreshold:
|
||||
color.setAlphaF(minAlphaF)
|
||||
else:
|
||||
alphaDiff = color.alphaF() - minAlphaF
|
||||
gradient = alphaDiff / float(distanceThreshold + 1)
|
||||
resultAlpha = color.alphaF() - gradient * countDistance
|
||||
# If alpha is out of bounds, clip it.
|
||||
resultAlpha = min(1.0, max(0.0, resultAlpha))
|
||||
color.setAlphaF(resultAlpha)
|
||||
return color
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = QApplication([])
|
||||
waiting_spinner = QtWaitingSpinner()
|
||||
waiting_spinner.show()
|
||||
waiting_spinner.start()
|
||||
app.exec()
|
||||
22
pykirdy/pyproject.toml
Normal file
22
pykirdy/pyproject.toml
Normal file
@@ -0,0 +1,22 @@
|
||||
[build-system]
|
||||
requires = ["setuptools"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "pykirdy"
|
||||
version = "0.0"
|
||||
authors = [{name = "M-Labs"}]
|
||||
description = "Python utilities for the Sinara 1550 Kirdy"
|
||||
urls.Repository = "https://git.m-labs.hk/M-Labs/kirdy"
|
||||
license = {text = "GPLv3"}
|
||||
dependencies = [
|
||||
"aenum >= 3.1.15",
|
||||
"numpy >= 2.0.0",
|
||||
"pyqtgraph >= 0.13.7",
|
||||
"pyqt6 >= 6.8.0",
|
||||
"qasync >= 0.27.1",
|
||||
"pglive >= 0.8.3",
|
||||
]
|
||||
|
||||
[project.gui-scripts]
|
||||
kirdy_qt = "pykirdy.kirdy_qt:main"
|
||||
64
rustfmt.toml
Normal file
64
rustfmt.toml
Normal file
@@ -0,0 +1,64 @@
|
||||
max_width = 120
|
||||
hard_tabs = false
|
||||
tab_spaces = 4
|
||||
newline_style = "Auto"
|
||||
use_small_heuristics = "Default"
|
||||
indent_style = "Block"
|
||||
wrap_comments = false
|
||||
format_code_in_doc_comments = false
|
||||
comment_width = 100
|
||||
normalize_comments = false
|
||||
normalize_doc_attributes = false
|
||||
format_strings = true
|
||||
format_macro_matchers = true
|
||||
format_macro_bodies = true
|
||||
empty_item_single_line = true
|
||||
struct_lit_single_line = true
|
||||
fn_single_line = false
|
||||
where_single_line = true
|
||||
imports_indent = "Visual"
|
||||
imports_layout = "Mixed"
|
||||
imports_granularity="Crate"
|
||||
group_imports = "StdExternalCrate"
|
||||
reorder_imports = true
|
||||
reorder_modules = true
|
||||
reorder_impl_items = false
|
||||
type_punctuation_density = "Wide"
|
||||
space_before_colon = false
|
||||
space_after_colon = true
|
||||
spaces_around_ranges = false
|
||||
binop_separator = "Front"
|
||||
remove_nested_parens = true
|
||||
combine_control_expr = true
|
||||
overflow_delimited_expr = false
|
||||
struct_field_align_threshold = 0
|
||||
enum_discrim_align_threshold = 0
|
||||
match_arm_blocks = true
|
||||
match_arm_leading_pipes = "Never"
|
||||
force_multiline_blocks = false
|
||||
fn_params_layout = "Tall"
|
||||
brace_style = "SameLineWhere"
|
||||
control_brace_style = "AlwaysSameLine"
|
||||
trailing_semicolon = true
|
||||
trailing_comma = "Vertical"
|
||||
match_block_trailing_comma = false
|
||||
blank_lines_upper_bound = 1
|
||||
blank_lines_lower_bound = 0
|
||||
edition = "2018"
|
||||
version = "Two"
|
||||
inline_attribute_width = 0
|
||||
merge_derives = true
|
||||
use_try_shorthand = false
|
||||
use_field_init_shorthand = false
|
||||
force_explicit_abi = true
|
||||
condense_wildcard_suffixes = false
|
||||
color = "Auto"
|
||||
unstable_features = false
|
||||
disable_all_formatting = false
|
||||
skip_children = false
|
||||
hide_parse_errors = false
|
||||
error_on_line_overflow = false
|
||||
error_on_unformatted = false
|
||||
ignore = []
|
||||
emit_mode = "Files"
|
||||
make_backup = false
|
||||
@@ -1,20 +1,32 @@
|
||||
use super::{gpio, sys_timer, usb};
|
||||
use crate::laser_diode::current_sources::*;
|
||||
use fugit::ExtU32;
|
||||
use log::info;
|
||||
use stm32f4xx_hal::{
|
||||
pac::{CorePeripherals, Peripherals},
|
||||
rcc::RccExt,
|
||||
time::MegaHertz,
|
||||
watchdog::IndependentWatchdog,
|
||||
};
|
||||
use log::{debug, info};
|
||||
use stm32f4xx_hal::{dma::StreamsTuple,
|
||||
pac::{CorePeripherals, Peripherals},
|
||||
rcc::RccExt,
|
||||
syscfg::SysCfgExt,
|
||||
time::MegaHertz,
|
||||
timer::TimerExt,
|
||||
watchdog::IndependentWatchdog};
|
||||
use uom::si::{electric_current::{ampere, milliampere},
|
||||
f32::ElectricCurrent};
|
||||
|
||||
use super::{gpio, sys_timer, usb};
|
||||
use crate::{device::{flash_store::{self, FlashStore},
|
||||
hw_rev::HWRev},
|
||||
laser_diode::{laser_diode::LdDrive, ld_ctrl::*},
|
||||
net::net::{IpSettings, ServerHandle},
|
||||
thermostat::{max1968::MAX1968, thermostat::Thermostat},
|
||||
DeviceSettings};
|
||||
|
||||
#[cfg(not(feature = "semihosting"))]
|
||||
const WATCHDOG_PERIOD: u32 = 1000;
|
||||
const WATCHDOG_PERIOD: u32 = 4000;
|
||||
#[cfg(feature = "semihosting")]
|
||||
const WATCHDOG_PERIOD: u32 = 30000;
|
||||
|
||||
pub fn bootup(mut core_perif: CorePeripherals, perif: Peripherals) -> IndependentWatchdog {
|
||||
pub fn bootup(
|
||||
mut core_perif: CorePeripherals,
|
||||
perif: Peripherals,
|
||||
) -> (IndependentWatchdog, FlashStore, HWRev, LdDrive, Thermostat) {
|
||||
core_perif.SCB.enable_icache();
|
||||
core_perif.SCB.enable_dcache(&mut core_perif.CPUID);
|
||||
|
||||
@@ -25,42 +37,122 @@ pub fn bootup(mut core_perif: CorePeripherals, perif: Peripherals) -> Independen
|
||||
.use_hse(MegaHertz::from_raw(8).convert())
|
||||
.sysclk(MegaHertz::from_raw(168).convert())
|
||||
.hclk(MegaHertz::from_raw(168).convert())
|
||||
.pclk1(MegaHertz::from_raw(32).convert())
|
||||
.pclk2(MegaHertz::from_raw(64).convert())
|
||||
.pclk1(MegaHertz::from_raw(42).convert())
|
||||
.pclk2(MegaHertz::from_raw(84).convert())
|
||||
.freeze();
|
||||
|
||||
sys_timer::setup(core_perif.SYST, clocks);
|
||||
|
||||
let (_eth_pins, usb, current_source_phy) = gpio::setup(
|
||||
let mut syscfg = perif.SYSCFG.constrain();
|
||||
let mut exti = perif.EXTI;
|
||||
|
||||
let (
|
||||
mut hw_rev,
|
||||
eth_pins,
|
||||
eth_mgmt_pins,
|
||||
usb,
|
||||
current_source_phy,
|
||||
ad5680_phy,
|
||||
ad7172_phy,
|
||||
max1968_phy,
|
||||
pd_mon_phy,
|
||||
ld_hw_variant,
|
||||
eeprom_phy,
|
||||
) = gpio::setup(
|
||||
clocks,
|
||||
perif.TIM4,
|
||||
perif.GPIOA,
|
||||
perif.GPIOB,
|
||||
perif.GPIOC,
|
||||
perif.GPIOD,
|
||||
perif.GPIOG,
|
||||
perif.GPIOE,
|
||||
perif.SPI1,
|
||||
perif.SPI2,
|
||||
perif.SPI3,
|
||||
perif.I2C3,
|
||||
perif.OTG_FS_GLOBAL,
|
||||
perif.OTG_FS_DEVICE,
|
||||
perif.OTG_FS_PWRCLK,
|
||||
&mut syscfg,
|
||||
&mut exti,
|
||||
);
|
||||
|
||||
usb::State::setup(usb);
|
||||
|
||||
let mut laser = CurrentSource {
|
||||
phy: current_source_phy,
|
||||
setting: CurrentSourceSettings {
|
||||
output_current: 0.0,
|
||||
},
|
||||
};
|
||||
debug!("Setting up TEC");
|
||||
let dma2_stream = StreamsTuple::new(perif.DMA2);
|
||||
let tec_driver = MAX1968::new(
|
||||
max1968_phy,
|
||||
ad5680_phy,
|
||||
perif.ADC1,
|
||||
perif.ADC2,
|
||||
dma2_stream.2,
|
||||
dma2_stream.3,
|
||||
);
|
||||
let mut thermostat = Thermostat::new(tec_driver, ad7172_phy);
|
||||
thermostat.setup();
|
||||
thermostat.calibrate_dac_value();
|
||||
thermostat.set_i(ElectricCurrent::new::<ampere>(0.0));
|
||||
|
||||
debug!("Setting up Laser Driver");
|
||||
let current_source = LdCtrl::new(current_source_phy);
|
||||
let mut laser = LdDrive::new(
|
||||
current_source,
|
||||
perif.ADC3,
|
||||
perif.TIM2.counter(&clocks),
|
||||
pd_mon_phy,
|
||||
ld_hw_variant,
|
||||
&mut syscfg,
|
||||
&mut exti,
|
||||
);
|
||||
laser.setup();
|
||||
laser.set_current(0.1).unwrap();
|
||||
laser.ld_set_i(ElectricCurrent::new::<ampere>(0.0));
|
||||
laser.set_pd_i_limit(ElectricCurrent::new::<milliampere>(2.5));
|
||||
laser.set_pd_mon_calibrated_vdda(thermostat.get_calibrated_vdda());
|
||||
|
||||
debug!("Setting up Internal Flash Driver");
|
||||
let flash_store = flash_store::store(perif.FLASH);
|
||||
|
||||
let mut ip_settings: IpSettings = IpSettings::default();
|
||||
let device_settings: DeviceSettings;
|
||||
match flash_store.read_value("Device") {
|
||||
Ok(Some(config)) => {
|
||||
device_settings = config;
|
||||
ip_settings = device_settings.ip_settings;
|
||||
debug!("Found Device Settings");
|
||||
}
|
||||
Ok(None) => {
|
||||
debug!("Flash does not have IP Settings");
|
||||
}
|
||||
Err(e) => {
|
||||
debug!("Cannot Store Flash: {:?}", e);
|
||||
}
|
||||
}
|
||||
|
||||
debug!("Setting up ETH");
|
||||
let mac_addr = hw_rev.get_mac_address(eeprom_phy);
|
||||
let ethernet_parts_in = stm32_eth::PartsIn {
|
||||
dma: perif.ETHERNET_DMA,
|
||||
mac: perif.ETHERNET_MAC,
|
||||
mmc: perif.ETHERNET_MMC,
|
||||
ptp: perif.ETHERNET_PTP,
|
||||
};
|
||||
ServerHandle::new(
|
||||
eth_pins,
|
||||
eth_mgmt_pins,
|
||||
ethernet_parts_in,
|
||||
clocks,
|
||||
perif.TIM5.counter(&clocks),
|
||||
mac_addr,
|
||||
ip_settings,
|
||||
);
|
||||
|
||||
debug!("Setting Watchdog");
|
||||
let mut wd = IndependentWatchdog::new(perif.IWDG);
|
||||
wd.start(WATCHDOG_PERIOD.millis());
|
||||
wd.feed();
|
||||
|
||||
info!("Kirdy setup complete");
|
||||
|
||||
wd
|
||||
(wd, flash_store, hw_rev, laser, thermostat)
|
||||
}
|
||||
|
||||
47
src/device/dfu.rs
Normal file
47
src/device/dfu.rs
Normal file
@@ -0,0 +1,47 @@
|
||||
use core::arch::asm;
|
||||
|
||||
use cortex_m_rt::pre_init;
|
||||
use stm32f4xx_hal::pac::{RCC, SYSCFG};
|
||||
|
||||
const DFU_TRIG_MSG: u32 = 0xDECAFBAD;
|
||||
|
||||
extern "C" {
|
||||
// This symbol comes from memory.x
|
||||
static mut _dfu_msg: u32;
|
||||
}
|
||||
|
||||
pub unsafe fn set_dfu_trigger() {
|
||||
_dfu_msg = DFU_TRIG_MSG;
|
||||
}
|
||||
|
||||
/// Called by reset handler in lib.rs immediately after reset.
|
||||
/// This function should not be called outside of reset handler as
|
||||
/// bootloader expects MCU to be in reset state when called.
|
||||
#[cfg(target_arch = "arm")]
|
||||
#[pre_init]
|
||||
unsafe fn __pre_init() {
|
||||
if _dfu_msg == DFU_TRIG_MSG {
|
||||
_dfu_msg = 0x00000000;
|
||||
|
||||
// Enable system config controller clock
|
||||
let rcc = &*RCC::ptr();
|
||||
rcc.apb2enr.modify(|_, w| w.syscfgen().set_bit());
|
||||
|
||||
// Bypass BOOT pins and remap bootloader to 0x00000000
|
||||
let syscfg = &*SYSCFG::ptr();
|
||||
syscfg.memrm.write(|w| w.mem_mode().bits(0b01));
|
||||
|
||||
// Impose instruction and memory barriers
|
||||
cortex_m::asm::isb();
|
||||
cortex_m::asm::dsb();
|
||||
|
||||
asm!(
|
||||
// Set stack pointer to bootloader location
|
||||
"LDR R0, =0x1FFF0000",
|
||||
"LDR SP,[R0, #0]",
|
||||
// Jump to bootloader
|
||||
"LDR R0,[R0, #4]",
|
||||
"BX R0",
|
||||
);
|
||||
}
|
||||
}
|
||||
24
src/device/eeprom.rs
Normal file
24
src/device/eeprom.rs
Normal file
@@ -0,0 +1,24 @@
|
||||
use stm32f4xx_hal::i2c::{self, I2c3};
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type EEPROM_phy = I2c3;
|
||||
|
||||
pub struct EEPROM {
|
||||
i2c: I2c3,
|
||||
}
|
||||
|
||||
const EEPROM_I2C_ADDR: u8 = 0x50;
|
||||
const EUI48_ADDR: u8 = 0xFA;
|
||||
|
||||
impl EEPROM {
|
||||
pub fn new(i2c: EEPROM_phy) -> Self {
|
||||
EEPROM { i2c: i2c }
|
||||
}
|
||||
|
||||
pub fn read_eui_48_addr(mut self) -> Result<[u8; 6], i2c::Error> {
|
||||
let mut buffer: [u8; 6] = [0; 6];
|
||||
self.i2c.write(EEPROM_I2C_ADDR, &[EUI48_ADDR])?;
|
||||
self.i2c.read(EEPROM_I2C_ADDR, &mut buffer)?;
|
||||
Ok(buffer)
|
||||
}
|
||||
}
|
||||
58
src/device/flash_store.rs
Normal file
58
src/device/flash_store.rs
Normal file
@@ -0,0 +1,58 @@
|
||||
use log::error;
|
||||
use sfkv::{Store, StoreBackend};
|
||||
use stm32f4xx_hal::{flash::{Error, FlashExt},
|
||||
pac::FLASH};
|
||||
|
||||
// Last flash sector is used to avoid overwriting the code in flash.
|
||||
pub const FLASH_SECTOR: u8 = 11;
|
||||
pub const FLASH_SECTOR_11_OFFSET: u32 = 0xE0000;
|
||||
|
||||
/// Only 16 KiB out of 128KiB in the Sector is used to save RAM
|
||||
pub const RESERVED_MEMORY: usize = 0x4000;
|
||||
static mut BACKUP_SPACE: [u8; RESERVED_MEMORY] = [0; RESERVED_MEMORY];
|
||||
|
||||
pub struct FlashBackend {
|
||||
flash: FLASH,
|
||||
}
|
||||
|
||||
fn get_offset() -> usize {
|
||||
FLASH_SECTOR_11_OFFSET as usize
|
||||
}
|
||||
|
||||
impl StoreBackend for FlashBackend {
|
||||
type Data = [u8];
|
||||
|
||||
fn data(&self) -> &Self::Data {
|
||||
&self.flash.read()[get_offset()..(get_offset() + RESERVED_MEMORY)]
|
||||
}
|
||||
|
||||
type Error = Error;
|
||||
fn erase(&mut self) -> Result<(), Self::Error> {
|
||||
self.flash.unlocked().erase(FLASH_SECTOR)
|
||||
}
|
||||
|
||||
fn program(&mut self, offset: usize, payload: &[u8]) -> Result<(), Self::Error> {
|
||||
self.flash.unlocked().program(get_offset() + offset, payload.iter())
|
||||
}
|
||||
|
||||
fn backup_space(&self) -> &'static mut [u8] {
|
||||
unsafe { BACKUP_SPACE.as_mut() }
|
||||
}
|
||||
}
|
||||
|
||||
pub type FlashStore = Store<FlashBackend>;
|
||||
|
||||
pub fn store(flash: FLASH) -> FlashStore {
|
||||
let backend = FlashBackend { flash };
|
||||
let mut store = FlashStore::new(backend);
|
||||
|
||||
match store.get_bytes_used() {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
error!("corrupt store, erasing. error: {:?}", e);
|
||||
let _ = store.erase().map_err(|e| error!("flash erase failed: {:?}", e));
|
||||
}
|
||||
}
|
||||
|
||||
store
|
||||
}
|
||||
@@ -1,48 +1,157 @@
|
||||
use crate::laser_diode::current_sources::*;
|
||||
use fugit::RateExtU32;
|
||||
use fugit::HertzU32;
|
||||
use stm32_eth::EthPins;
|
||||
use stm32f4xx_hal::{
|
||||
gpio::{gpioa::*, gpiob::*, gpioc::*, gpiog::*, GpioExt, Input},
|
||||
otg_fs::USB,
|
||||
pac::{GPIOA, GPIOB, GPIOC, GPIOD, GPIOG, OTG_FS_DEVICE, OTG_FS_GLOBAL, OTG_FS_PWRCLK, SPI2},
|
||||
rcc::Clocks,
|
||||
spi,
|
||||
spi::{NoMiso, Spi},
|
||||
};
|
||||
use stm32f4xx_hal::{gpio::{alt::otg_fs::{Dm, Dp},
|
||||
gpioa::*,
|
||||
gpiob::*,
|
||||
gpioc::*,
|
||||
GpioExt, Input, PinExt, Speed},
|
||||
i2c::{self, I2c},
|
||||
otg_fs::USB,
|
||||
pac::{EXTI, GPIOA, GPIOB, GPIOC, GPIOD, GPIOE, I2C3, OTG_FS_DEVICE, OTG_FS_GLOBAL, OTG_FS_PWRCLK,
|
||||
SPI1, SPI2, SPI3, TIM4},
|
||||
rcc::Clocks,
|
||||
spi::{NoMiso, Spi},
|
||||
syscfg::SysCfg,
|
||||
timer::{pwm::PwmExt, Channel1, Channel2, Channel3}};
|
||||
|
||||
pub type EthernetPins =
|
||||
EthPins<PA1<Input>, PA7<Input>, PB11<Input>, PG13<Input>, PB13<Input>, PC4<Input>, PC5<Input>>;
|
||||
use crate::{device::{eeprom::EEPROM_phy,
|
||||
hw_rev::{HWRev, HwRevPins},
|
||||
power_rail_monitor::{LdoMgmt, PinDescription, PowerRail}},
|
||||
laser_diode::{ld_ctrl::{self, LdCtrlPhy},
|
||||
ld_hw_variant::{LdHWVariantPins, LdHwVariant},
|
||||
ld_pwr_exc_protector::LdPwrExcProtectorPhy,
|
||||
max5719},
|
||||
net::net::EthernetMgmtPins,
|
||||
thermostat::{ad5680, ad7172,
|
||||
max1968::{self, MAX1968Phy, MAX1968PinSet, ShdnPinType, PWM_FREQ_KHZ}}};
|
||||
|
||||
pub type EthernetPins = EthPins<PA1<Input>, PA7<Input>, PB11<Input>, PB12<Input>, PB13<Input>, PC4<Input>, PC5<Input>>;
|
||||
|
||||
pub fn setup(
|
||||
clocks: Clocks,
|
||||
mut clocks: Clocks,
|
||||
tim4: TIM4,
|
||||
gpioa: GPIOA,
|
||||
gpiob: GPIOB,
|
||||
gpioc: GPIOC,
|
||||
gpiod: GPIOD,
|
||||
gpiog: GPIOG,
|
||||
gpioe: GPIOE,
|
||||
spi1: SPI1,
|
||||
spi2: SPI2,
|
||||
spi3: SPI3,
|
||||
i2c3: I2C3,
|
||||
otg_fs_global: OTG_FS_GLOBAL,
|
||||
otg_fs_device: OTG_FS_DEVICE,
|
||||
otg_fs_pwrclk: OTG_FS_PWRCLK,
|
||||
syscfg: &mut SysCfg,
|
||||
exti: &mut EXTI,
|
||||
) -> (
|
||||
HWRev,
|
||||
EthernetPins,
|
||||
EthernetMgmtPins,
|
||||
USB,
|
||||
CurrentSourcePhyConstruct<CurrentSourcePhyCh0>,
|
||||
// photo_diode_phy,
|
||||
// thermostat_phy
|
||||
LdCtrlPhy<ld_ctrl::Channel0>,
|
||||
ad5680::DacPhy,
|
||||
ad7172::AdcPhy,
|
||||
MAX1968Phy<max1968::Channel0>,
|
||||
LdPwrExcProtectorPhy,
|
||||
LdHwVariant,
|
||||
EEPROM_phy,
|
||||
) {
|
||||
let gpioa = gpioa.split();
|
||||
let gpiob = gpiob.split();
|
||||
let gpioc = gpioc.split();
|
||||
let gpiod = gpiod.split();
|
||||
let gpiog = gpiog.split();
|
||||
let gpioe = gpioe.split();
|
||||
|
||||
let mut hw_rev = HWRev::detect_hw_rev(HwRevPins {
|
||||
h0: gpioe.pe8.into_pull_down_input(),
|
||||
h1: gpioe.pe9.into_pull_down_input(),
|
||||
h2: gpioe.pe10.into_pull_down_input(),
|
||||
});
|
||||
|
||||
let ld_hw_variant = LdHwVariant::detect_hw_variant(
|
||||
hw_rev,
|
||||
LdHWVariantPins {
|
||||
board_hw_variant: gpioe.pe11.into_pull_down_input(),
|
||||
aux_psu_variant0: gpioe.pe12.into_pull_up_input(),
|
||||
aux_psu_present_n: gpioe.pe13.into_pull_up_input(),
|
||||
},
|
||||
);
|
||||
|
||||
let irq_number_pe1 = gpioe.pe1.interrupt();
|
||||
let irq_number_pe2 = gpioe.pe2.interrupt();
|
||||
let irq_number_pe3 = gpioe.pe3.interrupt();
|
||||
let irq_number_pe4 = gpioe.pe4.interrupt();
|
||||
let irq_number_pe5 = gpioe.pe4.interrupt();
|
||||
|
||||
let p3v3a_ldo = LdoMgmt {
|
||||
en: gpioa.pa10.into_push_pull_output(),
|
||||
pg: gpioe.pe4.into_pull_up_input(),
|
||||
irq_number: irq_number_pe4,
|
||||
pwr_rail: PowerRail::P3V3A,
|
||||
};
|
||||
|
||||
let p5v0a_ldo = LdoMgmt {
|
||||
en: gpiob.pb2.into_push_pull_output(),
|
||||
pg: gpioe.pe5.into_pull_up_input(),
|
||||
irq_number: irq_number_pe5,
|
||||
pwr_rail: PowerRail::P5V0A,
|
||||
};
|
||||
|
||||
let p9v0a_ldo = LdoMgmt {
|
||||
en: gpiob.pb9.into_push_pull_output(),
|
||||
pg: gpioe.pe1.into_pull_up_input(),
|
||||
irq_number: irq_number_pe1,
|
||||
pwr_rail: PowerRail::P9V0A,
|
||||
};
|
||||
|
||||
let p15va_ldo = LdoMgmt {
|
||||
en: gpioc.pc2.into_push_pull_output(),
|
||||
pg: gpioe.pe3.into_pull_up_input(),
|
||||
irq_number: irq_number_pe3,
|
||||
pwr_rail: PowerRail::P15VA,
|
||||
};
|
||||
|
||||
let n6v0_ldo = LdoMgmt {
|
||||
en: gpioc.pc13.into_push_pull_output(),
|
||||
pg: gpioe.pe2.into_pull_up_input(),
|
||||
irq_number: irq_number_pe2,
|
||||
pwr_rail: PowerRail::N6V0A,
|
||||
};
|
||||
|
||||
let thermostat_shdn: ShdnPinType = gpioa.pa5.into_push_pull_output();
|
||||
|
||||
let ld_pwr_good_pin = hw_rev.setup_ldo_pwr_stage(
|
||||
p3v3a_ldo,
|
||||
p5v0a_ldo,
|
||||
p9v0a_ldo,
|
||||
p15va_ldo,
|
||||
n6v0_ldo,
|
||||
gpioe.pe0.into_pull_up_input(),
|
||||
PinDescription {
|
||||
pin_id: thermostat_shdn.pin_id(),
|
||||
port_id: thermostat_shdn.port_id(),
|
||||
},
|
||||
syscfg,
|
||||
exti,
|
||||
);
|
||||
|
||||
let eeprom_phy = I2c::new(
|
||||
i2c3,
|
||||
(gpioa.pa8.into_open_drain_output(), gpioc.pc9.into_open_drain_output()),
|
||||
i2c::Mode::Fast {
|
||||
frequency: HertzU32::from_raw(400_000),
|
||||
duty_cycle: i2c::DutyCycle::Ratio2to1,
|
||||
},
|
||||
&mut clocks,
|
||||
);
|
||||
|
||||
let usb = USB {
|
||||
usb_global: otg_fs_global,
|
||||
usb_device: otg_fs_device,
|
||||
usb_pwrclk: otg_fs_pwrclk,
|
||||
pin_dm: gpioa.pa11.into_alternate(),
|
||||
pin_dp: gpioa.pa12.into_alternate(),
|
||||
pin_dm: Dm::PA11(gpioa.pa11.into_alternate()),
|
||||
pin_dp: Dp::PA12(gpioa.pa12.into_alternate()),
|
||||
hclk: clocks.hclk(),
|
||||
};
|
||||
|
||||
@@ -50,32 +159,101 @@ pub fn setup(
|
||||
ref_clk: gpioa.pa1,
|
||||
crs: gpioa.pa7,
|
||||
tx_en: gpiob.pb11,
|
||||
tx_d0: gpiog.pg13,
|
||||
tx_d0: gpiob.pb12,
|
||||
tx_d1: gpiob.pb13,
|
||||
rx_d0: gpioc.pc4,
|
||||
rx_d1: gpioc.pc5,
|
||||
};
|
||||
|
||||
let current_source_phy = CurrentSourcePhyConstruct {
|
||||
max5719_spi: Spi::new(
|
||||
spi2,
|
||||
(
|
||||
gpiob.pb10.into_alternate(),
|
||||
NoMiso {},
|
||||
gpiob.pb15.into_alternate(),
|
||||
let mut eth_mgmt_pins = EthernetMgmtPins {
|
||||
mdio: gpioa.pa2.into_alternate::<11>(),
|
||||
mdc: gpioc.pc1.into_alternate::<11>(),
|
||||
};
|
||||
eth_mgmt_pins.mdio.set_speed(Speed::VeryHigh);
|
||||
eth_mgmt_pins.mdc.set_speed(Speed::VeryHigh);
|
||||
|
||||
let current_source_phy = LdCtrlPhy {
|
||||
dac: max5719::Dac::new(
|
||||
Spi::new(
|
||||
spi2,
|
||||
(gpiob.pb10.into_alternate(), NoMiso::new(), gpiob.pb15.into_alternate()),
|
||||
max5719::SPI_MODE,
|
||||
max5719::SPI_CLOCK_MHZ.convert(),
|
||||
&clocks,
|
||||
),
|
||||
spi::Mode {
|
||||
polarity: spi::Polarity::IdleLow,
|
||||
phase: spi::Phase::CaptureOnFirstTransition,
|
||||
},
|
||||
10_u32.MHz(),
|
||||
&clocks,
|
||||
gpiod.pd8.into_push_pull_output(),
|
||||
gpiob.pb14.into_push_pull_output(),
|
||||
),
|
||||
max5719_load: gpiob.pb14.into_push_pull_output(),
|
||||
max5719_cs: gpiod.pd8.into_push_pull_output(),
|
||||
current_source_ldo_en: gpiod.pd9.into_push_pull_output(),
|
||||
current_source_short: gpioa.pa4.into_push_pull_output(),
|
||||
current_source_short_pin: gpioa.pa4.into_push_pull_output(),
|
||||
termination_status_pin: gpiod.pd7.internal_pull_up(true),
|
||||
};
|
||||
|
||||
(eth_pins, usb, current_source_phy)
|
||||
let pd_mon_phy = LdPwrExcProtectorPhy {
|
||||
_pd_mon_ch0: gpioa.pa3.into_analog(),
|
||||
pwr_en_ch0: gpiod.pd9.into_push_pull_output(),
|
||||
pwr_pg_ch0: ld_pwr_good_pin,
|
||||
};
|
||||
|
||||
let pwm_chs = (
|
||||
Channel1::new(gpiob.pb6),
|
||||
Channel2::new(gpiob.pb7),
|
||||
Channel3::new(gpiob.pb8),
|
||||
);
|
||||
let (max_i_neg0, max_v0, max_i_pos0) = tim4.pwm_hz(pwm_chs, PWM_FREQ_KHZ.convert(), &clocks).split();
|
||||
|
||||
let max1968_phy = MAX1968Phy::new(MAX1968PinSet {
|
||||
shdn: thermostat_shdn,
|
||||
vref_pin: gpioa.pa6.into_analog(),
|
||||
itec_pin: gpiob.pb1.into_analog(),
|
||||
dac_feedback_pin: gpioc.pc0.into_analog(),
|
||||
vtec_pin: gpiob.pb0.into_analog(),
|
||||
max_v: max_v0,
|
||||
max_i_pos: max_i_pos0,
|
||||
max_i_neg: max_i_neg0,
|
||||
});
|
||||
|
||||
let ad5680_phy = ad5680::DacPhy {
|
||||
spi: Spi::new(
|
||||
spi1,
|
||||
(
|
||||
gpiob.pb3.into_alternate().speed(Speed::VeryHigh),
|
||||
NoMiso::new(),
|
||||
gpiob.pb5.into_alternate().speed(Speed::VeryHigh),
|
||||
),
|
||||
ad5680::SPI_MODE,
|
||||
ad5680::SPI_CLOCK_MHZ.convert(),
|
||||
&clocks,
|
||||
),
|
||||
sync: gpiob.pb4.into_push_pull_output(),
|
||||
};
|
||||
|
||||
let ad7172_phy = ad7172::Adc::new(
|
||||
Spi::new(
|
||||
spi3,
|
||||
(
|
||||
gpioc.pc10.into_alternate(),
|
||||
gpioc.pc11.into_alternate(),
|
||||
gpioc.pc12.into_alternate(),
|
||||
),
|
||||
ad7172::SPI_MODE,
|
||||
ad7172::SPI_CLOCK_MHZ.convert(),
|
||||
&clocks,
|
||||
),
|
||||
gpioa.pa15.into_push_pull_output(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
(
|
||||
hw_rev,
|
||||
eth_pins,
|
||||
eth_mgmt_pins,
|
||||
usb,
|
||||
current_source_phy,
|
||||
ad5680_phy,
|
||||
ad7172_phy,
|
||||
max1968_phy,
|
||||
pd_mon_phy,
|
||||
ld_hw_variant,
|
||||
eeprom_phy,
|
||||
)
|
||||
}
|
||||
|
||||
97
src/device/hw_rev.rs
Normal file
97
src/device/hw_rev.rs
Normal file
@@ -0,0 +1,97 @@
|
||||
use crc::{Crc, CRC_24_BLE};
|
||||
use log::warn;
|
||||
use miniconf::Tree;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use stm32f4xx_hal::{gpio::{Input, PE10, PE8, PE9},
|
||||
pac::EXTI,
|
||||
signature,
|
||||
syscfg::SysCfg};
|
||||
|
||||
use crate::{device::{eeprom::{EEPROM_phy, EEPROM},
|
||||
power_rail_monitor::*,
|
||||
sys_timer::sleep},
|
||||
laser_diode::ld_pwr_exc_protector::LdPwrPgPinType};
|
||||
|
||||
pub struct HwRevPins {
|
||||
pub h0: PE8<Input>,
|
||||
pub h1: PE9<Input>,
|
||||
pub h2: PE10<Input>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Tree)]
|
||||
pub struct HWRev {
|
||||
pub major: u8,
|
||||
pub minor: u8,
|
||||
}
|
||||
|
||||
impl HWRev {
|
||||
pub fn detect_hw_rev(hwrev_pins: HwRevPins) -> Self {
|
||||
let (h0, h1, h2) = (
|
||||
hwrev_pins.h0.is_high(),
|
||||
hwrev_pins.h1.is_high(),
|
||||
hwrev_pins.h2.is_high(),
|
||||
);
|
||||
match (h0, h1, h2) {
|
||||
(true, true, true) => HWRev { major: 0, minor: 3 },
|
||||
(false, true, true) => HWRev { major: 1, minor: 0 },
|
||||
(_, _, _) => HWRev { major: 0, minor: 0 },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup_ldo_pwr_stage(
|
||||
&mut self,
|
||||
p3v3a: LdoMgmt<P3v3aLdo>,
|
||||
p5v0a: LdoMgmt<P5v0aLdo>,
|
||||
p9v0a: LdoMgmt<P9v0aLdo>,
|
||||
p15va: LdoMgmt<P15vaLdo>,
|
||||
n6v0a: LdoMgmt<N6v0aLdo>,
|
||||
ld_pwr_gd_pin: LdPwrPgPinType,
|
||||
thermostat_shdn_pin: PinDescription,
|
||||
syscfg: &mut SysCfg,
|
||||
exti: &mut EXTI,
|
||||
) -> Option<LdPwrPgPinType> {
|
||||
// On Rev0_3, during power up, digital power rails are stabilized way before analog power rails
|
||||
// This causes improper initialization on any peripherals requiring calibrations
|
||||
// See Issue #32 on Kirdy Hw Repo
|
||||
if self.major == 0 && self.minor == 3 {
|
||||
sleep(5000);
|
||||
None
|
||||
} else {
|
||||
LdoPwrStage::setup(p3v3a, p5v0a, p9v0a, p15va, n6v0a, thermostat_shdn_pin);
|
||||
LdoPwrStage::startup();
|
||||
LdoPwrStage::irq_setup(syscfg, exti);
|
||||
Some(ld_pwr_gd_pin)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_mac_address(&mut self, eeprom_phy: EEPROM_phy) -> [u8; 6] {
|
||||
if self.major >= 1 {
|
||||
let eeprom = EEPROM::new(eeprom_phy);
|
||||
match eeprom.read_eui_48_addr() {
|
||||
Ok(eui48) => return eui48,
|
||||
Err(err) => {
|
||||
warn!("EEPROM Not Found: {:?}", err);
|
||||
warn!("Revert to generating MAC Address from STM32 UID.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// On Rev0_3, it lacks pre-allocated Mac Addresses accessible on PCB.
|
||||
// This functions generate a random Mac Address with 96bit unique UUID inside STM32
|
||||
// See Issue #36 on Kirdy Hw Repo
|
||||
let uid = signature::Uid::get();
|
||||
let mut uid_data: [u8; 12] = [0; 12];
|
||||
uid_data[0] = uid.x() as u8;
|
||||
uid_data[1] = (uid.x() >> 8) as u8;
|
||||
uid_data[2] = uid.y() as u8;
|
||||
uid_data[3] = (uid.y() >> 8) as u8;
|
||||
uid_data[4..11].clone_from_slice(uid.lot_num().as_bytes());
|
||||
|
||||
let crc: Crc<u32> = Crc::<u32>::new(&CRC_24_BLE);
|
||||
let mut digest = crc.digest();
|
||||
digest.update(&uid_data);
|
||||
let crc24 = digest.finalize();
|
||||
|
||||
[0x02, 0xE0, 0xD5, (crc24 >> 16) as u8, (crc24 >> 8) as u8, (crc24 as u8)]
|
||||
}
|
||||
}
|
||||
@@ -3,13 +3,15 @@ pub fn init_log() {
|
||||
use super::usb;
|
||||
static USB_LOGGER: usb::Logger = usb::Logger;
|
||||
let _ = log::set_logger(&USB_LOGGER);
|
||||
log::set_max_level(log::LevelFilter::Debug);
|
||||
// log::set_max_level(log::LevelFilter::Debug);
|
||||
log::set_max_level(log::LevelFilter::Trace);
|
||||
}
|
||||
|
||||
#[cfg(feature = "RTT")]
|
||||
pub fn init_log() {
|
||||
use super::rtt_logger;
|
||||
use rtt_target::rtt_init_print;
|
||||
|
||||
use super::rtt_logger;
|
||||
static RTT_LOGGER: rtt_logger::Logger = rtt_logger::Logger;
|
||||
rtt_init_print!();
|
||||
let _ = log::set_logger(&RTT_LOGGER);
|
||||
@@ -18,8 +20,8 @@ pub fn init_log() {
|
||||
|
||||
#[cfg(feature = "semihosting")]
|
||||
pub fn init_log() {
|
||||
use cortex_m_log::log::{init, Logger};
|
||||
use cortex_m_log::printer::semihosting::{hio::HStdout, InterruptOk};
|
||||
use cortex_m_log::{log::{init, Logger},
|
||||
printer::semihosting::{hio::HStdout, InterruptOk}};
|
||||
use log::LevelFilter;
|
||||
static mut LOGGER: Option<Logger<InterruptOk<HStdout>>> = None;
|
||||
let logger = Logger {
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
pub mod boot;
|
||||
pub mod dfu;
|
||||
pub mod eeprom;
|
||||
pub mod flash_store;
|
||||
pub mod gpio;
|
||||
pub mod hw_rev;
|
||||
pub mod log_setup;
|
||||
pub mod power_rail_monitor;
|
||||
pub mod rtt_logger;
|
||||
pub mod sys_timer;
|
||||
pub mod usb;
|
||||
|
||||
381
src/device/power_rail_monitor.rs
Normal file
381
src/device/power_rail_monitor.rs
Normal file
@@ -0,0 +1,381 @@
|
||||
use stm32f4xx_hal::{gpio::{gpioa::PA10,
|
||||
gpiob::{PB2, PB9},
|
||||
gpioc::{PC13, PC2},
|
||||
gpioe::{PE1, PE2, PE3, PE4, PE5},
|
||||
Edge::Falling,
|
||||
ExtiPin, Input, Output, PushPull},
|
||||
hal::digital::{InputPin, OutputPin},
|
||||
interrupt,
|
||||
pac::{Peripherals, EXTI, NVIC},
|
||||
syscfg::SysCfg};
|
||||
|
||||
use crate::{sys_timer::{self},
|
||||
Failure};
|
||||
|
||||
pub struct P3v3aLdo;
|
||||
pub struct P5v0aLdo;
|
||||
pub struct P9v0aLdo;
|
||||
pub struct N6v0aLdo;
|
||||
pub struct P15vaLdo;
|
||||
|
||||
pub trait LdoPins {
|
||||
type En: OutputPin;
|
||||
type Pg: InputPin + ExtiPin;
|
||||
}
|
||||
|
||||
impl LdoPins for P3v3aLdo {
|
||||
type En = PA10<Output<PushPull>>;
|
||||
type Pg = PE4<Input>;
|
||||
}
|
||||
|
||||
impl LdoPins for P5v0aLdo {
|
||||
type En = PB2<Output<PushPull>>;
|
||||
type Pg = PE5<Input>;
|
||||
}
|
||||
|
||||
impl LdoPins for P9v0aLdo {
|
||||
type En = PB9<Output<PushPull>>;
|
||||
type Pg = PE1<Input>;
|
||||
}
|
||||
|
||||
impl LdoPins for N6v0aLdo {
|
||||
type En = PC13<Output<PushPull>>;
|
||||
type Pg = PE2<Input>;
|
||||
}
|
||||
|
||||
impl LdoPins for P15vaLdo {
|
||||
type En = PC2<Output<PushPull>>;
|
||||
type Pg = PE3<Input>;
|
||||
}
|
||||
|
||||
static mut ANALOG_PWR_STAGE_MGMT: Option<LdoPwrStage> = None;
|
||||
|
||||
pub struct PinDescription {
|
||||
pub pin_id: u8,
|
||||
pub port_id: u8,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct LdoStatus {
|
||||
pub power_rail: PowerRail,
|
||||
pub ack: bool,
|
||||
}
|
||||
|
||||
impl Default for LdoStatus {
|
||||
fn default() -> Self {
|
||||
LdoStatus {
|
||||
power_rail: PowerRail::Unknown,
|
||||
ack: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LdoPwrStage {
|
||||
pub p3v3a: LdoMgmt<P3v3aLdo>,
|
||||
pub p5v0a: LdoMgmt<P5v0aLdo>,
|
||||
pub p9v0a: LdoMgmt<P9v0aLdo>,
|
||||
pub p15va: LdoMgmt<P15vaLdo>,
|
||||
pub n6v0a: LdoMgmt<N6v0aLdo>,
|
||||
pub status: Result<(), LdoStatus>,
|
||||
thermostat_shdn: PinDescription,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum PowerRail {
|
||||
Unknown,
|
||||
P3V3A,
|
||||
P5V0A,
|
||||
P8V0A,
|
||||
P9V0A,
|
||||
P15VA,
|
||||
N6V0A,
|
||||
}
|
||||
|
||||
impl PowerRail {
|
||||
pub fn failure(self) -> Failure {
|
||||
match self {
|
||||
PowerRail::Unknown => Failure::Unknown,
|
||||
PowerRail::P3V3A => Failure::P3v3aPwrFailure,
|
||||
PowerRail::P5V0A => Failure::P5v0aPwrFailure,
|
||||
PowerRail::P8V0A => Failure::P8v0aPwrFailure,
|
||||
PowerRail::P9V0A => Failure::P9v0aPwrFailure,
|
||||
PowerRail::P15VA => Failure::P15VaPwrFailure,
|
||||
PowerRail::N6V0A => Failure::N6v0aPwrFailure,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LdoMgmt<C: LdoPins> {
|
||||
pub en: C::En,
|
||||
pub pg: C::Pg,
|
||||
pub irq_number: interrupt,
|
||||
pub pwr_rail: PowerRail,
|
||||
}
|
||||
|
||||
const PWR_UP_TIMEOUT: u32 = 50;
|
||||
impl<C: LdoPins> LdoMgmt<C> {
|
||||
pub fn power_up(&mut self) {
|
||||
self.en.set_high().unwrap();
|
||||
}
|
||||
|
||||
pub fn irq_setup(&mut self, syscfg: &mut SysCfg, exti: &mut EXTI) {
|
||||
self.pg.make_interrupt_source(syscfg);
|
||||
self.pg.enable_interrupt(exti);
|
||||
self.pg.trigger_on_edge(exti, Falling);
|
||||
|
||||
cortex_m::interrupt::free(|_| {
|
||||
NVIC::unpend(self.irq_number);
|
||||
unsafe {
|
||||
NVIC::unmask(self.irq_number);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
pub fn pwr_good(&mut self) -> bool {
|
||||
self.pg.is_high().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/// Only Applicable for Hardware Rev1_0 or above
|
||||
impl LdoPwrStage {
|
||||
/// Analog Power Rail Power Tree
|
||||
///
|
||||
///
|
||||
///
|
||||
/// +------------+ +-------------+
|
||||
/// +-----| Digital 5V |------| Digital 3V3 |
|
||||
/// | +------------+ +-------------+
|
||||
/// |
|
||||
/// +-----------+ | +-------+
|
||||
/// | 12V INPUT |---------| P9V0A |
|
||||
/// +-----------+ | +-------+
|
||||
/// |
|
||||
/// | +-------+ +-------+ +-------+
|
||||
/// +-----| +9V |-------| P5V0A |-------| P3V3A |
|
||||
/// | +-------+ | +-------+ +-------+
|
||||
/// | |
|
||||
/// | | +-------+ +-------+
|
||||
/// | +----| 18V |-------| P15VA |
|
||||
/// | | +-------+ +-------+
|
||||
/// | | |
|
||||
/// | | +-------+ +-------+
|
||||
/// | | | -9V |-------| N6V0A |
|
||||
/// | | +-------+ +-------+
|
||||
/// | |
|
||||
/// | | +-------+
|
||||
/// | +----| P8V0A |
|
||||
/// | +-------+
|
||||
/// |
|
||||
/// | +------------------+
|
||||
/// +---------------------| P8V0A (AUX_PSU) |
|
||||
/// +------------------+
|
||||
/// Laser Diode Driver: 9VA, 15V, 3V3, 5VA, N6VA, 8VA
|
||||
/// Thermostat: Digital 5V, 5VA 3V3A
|
||||
///
|
||||
pub fn setup(
|
||||
p3v3a: LdoMgmt<P3v3aLdo>,
|
||||
p5v0a: LdoMgmt<P5v0aLdo>,
|
||||
p9v0a: LdoMgmt<P9v0aLdo>,
|
||||
p15va: LdoMgmt<P15vaLdo>,
|
||||
n6v0a: LdoMgmt<N6v0aLdo>,
|
||||
thermostat_shdn_pin_description: PinDescription,
|
||||
) {
|
||||
unsafe {
|
||||
ANALOG_PWR_STAGE_MGMT = Some(LdoPwrStage {
|
||||
p3v3a: p3v3a,
|
||||
p5v0a: p5v0a,
|
||||
p9v0a: p9v0a,
|
||||
p15va: p15va,
|
||||
n6v0a: n6v0a,
|
||||
status: Ok(()),
|
||||
thermostat_shdn: thermostat_shdn_pin_description,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn get() -> Option<&'static mut Self> {
|
||||
unsafe { ANALOG_PWR_STAGE_MGMT.as_mut() }
|
||||
}
|
||||
|
||||
pub fn startup() -> bool {
|
||||
if let Some(ref mut mgmt) = LdoPwrStage::get() {
|
||||
mgmt.p5v0a.power_up();
|
||||
mgmt.p9v0a.power_up();
|
||||
let timeout = sys_timer::now() + PWR_UP_TIMEOUT;
|
||||
while !(mgmt.p5v0a.pwr_good() & mgmt.p9v0a.pwr_good()) & (sys_timer::now() <= timeout) {}
|
||||
|
||||
mgmt.p3v3a.power_up();
|
||||
mgmt.p15va.power_up();
|
||||
mgmt.n6v0a.power_up();
|
||||
let timeout = sys_timer::now() + PWR_UP_TIMEOUT;
|
||||
while !(mgmt.p3v3a.pwr_good() & mgmt.p15va.pwr_good() & mgmt.n6v0a.pwr_good())
|
||||
& (sys_timer::now() <= timeout)
|
||||
{}
|
||||
|
||||
return LdoPwrStage::check_power_rail_status().is_ok();
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
pub fn irq_setup(syscfg: &mut SysCfg, exti: &mut EXTI) {
|
||||
if let Some(ref mut mgmt) = LdoPwrStage::get() {
|
||||
mgmt.p3v3a.irq_setup(syscfg, exti);
|
||||
mgmt.p5v0a.irq_setup(syscfg, exti);
|
||||
mgmt.p9v0a.irq_setup(syscfg, exti);
|
||||
mgmt.p15va.irq_setup(syscfg, exti);
|
||||
mgmt.n6v0a.irq_setup(syscfg, exti);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_pwr_rail<L: LdoPins>(ldo: &mut LdoMgmt<L>) -> Result<(), Failure> {
|
||||
if let Some(ref mut mgmt) = LdoPwrStage::get() {
|
||||
if !ldo.pwr_good() {
|
||||
cortex_m::interrupt::free(|_| {
|
||||
if mgmt.status.is_ok() || (mgmt.status.is_err_and(|s| s.ack & (ldo.pwr_rail != s.power_rail))) {
|
||||
mgmt.status = Err(LdoStatus {
|
||||
power_rail: ldo.pwr_rail,
|
||||
ack: false,
|
||||
});
|
||||
};
|
||||
});
|
||||
return Err(ldo.pwr_rail.failure());
|
||||
} else {
|
||||
cortex_m::interrupt::free(|_| {
|
||||
if mgmt.status.is_err_and(|s| s.ack & (ldo.pwr_rail == s.power_rail)){
|
||||
mgmt.status = Ok(());
|
||||
}
|
||||
});
|
||||
return Ok(());
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn check_power_rail_status() -> Result<(), Failure> {
|
||||
if let Some(ref mut mgmt) = LdoPwrStage::get() {
|
||||
LdoPwrStage::check_pwr_rail(&mut mgmt.p3v3a)?;
|
||||
LdoPwrStage::check_pwr_rail(&mut mgmt.p5v0a)?;
|
||||
LdoPwrStage::check_pwr_rail(&mut mgmt.p15va)?;
|
||||
LdoPwrStage::check_pwr_rail(&mut mgmt.p9v0a)?;
|
||||
LdoPwrStage::check_pwr_rail(&mut mgmt.n6v0a)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn clear_irq_bit(pwr_rail: PowerRail) {
|
||||
if let Some(ref mut mgmt) = LdoPwrStage::get() {
|
||||
match pwr_rail {
|
||||
PowerRail::P3V3A => {
|
||||
mgmt.p3v3a.pg.clear_interrupt_pending_bit();
|
||||
}
|
||||
PowerRail::P5V0A => {
|
||||
mgmt.p3v3a.pg.clear_interrupt_pending_bit();
|
||||
}
|
||||
PowerRail::P9V0A => {
|
||||
mgmt.p9v0a.pg.clear_interrupt_pending_bit();
|
||||
}
|
||||
PowerRail::P15VA => {
|
||||
mgmt.p15va.pg.clear_interrupt_pending_bit();
|
||||
}
|
||||
PowerRail::N6V0A => {
|
||||
mgmt.n6v0a.pg.clear_interrupt_pending_bit();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn irq_handler(pwr_rail: PowerRail) {
|
||||
if let Some(ref mut mgmt) = LdoPwrStage::get() {
|
||||
if mgmt.status.is_ok() || (mgmt.status.is_err_and(|s| s.ack & (pwr_rail != s.power_rail))) {
|
||||
mgmt.status = Err(LdoStatus {
|
||||
power_rail: pwr_rail,
|
||||
ack: false,
|
||||
});
|
||||
}
|
||||
|
||||
match mgmt.thermostat_shdn.port_id {
|
||||
0 => {
|
||||
unsafe {
|
||||
Peripherals::steal()
|
||||
.GPIOA
|
||||
.bsrr
|
||||
.write(|w| w.bits(1 << (mgmt.thermostat_shdn.pin_id + 16)))
|
||||
};
|
||||
}
|
||||
_ => {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger EXTI0 Interrupt to turn off Laser Diode Power
|
||||
unsafe {
|
||||
(*EXTI::ptr()).swier.write(|w| { w.swier0() }.set_bit());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_pwr_failure_irq() -> Result<(), Failure> {
|
||||
if let Some(ref mut mgmt) = LdoPwrStage::get() {
|
||||
let status: Result<(), LdoStatus> = mgmt.status.clone();
|
||||
match status {
|
||||
Ok(()) => return Ok(()),
|
||||
Err(s) => {
|
||||
return cortex_m::interrupt::free(|_| {
|
||||
if s.ack {
|
||||
let _ = LdoPwrStage::check_power_rail_status();
|
||||
Ok(())
|
||||
} else {
|
||||
mgmt.status = mgmt.status.map_err(|mut s| {
|
||||
s.ack = true;
|
||||
s
|
||||
});
|
||||
Err(s.power_rail.failure())
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[interrupt]
|
||||
fn EXTI1() {
|
||||
cortex_m::interrupt::free(|_| {
|
||||
LdoPwrStage::irq_handler(PowerRail::P9V0A);
|
||||
LdoPwrStage::clear_irq_bit(PowerRail::P9V0A)
|
||||
});
|
||||
}
|
||||
|
||||
#[interrupt]
|
||||
fn EXTI2() {
|
||||
cortex_m::interrupt::free(|_| {
|
||||
LdoPwrStage::irq_handler(PowerRail::N6V0A);
|
||||
LdoPwrStage::clear_irq_bit(PowerRail::N6V0A)
|
||||
});
|
||||
}
|
||||
|
||||
#[interrupt]
|
||||
fn EXTI3() {
|
||||
cortex_m::interrupt::free(|_| {
|
||||
LdoPwrStage::irq_handler(PowerRail::P15VA);
|
||||
LdoPwrStage::clear_irq_bit(PowerRail::P15VA)
|
||||
});
|
||||
}
|
||||
|
||||
#[interrupt]
|
||||
fn EXTI4() {
|
||||
cortex_m::interrupt::free(|_| {
|
||||
LdoPwrStage::irq_handler(PowerRail::P3V3A);
|
||||
LdoPwrStage::clear_irq_bit(PowerRail::P3V3A)
|
||||
});
|
||||
}
|
||||
|
||||
#[interrupt]
|
||||
fn EXTI9_5() {
|
||||
cortex_m::interrupt::free(|_| {
|
||||
LdoPwrStage::irq_handler(PowerRail::P5V0A);
|
||||
LdoPwrStage::clear_irq_bit(PowerRail::P5V0A)
|
||||
});
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
use core::cell::RefCell;
|
||||
use core::ops::Deref;
|
||||
use cortex_m::interrupt::Mutex;
|
||||
use cortex_m::peripheral::syst::SystClkSource;
|
||||
use core::{cell::RefCell, ops::Deref};
|
||||
|
||||
use cortex_m::{interrupt::Mutex, peripheral::syst::SystClkSource};
|
||||
use cortex_m_rt::exception;
|
||||
use stm32f4xx_hal::{pac::SYST, rcc::Clocks};
|
||||
use stm32f4xx_hal::{pac::{SYST, Peripherals}, rcc::Clocks};
|
||||
|
||||
/// Rate in Hz
|
||||
const TIMER_RATE: u32 = 1000;
|
||||
@@ -11,9 +10,13 @@ const TIMER_RATE: u32 = 1000;
|
||||
const TIMER_DELTA: u32 = 1000 / TIMER_RATE;
|
||||
/// Elapsed time in milliseconds
|
||||
static TIMER_MS: Mutex<RefCell<u32>> = Mutex::new(RefCell::new(0));
|
||||
static mut US_COUNT: u32 = 168;
|
||||
|
||||
/// Setup SysTick exception
|
||||
pub fn setup(mut syst: SYST, clocks: Clocks) {
|
||||
unsafe {
|
||||
US_COUNT = clocks.hclk().to_MHz()
|
||||
}
|
||||
syst.set_clock_source(SystClkSource::Core);
|
||||
syst.set_reload(clocks.hclk().to_Hz() / TIMER_RATE - 1);
|
||||
syst.enable_counter();
|
||||
@@ -33,6 +36,15 @@ pub fn now() -> u32 {
|
||||
cortex_m::interrupt::free(|cs| *TIMER_MS.borrow(cs).borrow().deref())
|
||||
}
|
||||
|
||||
/// Obtain current time in milliseconds + microseconds
|
||||
pub fn now_precise() -> (u32, u32) {
|
||||
let ms = now();
|
||||
unsafe {
|
||||
let us = (Peripherals::steal().STK.load.read().bits() - Peripherals::steal().STK.val.read().bits()) / US_COUNT;
|
||||
(ms, us)
|
||||
}
|
||||
}
|
||||
|
||||
/// block for `amount` milliseconds
|
||||
pub fn sleep(amount: u32) {
|
||||
if amount == 0 {
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
use core::{
|
||||
fmt::{self, Write},
|
||||
mem::MaybeUninit,
|
||||
};
|
||||
use core::{fmt::{self, Write},
|
||||
mem::MaybeUninit};
|
||||
|
||||
use cortex_m::interrupt::free;
|
||||
use log::{Log, Metadata, Record};
|
||||
use stm32f4xx_hal::{
|
||||
otg_fs::{UsbBus as Bus, USB},
|
||||
pac::{interrupt, Interrupt, NVIC},
|
||||
};
|
||||
use usb_device::{
|
||||
class_prelude::UsbBusAllocator,
|
||||
prelude::{UsbDevice, UsbDeviceBuilder, UsbVidPid},
|
||||
};
|
||||
use stm32f4xx_hal::{otg_fs::{UsbBus as Bus, USB},
|
||||
pac::{interrupt, Interrupt, NVIC}};
|
||||
use usb_device::{class_prelude::UsbBusAllocator,
|
||||
descriptor::lang_id,
|
||||
device::StringDescriptors,
|
||||
prelude::{UsbDevice, UsbDeviceBuilder, UsbVidPid}};
|
||||
use usbd_serial::SerialPort;
|
||||
|
||||
static mut EP_MEMORY: [u32; 1024] = [0; 1024];
|
||||
@@ -27,16 +24,20 @@ pub struct State {
|
||||
|
||||
impl State {
|
||||
pub fn setup(usb: USB) {
|
||||
unsafe { BUS.write(Bus::new(usb, &mut EP_MEMORY)) };
|
||||
unsafe { BUS.write(Bus::new(usb, EP_MEMORY.as_mut())) };
|
||||
|
||||
let str_descriptor = StringDescriptors::new(lang_id::LangID::EN)
|
||||
.manufacturer("M-Labs")
|
||||
.product("Kirdy");
|
||||
|
||||
let bus = unsafe { BUS.assume_init_ref() };
|
||||
let serial = SerialPort::new(bus);
|
||||
let dev = UsbDeviceBuilder::new(bus, UsbVidPid(0x16c0, 0x27dd))
|
||||
.manufacturer("M-Labs")
|
||||
.product("thermostat")
|
||||
.device_release(0x20)
|
||||
.self_powered(true)
|
||||
.device_class(usbd_serial::USB_CLASS_CDC)
|
||||
.strings(&[str_descriptor])
|
||||
.unwrap()
|
||||
.build();
|
||||
|
||||
free(|_| unsafe {
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
use stm32f4xx_hal::{
|
||||
gpio::{gpioa::*, gpiob::*, gpiod::*, Alternate, Output, PushPull, PD9},
|
||||
hal::{blocking::spi::Write, digital::v2::OutputPin},
|
||||
pac::SPI2,
|
||||
spi::{NoMiso, Spi, TransferModeNormal},
|
||||
};
|
||||
|
||||
use crate::device::sys_timer::sleep;
|
||||
pub trait CurrentSourcePhy {
|
||||
type CurrentSourceLdoEn: OutputPin;
|
||||
type CurrentSourceShort: OutputPin;
|
||||
type Max5719Load: OutputPin;
|
||||
type Max5719Cs: OutputPin;
|
||||
type Max5719Spi: Write<u8>;
|
||||
}
|
||||
|
||||
pub struct CurrentSourcePhyConstruct<C: CurrentSourcePhy> {
|
||||
pub max5719_spi: C::Max5719Spi,
|
||||
pub max5719_load: C::Max5719Load,
|
||||
pub max5719_cs: C::Max5719Cs,
|
||||
pub current_source_ldo_en: C::CurrentSourceLdoEn,
|
||||
pub current_source_short: C::CurrentSourceShort,
|
||||
}
|
||||
pub struct CurrentSourceSettings {
|
||||
pub output_current: f32,
|
||||
}
|
||||
pub struct CurrentSource<C: CurrentSourcePhy> {
|
||||
pub phy: CurrentSourcePhyConstruct<C>,
|
||||
pub setting: CurrentSourceSettings,
|
||||
}
|
||||
|
||||
pub struct CurrentSourcePhyCh0;
|
||||
|
||||
impl CurrentSourcePhy for CurrentSourcePhyCh0 {
|
||||
type CurrentSourceLdoEn = PD9<Output<PushPull>>;
|
||||
type CurrentSourceShort = PA4<Output<PushPull>>;
|
||||
type Max5719Load = PB14<Output<PushPull>>;
|
||||
type Max5719Cs = PD8<Output<PushPull>>;
|
||||
type Max5719Spi =
|
||||
Spi<SPI2, (PB10<Alternate<5>>, NoMiso, PB15<Alternate<5>>), TransferModeNormal>;
|
||||
}
|
||||
|
||||
impl<C: CurrentSourcePhy> CurrentSource<C> {
|
||||
pub fn setup(&mut self) {
|
||||
let _ = self.phy.max5719_load.set_high();
|
||||
let _ = self.phy.max5719_cs.set_high();
|
||||
let _ = self.phy.current_source_ldo_en.set_high();
|
||||
sleep(10_u32);
|
||||
let _ = self.phy.current_source_short.set_high();
|
||||
sleep(10_u32);
|
||||
}
|
||||
|
||||
pub fn set_current(
|
||||
&mut self,
|
||||
current: f32,
|
||||
) -> Result<(), <<C as CurrentSourcePhy>::Max5719Spi as Write<u8>>::Error> {
|
||||
let _ = self.phy.max5719_load.set_high();
|
||||
let _ = self.phy.max5719_cs.set_low();
|
||||
self.setting.output_current = current * 10.0 / 0.75;
|
||||
let word = (((self.setting.output_current / 4.096) * 1048576.0) as u32) << 4;
|
||||
let mut buf = [
|
||||
((word >> 16) & 0xFF) as u8,
|
||||
((word >> 8) & 0xFF) as u8,
|
||||
((word >> 0) & 0xFF) as u8,
|
||||
];
|
||||
self.phy.max5719_spi.write(&mut buf)?;
|
||||
let _ = self.phy.max5719_cs.set_high();
|
||||
let _ = self.phy.max5719_load.set_low();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
314
src/laser_diode/laser_diode.rs
Normal file
314
src/laser_diode/laser_diode.rs
Normal file
@@ -0,0 +1,314 @@
|
||||
use miniconf::Tree;
|
||||
use num_traits::Zero;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use stm32f4xx_hal::{pac::{ADC3, EXTI, TIM2},
|
||||
syscfg::SysCfg,
|
||||
timer::CounterUs};
|
||||
use uom::si::{electric_current::{ampere, milliampere},
|
||||
f32::{ElectricCurrent, ElectricalConductance, Power},
|
||||
power::milliwatt};
|
||||
|
||||
use crate::{device::{power_rail_monitor::LdoPwrStage, sys_timer::sleep},
|
||||
laser_diode::{ld_ctrl::{Impedance50Ohm, LdCtrl},
|
||||
ld_current_out_ctrl_timer::LdCurrentOutCtrlTimer,
|
||||
ld_hw_variant::{LdHwVariant, LdHwVariantEnum},
|
||||
ld_pwr_exc_protector::{self, LdPwrExcProtector},
|
||||
pd_mon_params},
|
||||
Failure};
|
||||
#[derive(Deserialize, Serialize, Clone, Copy, Debug, Tree)]
|
||||
struct Settings {
|
||||
pwr_on: bool,
|
||||
default_pwr_on: bool,
|
||||
ld_drive_current: ElectricCurrent,
|
||||
pd_mon_params: pd_mon_params::Parameters,
|
||||
ld_pwr_limit: Power,
|
||||
ld_terms_short: bool,
|
||||
incoming_pd_mon_params: pd_mon_params::Parameters,
|
||||
}
|
||||
|
||||
impl Default for Settings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
pwr_on: false,
|
||||
default_pwr_on: false,
|
||||
ld_drive_current: ElectricCurrent::new::<milliampere>(0.0),
|
||||
pd_mon_params: pd_mon_params::Parameters::default(),
|
||||
incoming_pd_mon_params: pd_mon_params::Parameters::default(),
|
||||
ld_pwr_limit: Power::new::<milliwatt>(0.0),
|
||||
ld_terms_short: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Tree)]
|
||||
pub struct StatusReport {
|
||||
pwr_on: bool,
|
||||
pwr_excursion: bool,
|
||||
pwr_failure: bool,
|
||||
ld_i_set: ElectricCurrent,
|
||||
pd_i: ElectricCurrent,
|
||||
pd_pwr: Power,
|
||||
term_50ohm: Impedance50Ohm,
|
||||
}
|
||||
|
||||
pub struct LdDrive {
|
||||
ld_hw_variant: LdHwVariant,
|
||||
ctrl: LdCtrl,
|
||||
settings: Settings,
|
||||
}
|
||||
|
||||
impl LdDrive {
|
||||
pub fn new(
|
||||
current_source: LdCtrl,
|
||||
pins_adc: ADC3,
|
||||
tim2: CounterUs<TIM2>,
|
||||
phy: ld_pwr_exc_protector::LdPwrExcProtectorPhy,
|
||||
ld_hw_variant: LdHwVariant,
|
||||
syscfg: &mut SysCfg,
|
||||
exti: &mut EXTI,
|
||||
) -> Self {
|
||||
LdPwrExcProtector::setup(pins_adc, phy, syscfg, exti);
|
||||
LdCurrentOutCtrlTimer::setup(tim2);
|
||||
|
||||
LdDrive {
|
||||
ld_hw_variant: ld_hw_variant,
|
||||
ctrl: current_source,
|
||||
settings: Settings::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup(&mut self) {
|
||||
LdPwrExcProtector::pwr_off();
|
||||
self.ctrl.set_i(
|
||||
ElectricCurrent::new::<milliampere>(0.0),
|
||||
self.ld_hw_variant.transimpedance,
|
||||
LdHwVariant::DAC_OUT_V_MAX,
|
||||
);
|
||||
LdCurrentOutCtrlTimer::reset();
|
||||
self.ctrl.ld_short_enable();
|
||||
}
|
||||
|
||||
pub fn get_hw_variant(&mut self) -> LdHwVariantEnum {
|
||||
return self.ld_hw_variant.name;
|
||||
}
|
||||
|
||||
pub fn ld_short(&mut self) {
|
||||
if LdPwrExcProtector::get_pwr_status().pwr_engaged {
|
||||
self.ctrl.ld_short_enable();
|
||||
}
|
||||
self.settings.ld_terms_short = true;
|
||||
}
|
||||
|
||||
pub fn ld_open(&mut self) {
|
||||
if LdPwrExcProtector::get_pwr_status().pwr_engaged {
|
||||
self.ctrl.ld_short_disable();
|
||||
}
|
||||
self.settings.ld_terms_short = false;
|
||||
}
|
||||
|
||||
pub fn power_up(&mut self) -> Result<(), Failure> {
|
||||
let pwr_rail_status = LdoPwrStage::check_power_rail_status();
|
||||
if pwr_rail_status.is_ok() {
|
||||
let prev_i_set = self.settings.ld_drive_current;
|
||||
LdCurrentOutCtrlTimer::reset();
|
||||
|
||||
if self.settings.ld_terms_short {
|
||||
self.ctrl.ld_short_enable();
|
||||
} else {
|
||||
self.ctrl.ld_short_disable();
|
||||
}
|
||||
|
||||
let _ = self.ctrl.set_i(
|
||||
ElectricCurrent::new::<milliampere>(0.0),
|
||||
self.ld_hw_variant.transimpedance,
|
||||
LdHwVariant::DAC_OUT_V_MAX,
|
||||
);
|
||||
// Wait for the DAC to reset its voltage back to 0V
|
||||
sleep(35);
|
||||
LdPwrExcProtector::pwr_on_and_arm_protection();
|
||||
self.ld_set_i(prev_i_set);
|
||||
self.settings.pwr_on = true;
|
||||
}
|
||||
pwr_rail_status
|
||||
}
|
||||
|
||||
pub fn power_down(&mut self) {
|
||||
LdPwrExcProtector::pwr_off();
|
||||
self.settings.pwr_on = false;
|
||||
// Short the laser diode terminals at power off state for electrical protection
|
||||
self.ctrl.ld_short_enable();
|
||||
}
|
||||
|
||||
pub fn get_pd_i(&mut self) -> ElectricCurrent {
|
||||
self.settings
|
||||
.pd_mon_params
|
||||
.get_pd_i_from_pd_v(LdPwrExcProtector::get_pwr_status().v)
|
||||
}
|
||||
|
||||
pub fn get_pd_pwr(&mut self) -> Power {
|
||||
self.settings.pd_mon_params.get_ld_pwr_from_ld_i(
|
||||
self.settings
|
||||
.pd_mon_params
|
||||
.get_pd_i_from_pd_v(LdPwrExcProtector::get_pwr_status().v),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn ld_set_i(&mut self, i: ElectricCurrent) -> bool {
|
||||
self.settings.ld_drive_current = i.min(self.ld_hw_variant.current_max).max(ElectricCurrent::zero());
|
||||
LdCurrentOutCtrlTimer::set_target_i_and_listen_irq(self.settings.ld_drive_current, self.ctrl.get_i_set());
|
||||
self.settings.ld_drive_current != i
|
||||
}
|
||||
|
||||
pub fn poll_and_update_output_current(&mut self) -> ElectricCurrent {
|
||||
match LdCurrentOutCtrlTimer::get_irq_status() {
|
||||
Some(i_set) => {
|
||||
let i_set = self
|
||||
.ctrl
|
||||
.set_i(i_set, self.ld_hw_variant.transimpedance, LdHwVariant::DAC_OUT_V_MAX);
|
||||
LdCurrentOutCtrlTimer::clear_alarm_and_resume_listening();
|
||||
i_set
|
||||
}
|
||||
None => ElectricCurrent::new::<ampere>(0.0),
|
||||
}
|
||||
}
|
||||
|
||||
// Set the calibrated VDDA value obtained from ADC1 calibration
|
||||
pub fn set_pd_mon_calibrated_vdda(&mut self, val_cal: u32) {
|
||||
LdPwrExcProtector::set_calibrated_vdda(val_cal)
|
||||
}
|
||||
|
||||
pub fn pd_mon_clear_alarm(&mut self) {
|
||||
LdPwrExcProtector::clear_alarm_status();
|
||||
}
|
||||
|
||||
pub fn set_pd_transconductance(&mut self, transconductance: ElectricalConductance) {
|
||||
self.settings.pd_mon_params.set_transconductance(transconductance)
|
||||
}
|
||||
|
||||
pub fn set_pd_responsitivity(&mut self, responsitivity: pd_mon_params::ResponsitivityUnit) {
|
||||
self.settings.incoming_pd_mon_params.set_responsitivity(responsitivity);
|
||||
}
|
||||
|
||||
pub fn set_pd_dark_current(&mut self, i_dark: ElectricCurrent) {
|
||||
self.settings.incoming_pd_mon_params.set_i_dark(i_dark);
|
||||
}
|
||||
|
||||
pub fn apply_pd_params(&mut self) -> bool {
|
||||
let prev_pd_params = self.settings.pd_mon_params;
|
||||
self.settings.incoming_pd_mon_params.transconductance = self.settings.pd_mon_params.transconductance;
|
||||
self.settings.pd_mon_params = self.settings.incoming_pd_mon_params;
|
||||
|
||||
let max_settable_pwr = self.get_ld_power_limit_range();
|
||||
let is_legal = self.settings.ld_pwr_limit <= max_settable_pwr;
|
||||
if is_legal {
|
||||
self.set_ld_power_limit(self.settings.ld_pwr_limit);
|
||||
} else {
|
||||
self.settings.pd_mon_params = prev_pd_params;
|
||||
}
|
||||
is_legal
|
||||
}
|
||||
|
||||
pub fn set_ld_power_limit(&mut self, pwr_limit: Power) -> bool {
|
||||
let is_legal = LdPwrExcProtector::set_trigger_threshold_v(
|
||||
self.settings.pd_mon_params.get_pd_i_from_ld_pwr(pwr_limit) / self.settings.pd_mon_params.transconductance,
|
||||
);
|
||||
if is_legal {
|
||||
self.settings.ld_pwr_limit = pwr_limit;
|
||||
}
|
||||
is_legal
|
||||
}
|
||||
|
||||
pub fn get_ld_power_limit_range(&mut self) -> Power {
|
||||
let v_range = LdPwrExcProtector::get_settable_volt_range();
|
||||
let i_range = self.settings.pd_mon_params.get_pd_i_from_pd_v(v_range);
|
||||
let max_settable_pwr = self.settings.pd_mon_params.get_ld_pwr_from_ld_i(i_range);
|
||||
if max_settable_pwr.is_nan() || max_settable_pwr.is_infinite() {
|
||||
Power::zero()
|
||||
} else {
|
||||
max_settable_pwr
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_pd_i_limit(&mut self, i: ElectricCurrent) -> bool {
|
||||
return LdPwrExcProtector::set_trigger_threshold_v(i / self.settings.pd_mon_params.transconductance);
|
||||
}
|
||||
|
||||
pub fn set_default_pwr_on(&mut self, pwr_on: bool) {
|
||||
self.settings.default_pwr_on = pwr_on;
|
||||
}
|
||||
|
||||
pub fn get_term_status(&mut self) -> Impedance50Ohm {
|
||||
self.ctrl.get_lf_mod_in_impedance()
|
||||
}
|
||||
|
||||
pub fn get_status_report(&mut self) -> StatusReport {
|
||||
let ld_i_set = if LdPwrExcProtector::get_pwr_status().pwr_engaged {
|
||||
self.ctrl.get_i_set()
|
||||
} else {
|
||||
ElectricCurrent::new::<ampere>(0.0)
|
||||
};
|
||||
StatusReport {
|
||||
pwr_on: LdPwrExcProtector::get_pwr_status().pwr_engaged,
|
||||
pwr_excursion: LdPwrExcProtector::get_pwr_status().pwr_excursion,
|
||||
pwr_failure: LdPwrExcProtector::get_ldo_status(),
|
||||
ld_i_set: ld_i_set,
|
||||
pd_i: self.get_pd_i(),
|
||||
pd_pwr: self.get_pd_pwr(),
|
||||
term_50ohm: self.get_term_status(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_settings_summary(&mut self) -> LdSettingsSummary {
|
||||
let settings = self.settings;
|
||||
LdSettingsSummary {
|
||||
default_pwr_on: self.settings.default_pwr_on,
|
||||
ld_drive_current: LdSettingsSummaryField {
|
||||
value: settings.ld_drive_current,
|
||||
max: self.ld_hw_variant.current_max,
|
||||
},
|
||||
pd_mon_params: settings.pd_mon_params,
|
||||
ld_pwr_limit: LdSettingsSummaryField {
|
||||
value: settings.ld_pwr_limit,
|
||||
max: self.get_ld_power_limit_range(),
|
||||
},
|
||||
ld_terms_short: settings.ld_terms_short,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_settings_from_summary(&mut self, settings: LdSettingsSummary) {
|
||||
self.power_down();
|
||||
self.settings.ld_drive_current = settings.ld_drive_current.value;
|
||||
self.settings.pd_mon_params = settings.pd_mon_params;
|
||||
let max_pwr_limit = self.get_ld_power_limit_range();
|
||||
self.settings.ld_pwr_limit = settings.ld_pwr_limit.value.min(max_pwr_limit);
|
||||
self.settings.default_pwr_on = settings.default_pwr_on;
|
||||
self.set_ld_power_limit(self.settings.ld_pwr_limit);
|
||||
|
||||
if self.settings.ld_terms_short {
|
||||
self.ld_short();
|
||||
} else {
|
||||
self.ld_open();
|
||||
}
|
||||
|
||||
if settings.default_pwr_on {
|
||||
let _ = self.power_up();
|
||||
} else {
|
||||
self.power_down();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Tree)]
|
||||
pub struct LdSettingsSummary {
|
||||
default_pwr_on: bool,
|
||||
ld_drive_current: LdSettingsSummaryField<ElectricCurrent>,
|
||||
pd_mon_params: pd_mon_params::Parameters,
|
||||
ld_pwr_limit: LdSettingsSummaryField<Power>,
|
||||
ld_terms_short: bool,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Tree)]
|
||||
pub struct LdSettingsSummaryField<T> {
|
||||
value: T,
|
||||
max: T,
|
||||
}
|
||||
96
src/laser_diode/ld_ctrl.rs
Normal file
96
src/laser_diode/ld_ctrl.rs
Normal file
@@ -0,0 +1,96 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use stm32f4xx_hal::{gpio::{gpioa::*, gpiob::*, gpiod::*, Input, Output, PushPull},
|
||||
hal::{digital::{InputPin, OutputPin},
|
||||
spi::SpiBus},
|
||||
pac::SPI2,
|
||||
spi::Spi};
|
||||
use uom::si::{electric_current::ampere,
|
||||
f32::{ElectricCurrent, ElectricPotential, ElectricalResistance},
|
||||
ratio::ratio};
|
||||
|
||||
use crate::laser_diode::max5719::{self, Dac};
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug, Clone, Copy)]
|
||||
pub enum Impedance50Ohm {
|
||||
On,
|
||||
Off,
|
||||
}
|
||||
|
||||
pub trait ChannelPins {
|
||||
type CurrentSourceShort: OutputPin;
|
||||
type TerminationStatus: InputPin;
|
||||
type Max5719Load: OutputPin;
|
||||
type Max5719Cs: OutputPin;
|
||||
type Max5719Spi: SpiBus<u8>;
|
||||
}
|
||||
|
||||
pub struct LdCtrlPhy<C: ChannelPins> {
|
||||
pub dac: Dac<C::Max5719Spi, C::Max5719Cs, C::Max5719Load>,
|
||||
pub current_source_short_pin: C::CurrentSourceShort,
|
||||
pub termination_status_pin: C::TerminationStatus,
|
||||
}
|
||||
pub struct Channel0;
|
||||
|
||||
impl ChannelPins for Channel0 {
|
||||
type CurrentSourceShort = PA4<Output<PushPull>>;
|
||||
type TerminationStatus = PD7<Input>;
|
||||
type Max5719Load = DacLoad;
|
||||
type Max5719Cs = DacCs;
|
||||
type Max5719Spi = DacSpi;
|
||||
}
|
||||
|
||||
type DacSpi = Spi<SPI2>;
|
||||
type DacCs = PD8<Output<PushPull>>;
|
||||
type DacLoad = PB14<Output<PushPull>>;
|
||||
|
||||
pub struct LdCtrl {
|
||||
pub phy: LdCtrlPhy<Channel0>,
|
||||
i_set: ElectricCurrent,
|
||||
}
|
||||
|
||||
impl LdCtrl {
|
||||
pub fn new(phy_ch0: LdCtrlPhy<Channel0>) -> Self {
|
||||
LdCtrl {
|
||||
phy: phy_ch0,
|
||||
i_set: ElectricCurrent::new::<ampere>(0.0),
|
||||
}
|
||||
}
|
||||
|
||||
// LD Terminals are shorted together
|
||||
pub fn ld_short_enable(&mut self) {
|
||||
self.phy.current_source_short_pin.set_low();
|
||||
}
|
||||
|
||||
// LD Current flows from anode to cathode
|
||||
pub fn ld_short_disable(&mut self) {
|
||||
self.phy.current_source_short_pin.set_high();
|
||||
}
|
||||
|
||||
pub fn get_lf_mod_in_impedance(&mut self) -> Impedance50Ohm {
|
||||
if self.phy.termination_status_pin.is_high() {
|
||||
Impedance50Ohm::On
|
||||
} else {
|
||||
Impedance50Ohm::Off
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_dac(&mut self, voltage: ElectricPotential, dac_out_v_max: ElectricPotential) -> ElectricPotential {
|
||||
let value = ((voltage / dac_out_v_max).get::<ratio>() * (max5719::MAX_VALUE as f32)) as u32;
|
||||
self.phy.dac.set(value).unwrap();
|
||||
value as f32 * dac_out_v_max / max5719::MAX_VALUE as f32
|
||||
}
|
||||
|
||||
pub fn set_i(
|
||||
&mut self,
|
||||
current: ElectricCurrent,
|
||||
transimpedance: ElectricalResistance,
|
||||
dac_out_v_max: ElectricPotential,
|
||||
) -> ElectricCurrent {
|
||||
self.i_set = self.set_dac(current * transimpedance, dac_out_v_max) / transimpedance;
|
||||
self.i_set
|
||||
}
|
||||
|
||||
pub fn get_i_set(&mut self) -> ElectricCurrent {
|
||||
self.i_set
|
||||
}
|
||||
}
|
||||
128
src/laser_diode/ld_current_out_ctrl_timer.rs
Normal file
128
src/laser_diode/ld_current_out_ctrl_timer.rs
Normal file
@@ -0,0 +1,128 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use fugit::{HertzU32, TimerDurationU32};
|
||||
use log::debug;
|
||||
use stm32f4xx_hal::{pac::{interrupt, Interrupt, TIM2},
|
||||
timer::{Counter, Event},
|
||||
Listen};
|
||||
use uom::si::{electric_current::ampere, f32::ElectricCurrent};
|
||||
|
||||
pub struct LdCurrentOutCtrlTimer {
|
||||
target_i: ElectricCurrent,
|
||||
now_i: ElectricCurrent,
|
||||
timer: Counter<TIM2, FREQ>,
|
||||
timeout: bool,
|
||||
}
|
||||
static mut LD_CURRENT_OUT_CTRL_TIMER: Option<LdCurrentOutCtrlTimer> = None;
|
||||
|
||||
pub const FREQ: u32 = 1000000;
|
||||
|
||||
/// This timer notifies the main loop to set the correct output current so that ld output current can ramp up/down slowly.
|
||||
/// The current output slope is guaranteed to be larger but not necessarily equal to than the preset value.
|
||||
impl LdCurrentOutCtrlTimer {
|
||||
const TIME_STEP: TimerDurationU32<FREQ> = TimerDurationU32::from_rate(HertzU32::from_raw(250));
|
||||
const STEP_SIZE: ElectricCurrent = ElectricCurrent {
|
||||
dimension: PhantomData,
|
||||
units: PhantomData,
|
||||
value: 0.0001,
|
||||
};
|
||||
|
||||
pub fn setup(mut tim2: Counter<TIM2, FREQ>) {
|
||||
tim2.start(LdCurrentOutCtrlTimer::TIME_STEP).unwrap();
|
||||
unsafe {
|
||||
cortex_m::peripheral::NVIC::unmask(Interrupt::TIM2);
|
||||