Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b2203e008 | ||
|
|
a3cefc3c79 | ||
|
|
1c3a811154 | ||
|
|
aeb17f194c | ||
|
|
1c5ac13da8 | ||
|
|
7688986ad7 | ||
|
|
a686d19e61 | ||
|
|
380394b93a |
62
.VSCodeCounter/2026-04-01_16-39-17/details.md
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
# Details
|
||||||
|
|
||||||
|
Date : 2026-04-01 16:39:17
|
||||||
|
|
||||||
|
Directory e:\\Workspace\\JE-Skin
|
||||||
|
|
||||||
|
Total : 47 files, 8908 codes, 94 comments, 1250 blanks, all 10252 lines
|
||||||
|
|
||||||
|
[Summary](results.md) / Details / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||||
|
|
||||||
|
## Files
|
||||||
|
| filename | language | code | comment | blank | total |
|
||||||
|
| :--- | :--- | ---: | ---: | ---: | ---: |
|
||||||
|
| [.idea/modules.xml](/.idea/modules.xml) | XML | 8 | 0 | 0 | 8 |
|
||||||
|
| [.idea/tauri-demo.iml](/.idea/tauri-demo.iml) | XML | 11 | 0 | 0 | 11 |
|
||||||
|
| [README.md](/README.md) | Markdown | 34 | 0 | 20 | 54 |
|
||||||
|
| [flowus\_tools.json](/flowus_tools.json) | JSON | 1 | 0 | 1 | 2 |
|
||||||
|
| [frontend\_prompt.md](/frontend_prompt.md) | Markdown | 189 | 0 | 66 | 255 |
|
||||||
|
| [package-lock.json](/package-lock.json) | JSON | 1,957 | 0 | 1 | 1,958 |
|
||||||
|
| [package.json](/package.json) | JSON | 31 | 0 | 1 | 32 |
|
||||||
|
| [src-tauri/build.rs](/src-tauri/build.rs) | Rust | 3 | 0 | 1 | 4 |
|
||||||
|
| [src-tauri/capabilities/default.json](/src-tauri/capabilities/default.json) | JSON | 15 | 0 | 1 | 16 |
|
||||||
|
| [src-tauri/src/commands/mod.rs](/src-tauri/src/commands/mod.rs) | Rust | 2 | 0 | 1 | 3 |
|
||||||
|
| [src-tauri/src/commands/serial.rs](/src-tauri/src/commands/serial.rs) | Rust | 246 | 0 | 44 | 290 |
|
||||||
|
| [src-tauri/src/commands/window.rs](/src-tauri/src/commands/window.rs) | Rust | 27 | 0 | 6 | 33 |
|
||||||
|
| [src-tauri/src/lib.rs](/src-tauri/src/lib.rs) | Rust | 22 | 0 | 2 | 24 |
|
||||||
|
| [src-tauri/src/log.rs](/src-tauri/src/log.rs) | Rust | 34 | 0 | 2 | 36 |
|
||||||
|
| [src-tauri/src/main.rs](/src-tauri/src/main.rs) | Rust | 8 | 1 | 2 | 11 |
|
||||||
|
| [src-tauri/src/serial\_core/codec.rs](/src-tauri/src/serial_core/codec.rs) | Rust | 6 | 0 | 1 | 7 |
|
||||||
|
| [src-tauri/src/serial\_core/codecs/mod.rs](/src-tauri/src/serial_core/codecs/mod.rs) | Rust | 4 | 0 | 1 | 5 |
|
||||||
|
| [src-tauri/src/serial\_core/codecs/tactile\_a.rs](/src-tauri/src/serial_core/codecs/tactile_a.rs) | Rust | 67 | 0 | 17 | 84 |
|
||||||
|
| [src-tauri/src/serial\_core/codecs/test.rs](/src-tauri/src/serial_core/codecs/test.rs) | Rust | 213 | 7 | 40 | 260 |
|
||||||
|
| [src-tauri/src/serial\_core/error.rs](/src-tauri/src/serial_core/error.rs) | Rust | 47 | 0 | 6 | 53 |
|
||||||
|
| [src-tauri/src/serial\_core/frame.rs](/src-tauri/src/serial_core/frame.rs) | Rust | 46 | 3 | 9 | 58 |
|
||||||
|
| [src-tauri/src/serial\_core/mod.rs](/src-tauri/src/serial_core/mod.rs) | Rust | 22 | 0 | 7 | 29 |
|
||||||
|
| [src-tauri/src/serial\_core/model.rs](/src-tauri/src/serial_core/model.rs) | Rust | 377 | 57 | 67 | 501 |
|
||||||
|
| [src-tauri/src/serial\_core/record.rs](/src-tauri/src/serial_core/record.rs) | Rust | 50 | 4 | 11 | 65 |
|
||||||
|
| [src-tauri/src/serial\_core/serial.rs](/src-tauri/src/serial_core/serial.rs) | Rust | 73 | 0 | 8 | 81 |
|
||||||
|
| [src-tauri/src/serial\_core/utils.rs](/src-tauri/src/serial_core/utils.rs) | Rust | 26 | 0 | 6 | 32 |
|
||||||
|
| [src-tauri/tauri.conf.json](/src-tauri/tauri.conf.json) | JSON | 36 | 0 | 1 | 37 |
|
||||||
|
| [src/app.html](/src/app.html) | HTML | 13 | 0 | 1 | 14 |
|
||||||
|
| [src/lib/components/CenterStage.svelte](/src/lib/components/CenterStage.svelte) | Svelte | 691 | 0 | 96 | 787 |
|
||||||
|
| [src/lib/components/ConfigPanel.svelte](/src/lib/components/ConfigPanel.svelte) | Svelte | 398 | 0 | 63 | 461 |
|
||||||
|
| [src/lib/components/HudPanel.svelte](/src/lib/components/HudPanel.svelte) | Svelte | 861 | 0 | 110 | 971 |
|
||||||
|
| [src/lib/components/PressureMatrixViewer.svelte](/src/lib/components/PressureMatrixViewer.svelte) | Svelte | 558 | 0 | 97 | 655 |
|
||||||
|
| [src/lib/components/SignalChart.svelte](/src/lib/components/SignalChart.svelte) | Svelte | 382 | 0 | 71 | 453 |
|
||||||
|
| [src/lib/components/SummaryCurve.svelte](/src/lib/components/SummaryCurve.svelte) | Svelte | 497 | 0 | 88 | 585 |
|
||||||
|
| [src/lib/config/color-map.ts](/src/lib/config/color-map.ts) | TypeScript | 55 | 0 | 3 | 58 |
|
||||||
|
| [src/lib/styles/theme.css](/src/lib/styles/theme.css) | PostCSS | 43 | 1 | 7 | 51 |
|
||||||
|
| [src/lib/types/hud.ts](/src/lib/types/hud.ts) | TypeScript | 126 | 0 | 20 | 146 |
|
||||||
|
| [src/routes/+layout.svelte](/src/routes/+layout.svelte) | Svelte | 13 | 0 | 5 | 18 |
|
||||||
|
| [src/routes/+layout.ts](/src/routes/+layout.ts) | TypeScript | 1 | 4 | 1 | 6 |
|
||||||
|
| [src/routes/+page.svelte](/src/routes/+page.svelte) | Svelte | 1,286 | 0 | 176 | 1,462 |
|
||||||
|
| [static/svelte.svg](/static/svelte.svg) | XML | 1 | 0 | 0 | 1 |
|
||||||
|
| [static/tauri.svg](/static/tauri.svg) | XML | 6 | 0 | 1 | 7 |
|
||||||
|
| [static/vite.svg](/static/vite.svg) | XML | 1 | 0 | 0 | 1 |
|
||||||
|
| [svelte.config.js](/svelte.config.js) | JavaScript | 11 | 5 | 3 | 19 |
|
||||||
|
| [tauri-event.md](/tauri-event.md) | Markdown | 374 | 0 | 181 | 555 |
|
||||||
|
| [tsconfig.json](/tsconfig.json) | JSON with Comments | 14 | 5 | 1 | 20 |
|
||||||
|
| [vite.config.js](/vite.config.js) | JavaScript | 22 | 7 | 4 | 33 |
|
||||||
|
|
||||||
|
[Summary](results.md) / Details / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||||
15
.VSCodeCounter/2026-04-01_16-39-17/diff-details.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# Diff Details
|
||||||
|
|
||||||
|
Date : 2026-04-01 16:39:17
|
||||||
|
|
||||||
|
Directory e:\\Workspace\\JE-Skin
|
||||||
|
|
||||||
|
Total : 0 files, 0 codes, 0 comments, 0 blanks, all 0 lines
|
||||||
|
|
||||||
|
[Summary](results.md) / [Details](details.md) / [Diff Summary](diff.md) / Diff Details
|
||||||
|
|
||||||
|
## Files
|
||||||
|
| filename | language | code | comment | blank | total |
|
||||||
|
| :--- | :--- | ---: | ---: | ---: | ---: |
|
||||||
|
|
||||||
|
[Summary](results.md) / [Details](details.md) / [Diff Summary](diff.md) / Diff Details
|
||||||
2
.VSCodeCounter/2026-04-01_16-39-17/diff.csv
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
"filename", "language", "", "comment", "blank", "total"
|
||||||
|
"Total", "-", , 0, 0, 0
|
||||||
|
19
.VSCodeCounter/2026-04-01_16-39-17/diff.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Diff Summary
|
||||||
|
|
||||||
|
Date : 2026-04-01 16:39:17
|
||||||
|
|
||||||
|
Directory e:\\Workspace\\JE-Skin
|
||||||
|
|
||||||
|
Total : 0 files, 0 codes, 0 comments, 0 blanks, all 0 lines
|
||||||
|
|
||||||
|
[Summary](results.md) / [Details](details.md) / Diff Summary / [Diff Details](diff-details.md)
|
||||||
|
|
||||||
|
## Languages
|
||||||
|
| language | files | code | comment | blank | total |
|
||||||
|
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||||
|
|
||||||
|
## Directories
|
||||||
|
| path | files | code | comment | blank | total |
|
||||||
|
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||||
|
|
||||||
|
[Summary](results.md) / [Details](details.md) / Diff Summary / [Diff Details](diff-details.md)
|
||||||
22
.VSCodeCounter/2026-04-01_16-39-17/diff.txt
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
Date : 2026-04-01 16:39:17
|
||||||
|
Directory : e:\Workspace\JE-Skin
|
||||||
|
Total : 0 files, 0 codes, 0 comments, 0 blanks, all 0 lines
|
||||||
|
|
||||||
|
Languages
|
||||||
|
+----------+------------+------------+------------+------------+------------+
|
||||||
|
| language | files | code | comment | blank | total |
|
||||||
|
+----------+------------+------------+------------+------------+------------+
|
||||||
|
+----------+------------+------------+------------+------------+------------+
|
||||||
|
|
||||||
|
Directories
|
||||||
|
+------+------------+------------+------------+------------+------------+
|
||||||
|
| path | files | code | comment | blank | total |
|
||||||
|
+------+------------+------------+------------+------------+------------+
|
||||||
|
+------+------------+------------+------------+------------+------------+
|
||||||
|
|
||||||
|
Files
|
||||||
|
+----------+----------+------------+------------+------------+------------+
|
||||||
|
| filename | language | code | comment | blank | total |
|
||||||
|
+----------+----------+------------+------------+------------+------------+
|
||||||
|
| Total | | 0 | 0 | 0 | 0 |
|
||||||
|
+----------+----------+------------+------------+------------+------------+
|
||||||
49
.VSCodeCounter/2026-04-01_16-39-17/results.csv
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
"filename", "language", "JavaScript", "JSON", "Markdown", "JSON with Comments", "XML", "TypeScript", "Svelte", "Rust", "PostCSS", "HTML", "comment", "blank", "total"
|
||||||
|
"e:\Workspace\JE-Skin\.idea\modules.xml", "XML", 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 8
|
||||||
|
"e:\Workspace\JE-Skin\.idea\tauri-demo.iml", "XML", 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 11
|
||||||
|
"e:\Workspace\JE-Skin\README.md", "Markdown", 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 20, 54
|
||||||
|
"e:\Workspace\JE-Skin\flowus_tools.json", "JSON", 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2
|
||||||
|
"e:\Workspace\JE-Skin\frontend_prompt.md", "Markdown", 0, 0, 189, 0, 0, 0, 0, 0, 0, 0, 0, 66, 255
|
||||||
|
"e:\Workspace\JE-Skin\package-lock.json", "JSON", 0, 1957, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1958
|
||||||
|
"e:\Workspace\JE-Skin\package.json", "JSON", 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 32
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\build.rs", "Rust", 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 4
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\capabilities\default.json", "JSON", 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 16
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\commands\mod.rs", "Rust", 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 3
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\commands\serial.rs", "Rust", 0, 0, 0, 0, 0, 0, 0, 246, 0, 0, 0, 44, 290
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\commands\window.rs", "Rust", 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 6, 33
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\lib.rs", "Rust", 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 2, 24
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\log.rs", "Rust", 0, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 2, 36
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\main.rs", "Rust", 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 1, 2, 11
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\serial_core\codec.rs", "Rust", 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 1, 7
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\serial_core\codecs\mod.rs", "Rust", 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 1, 5
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\serial_core\codecs\tactile_a.rs", "Rust", 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 17, 84
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\serial_core\codecs\test.rs", "Rust", 0, 0, 0, 0, 0, 0, 0, 213, 0, 0, 7, 40, 260
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\serial_core\error.rs", "Rust", 0, 0, 0, 0, 0, 0, 0, 47, 0, 0, 0, 6, 53
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\serial_core\frame.rs", "Rust", 0, 0, 0, 0, 0, 0, 0, 46, 0, 0, 3, 9, 58
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\serial_core\mod.rs", "Rust", 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 7, 29
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\serial_core\model.rs", "Rust", 0, 0, 0, 0, 0, 0, 0, 377, 0, 0, 57, 67, 501
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\serial_core\record.rs", "Rust", 0, 0, 0, 0, 0, 0, 0, 50, 0, 0, 4, 11, 65
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\serial_core\serial.rs", "Rust", 0, 0, 0, 0, 0, 0, 0, 73, 0, 0, 0, 8, 81
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\serial_core\utils.rs", "Rust", 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 6, 32
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\tauri.conf.json", "JSON", 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 37
|
||||||
|
"e:\Workspace\JE-Skin\src\app.html", "HTML", 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 1, 14
|
||||||
|
"e:\Workspace\JE-Skin\src\lib\components\CenterStage.svelte", "Svelte", 0, 0, 0, 0, 0, 0, 691, 0, 0, 0, 0, 96, 787
|
||||||
|
"e:\Workspace\JE-Skin\src\lib\components\ConfigPanel.svelte", "Svelte", 0, 0, 0, 0, 0, 0, 398, 0, 0, 0, 0, 63, 461
|
||||||
|
"e:\Workspace\JE-Skin\src\lib\components\HudPanel.svelte", "Svelte", 0, 0, 0, 0, 0, 0, 861, 0, 0, 0, 0, 110, 971
|
||||||
|
"e:\Workspace\JE-Skin\src\lib\components\PressureMatrixViewer.svelte", "Svelte", 0, 0, 0, 0, 0, 0, 558, 0, 0, 0, 0, 97, 655
|
||||||
|
"e:\Workspace\JE-Skin\src\lib\components\SignalChart.svelte", "Svelte", 0, 0, 0, 0, 0, 0, 382, 0, 0, 0, 0, 71, 453
|
||||||
|
"e:\Workspace\JE-Skin\src\lib\components\SummaryCurve.svelte", "Svelte", 0, 0, 0, 0, 0, 0, 497, 0, 0, 0, 0, 88, 585
|
||||||
|
"e:\Workspace\JE-Skin\src\lib\config\color-map.ts", "TypeScript", 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, 0, 3, 58
|
||||||
|
"e:\Workspace\JE-Skin\src\lib\styles\theme.css", "PostCSS", 0, 0, 0, 0, 0, 0, 0, 0, 43, 0, 1, 7, 51
|
||||||
|
"e:\Workspace\JE-Skin\src\lib\types\hud.ts", "TypeScript", 0, 0, 0, 0, 0, 126, 0, 0, 0, 0, 0, 20, 146
|
||||||
|
"e:\Workspace\JE-Skin\src\routes\+layout.svelte", "Svelte", 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 5, 18
|
||||||
|
"e:\Workspace\JE-Skin\src\routes\+layout.ts", "TypeScript", 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 4, 1, 6
|
||||||
|
"e:\Workspace\JE-Skin\src\routes\+page.svelte", "Svelte", 0, 0, 0, 0, 0, 0, 1286, 0, 0, 0, 0, 176, 1462
|
||||||
|
"e:\Workspace\JE-Skin\static\svelte.svg", "XML", 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1
|
||||||
|
"e:\Workspace\JE-Skin\static\tauri.svg", "XML", 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 1, 7
|
||||||
|
"e:\Workspace\JE-Skin\static\vite.svg", "XML", 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1
|
||||||
|
"e:\Workspace\JE-Skin\svelte.config.js", "JavaScript", 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 3, 19
|
||||||
|
"e:\Workspace\JE-Skin\tauri-event.md", "Markdown", 0, 0, 374, 0, 0, 0, 0, 0, 0, 0, 0, 181, 555
|
||||||
|
"e:\Workspace\JE-Skin\tsconfig.json", "JSON with Comments", 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 5, 1, 20
|
||||||
|
"e:\Workspace\JE-Skin\vite.config.js", "JavaScript", 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 4, 33
|
||||||
|
"Total", "-", 33, 2040, 597, 14, 27, 182, 4686, 1273, 43, 13, 94, 1250, 10252
|
||||||
|
1
.VSCodeCounter/2026-04-01_16-39-17/results.json
Normal file
50
.VSCodeCounter/2026-04-01_16-39-17/results.md
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
# Summary
|
||||||
|
|
||||||
|
Date : 2026-04-01 16:39:17
|
||||||
|
|
||||||
|
Directory e:\\Workspace\\JE-Skin
|
||||||
|
|
||||||
|
Total : 47 files, 8908 codes, 94 comments, 1250 blanks, all 10252 lines
|
||||||
|
|
||||||
|
Summary / [Details](details.md) / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||||
|
|
||||||
|
## Languages
|
||||||
|
| language | files | code | comment | blank | total |
|
||||||
|
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||||
|
| Svelte | 8 | 4,686 | 0 | 706 | 5,392 |
|
||||||
|
| JSON | 5 | 2,040 | 0 | 5 | 2,045 |
|
||||||
|
| Rust | 18 | 1,273 | 72 | 231 | 1,576 |
|
||||||
|
| Markdown | 3 | 597 | 0 | 267 | 864 |
|
||||||
|
| TypeScript | 3 | 182 | 4 | 24 | 210 |
|
||||||
|
| PostCSS | 1 | 43 | 1 | 7 | 51 |
|
||||||
|
| JavaScript | 2 | 33 | 12 | 7 | 52 |
|
||||||
|
| XML | 5 | 27 | 0 | 1 | 28 |
|
||||||
|
| JSON with Comments | 1 | 14 | 5 | 1 | 20 |
|
||||||
|
| HTML | 1 | 13 | 0 | 1 | 14 |
|
||||||
|
|
||||||
|
## Directories
|
||||||
|
| path | files | code | comment | blank | total |
|
||||||
|
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||||
|
| . | 47 | 8,908 | 94 | 1,250 | 10,252 |
|
||||||
|
| . (Files) | 9 | 2,633 | 17 | 278 | 2,928 |
|
||||||
|
| .idea | 2 | 19 | 0 | 0 | 19 |
|
||||||
|
| src | 13 | 4,924 | 5 | 738 | 5,667 |
|
||||||
|
| src (Files) | 1 | 13 | 0 | 1 | 14 |
|
||||||
|
| src-tauri | 20 | 1,324 | 72 | 233 | 1,629 |
|
||||||
|
| src-tauri (Files) | 2 | 39 | 0 | 2 | 41 |
|
||||||
|
| src-tauri\\capabilities | 1 | 15 | 0 | 1 | 16 |
|
||||||
|
| src-tauri\\src | 17 | 1,270 | 72 | 230 | 1,572 |
|
||||||
|
| src-tauri\\src (Files) | 3 | 64 | 1 | 6 | 71 |
|
||||||
|
| src-tauri\\src\\commands | 3 | 275 | 0 | 51 | 326 |
|
||||||
|
| src-tauri\\src\\serial_core | 11 | 931 | 71 | 173 | 1,175 |
|
||||||
|
| src-tauri\\src\\serial_core (Files) | 8 | 647 | 64 | 115 | 826 |
|
||||||
|
| src-tauri\\src\\serial_core\\codecs | 3 | 284 | 7 | 58 | 349 |
|
||||||
|
| src\\lib | 9 | 3,611 | 1 | 555 | 4,167 |
|
||||||
|
| src\\lib\\components | 6 | 3,387 | 0 | 525 | 3,912 |
|
||||||
|
| src\\lib\\config | 1 | 55 | 0 | 3 | 58 |
|
||||||
|
| src\\lib\\styles | 1 | 43 | 1 | 7 | 51 |
|
||||||
|
| src\\lib\\types | 1 | 126 | 0 | 20 | 146 |
|
||||||
|
| src\\routes | 3 | 1,300 | 4 | 182 | 1,486 |
|
||||||
|
| static | 3 | 8 | 0 | 1 | 9 |
|
||||||
|
|
||||||
|
Summary / [Details](details.md) / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||||
100
.VSCodeCounter/2026-04-01_16-39-17/results.txt
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
Date : 2026-04-01 16:39:17
|
||||||
|
Directory : e:\Workspace\JE-Skin
|
||||||
|
Total : 47 files, 8908 codes, 94 comments, 1250 blanks, all 10252 lines
|
||||||
|
|
||||||
|
Languages
|
||||||
|
+--------------------+------------+------------+------------+------------+------------+
|
||||||
|
| language | files | code | comment | blank | total |
|
||||||
|
+--------------------+------------+------------+------------+------------+------------+
|
||||||
|
| Svelte | 8 | 4,686 | 0 | 706 | 5,392 |
|
||||||
|
| JSON | 5 | 2,040 | 0 | 5 | 2,045 |
|
||||||
|
| Rust | 18 | 1,273 | 72 | 231 | 1,576 |
|
||||||
|
| Markdown | 3 | 597 | 0 | 267 | 864 |
|
||||||
|
| TypeScript | 3 | 182 | 4 | 24 | 210 |
|
||||||
|
| PostCSS | 1 | 43 | 1 | 7 | 51 |
|
||||||
|
| JavaScript | 2 | 33 | 12 | 7 | 52 |
|
||||||
|
| XML | 5 | 27 | 0 | 1 | 28 |
|
||||||
|
| JSON with Comments | 1 | 14 | 5 | 1 | 20 |
|
||||||
|
| HTML | 1 | 13 | 0 | 1 | 14 |
|
||||||
|
+--------------------+------------+------------+------------+------------+------------+
|
||||||
|
|
||||||
|
Directories
|
||||||
|
+---------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||||
|
| path | files | code | comment | blank | total |
|
||||||
|
+---------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||||
|
| . | 47 | 8,908 | 94 | 1,250 | 10,252 |
|
||||||
|
| . (Files) | 9 | 2,633 | 17 | 278 | 2,928 |
|
||||||
|
| .idea | 2 | 19 | 0 | 0 | 19 |
|
||||||
|
| src | 13 | 4,924 | 5 | 738 | 5,667 |
|
||||||
|
| src (Files) | 1 | 13 | 0 | 1 | 14 |
|
||||||
|
| src-tauri | 20 | 1,324 | 72 | 233 | 1,629 |
|
||||||
|
| src-tauri (Files) | 2 | 39 | 0 | 2 | 41 |
|
||||||
|
| src-tauri\capabilities | 1 | 15 | 0 | 1 | 16 |
|
||||||
|
| src-tauri\src | 17 | 1,270 | 72 | 230 | 1,572 |
|
||||||
|
| src-tauri\src (Files) | 3 | 64 | 1 | 6 | 71 |
|
||||||
|
| src-tauri\src\commands | 3 | 275 | 0 | 51 | 326 |
|
||||||
|
| src-tauri\src\serial_core | 11 | 931 | 71 | 173 | 1,175 |
|
||||||
|
| src-tauri\src\serial_core (Files) | 8 | 647 | 64 | 115 | 826 |
|
||||||
|
| src-tauri\src\serial_core\codecs | 3 | 284 | 7 | 58 | 349 |
|
||||||
|
| src\lib | 9 | 3,611 | 1 | 555 | 4,167 |
|
||||||
|
| src\lib\components | 6 | 3,387 | 0 | 525 | 3,912 |
|
||||||
|
| src\lib\config | 1 | 55 | 0 | 3 | 58 |
|
||||||
|
| src\lib\styles | 1 | 43 | 1 | 7 | 51 |
|
||||||
|
| src\lib\types | 1 | 126 | 0 | 20 | 146 |
|
||||||
|
| src\routes | 3 | 1,300 | 4 | 182 | 1,486 |
|
||||||
|
| static | 3 | 8 | 0 | 1 | 9 |
|
||||||
|
+---------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||||
|
|
||||||
|
Files
|
||||||
|
+---------------------------------------------------------------------------+--------------------+------------+------------+------------+------------+
|
||||||
|
| filename | language | code | comment | blank | total |
|
||||||
|
+---------------------------------------------------------------------------+--------------------+------------+------------+------------+------------+
|
||||||
|
| e:\Workspace\JE-Skin\.idea\modules.xml | XML | 8 | 0 | 0 | 8 |
|
||||||
|
| e:\Workspace\JE-Skin\.idea\tauri-demo.iml | XML | 11 | 0 | 0 | 11 |
|
||||||
|
| e:\Workspace\JE-Skin\README.md | Markdown | 34 | 0 | 20 | 54 |
|
||||||
|
| e:\Workspace\JE-Skin\flowus_tools.json | JSON | 1 | 0 | 1 | 2 |
|
||||||
|
| e:\Workspace\JE-Skin\frontend_prompt.md | Markdown | 189 | 0 | 66 | 255 |
|
||||||
|
| e:\Workspace\JE-Skin\package-lock.json | JSON | 1,957 | 0 | 1 | 1,958 |
|
||||||
|
| e:\Workspace\JE-Skin\package.json | JSON | 31 | 0 | 1 | 32 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\build.rs | Rust | 3 | 0 | 1 | 4 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\capabilities\default.json | JSON | 15 | 0 | 1 | 16 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\commands\mod.rs | Rust | 2 | 0 | 1 | 3 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\commands\serial.rs | Rust | 246 | 0 | 44 | 290 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\commands\window.rs | Rust | 27 | 0 | 6 | 33 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\lib.rs | Rust | 22 | 0 | 2 | 24 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\log.rs | Rust | 34 | 0 | 2 | 36 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\main.rs | Rust | 8 | 1 | 2 | 11 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\serial_core\codec.rs | Rust | 6 | 0 | 1 | 7 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\serial_core\codecs\mod.rs | Rust | 4 | 0 | 1 | 5 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\serial_core\codecs\tactile_a.rs | Rust | 67 | 0 | 17 | 84 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\serial_core\codecs\test.rs | Rust | 213 | 7 | 40 | 260 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\serial_core\error.rs | Rust | 47 | 0 | 6 | 53 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\serial_core\frame.rs | Rust | 46 | 3 | 9 | 58 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\serial_core\mod.rs | Rust | 22 | 0 | 7 | 29 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\serial_core\model.rs | Rust | 377 | 57 | 67 | 501 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\serial_core\record.rs | Rust | 50 | 4 | 11 | 65 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\serial_core\serial.rs | Rust | 73 | 0 | 8 | 81 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\serial_core\utils.rs | Rust | 26 | 0 | 6 | 32 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\tauri.conf.json | JSON | 36 | 0 | 1 | 37 |
|
||||||
|
| e:\Workspace\JE-Skin\src\app.html | HTML | 13 | 0 | 1 | 14 |
|
||||||
|
| e:\Workspace\JE-Skin\src\lib\components\CenterStage.svelte | Svelte | 691 | 0 | 96 | 787 |
|
||||||
|
| e:\Workspace\JE-Skin\src\lib\components\ConfigPanel.svelte | Svelte | 398 | 0 | 63 | 461 |
|
||||||
|
| e:\Workspace\JE-Skin\src\lib\components\HudPanel.svelte | Svelte | 861 | 0 | 110 | 971 |
|
||||||
|
| e:\Workspace\JE-Skin\src\lib\components\PressureMatrixViewer.svelte | Svelte | 558 | 0 | 97 | 655 |
|
||||||
|
| e:\Workspace\JE-Skin\src\lib\components\SignalChart.svelte | Svelte | 382 | 0 | 71 | 453 |
|
||||||
|
| e:\Workspace\JE-Skin\src\lib\components\SummaryCurve.svelte | Svelte | 497 | 0 | 88 | 585 |
|
||||||
|
| e:\Workspace\JE-Skin\src\lib\config\color-map.ts | TypeScript | 55 | 0 | 3 | 58 |
|
||||||
|
| e:\Workspace\JE-Skin\src\lib\styles\theme.css | PostCSS | 43 | 1 | 7 | 51 |
|
||||||
|
| e:\Workspace\JE-Skin\src\lib\types\hud.ts | TypeScript | 126 | 0 | 20 | 146 |
|
||||||
|
| e:\Workspace\JE-Skin\src\routes\+layout.svelte | Svelte | 13 | 0 | 5 | 18 |
|
||||||
|
| e:\Workspace\JE-Skin\src\routes\+layout.ts | TypeScript | 1 | 4 | 1 | 6 |
|
||||||
|
| e:\Workspace\JE-Skin\src\routes\+page.svelte | Svelte | 1,286 | 0 | 176 | 1,462 |
|
||||||
|
| e:\Workspace\JE-Skin\static\svelte.svg | XML | 1 | 0 | 0 | 1 |
|
||||||
|
| e:\Workspace\JE-Skin\static\tauri.svg | XML | 6 | 0 | 1 | 7 |
|
||||||
|
| e:\Workspace\JE-Skin\static\vite.svg | XML | 1 | 0 | 0 | 1 |
|
||||||
|
| e:\Workspace\JE-Skin\svelte.config.js | JavaScript | 11 | 5 | 3 | 19 |
|
||||||
|
| e:\Workspace\JE-Skin\tauri-event.md | Markdown | 374 | 0 | 181 | 555 |
|
||||||
|
| e:\Workspace\JE-Skin\tsconfig.json | JSON with Comments | 14 | 5 | 1 | 20 |
|
||||||
|
| e:\Workspace\JE-Skin\vite.config.js | JavaScript | 22 | 7 | 4 | 33 |
|
||||||
|
| Total | | 8,908 | 94 | 1,250 | 10,252 |
|
||||||
|
+---------------------------------------------------------------------------+--------------------+------------+------------+------------+------------+
|
||||||
62
.VSCodeCounter/2026-04-02_14-42-07/details.md
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
# Details
|
||||||
|
|
||||||
|
Date : 2026-04-02 14:42:07
|
||||||
|
|
||||||
|
Directory e:\\Workspace\\JE-Skin
|
||||||
|
|
||||||
|
Total : 47 files, 9155 codes, 95 comments, 1279 blanks, all 10529 lines
|
||||||
|
|
||||||
|
[Summary](results.md) / Details / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||||
|
|
||||||
|
## Files
|
||||||
|
| filename | language | code | comment | blank | total |
|
||||||
|
| :--- | :--- | ---: | ---: | ---: | ---: |
|
||||||
|
| [.idea/modules.xml](/.idea/modules.xml) | XML | 8 | 0 | 0 | 8 |
|
||||||
|
| [.idea/tauri-demo.iml](/.idea/tauri-demo.iml) | XML | 11 | 0 | 0 | 11 |
|
||||||
|
| [README.md](/README.md) | Markdown | 34 | 0 | 20 | 54 |
|
||||||
|
| [flowus\_tools.json](/flowus_tools.json) | JSON | 1 | 0 | 1 | 2 |
|
||||||
|
| [frontend\_prompt.md](/frontend_prompt.md) | Markdown | 189 | 0 | 66 | 255 |
|
||||||
|
| [package-lock.json](/package-lock.json) | JSON | 1,957 | 0 | 1 | 1,958 |
|
||||||
|
| [package.json](/package.json) | JSON | 31 | 0 | 1 | 32 |
|
||||||
|
| [src-tauri/build.rs](/src-tauri/build.rs) | Rust | 3 | 0 | 1 | 4 |
|
||||||
|
| [src-tauri/capabilities/default.json](/src-tauri/capabilities/default.json) | JSON | 15 | 0 | 1 | 16 |
|
||||||
|
| [src-tauri/src/commands/mod.rs](/src-tauri/src/commands/mod.rs) | Rust | 2 | 0 | 1 | 3 |
|
||||||
|
| [src-tauri/src/commands/serial.rs](/src-tauri/src/commands/serial.rs) | Rust | 246 | 0 | 44 | 290 |
|
||||||
|
| [src-tauri/src/commands/window.rs](/src-tauri/src/commands/window.rs) | Rust | 27 | 0 | 6 | 33 |
|
||||||
|
| [src-tauri/src/lib.rs](/src-tauri/src/lib.rs) | Rust | 22 | 0 | 2 | 24 |
|
||||||
|
| [src-tauri/src/log.rs](/src-tauri/src/log.rs) | Rust | 34 | 0 | 2 | 36 |
|
||||||
|
| [src-tauri/src/main.rs](/src-tauri/src/main.rs) | Rust | 8 | 1 | 2 | 11 |
|
||||||
|
| [src-tauri/src/serial\_core/codec.rs](/src-tauri/src/serial_core/codec.rs) | Rust | 6 | 0 | 1 | 7 |
|
||||||
|
| [src-tauri/src/serial\_core/codecs/mod.rs](/src-tauri/src/serial_core/codecs/mod.rs) | Rust | 4 | 0 | 1 | 5 |
|
||||||
|
| [src-tauri/src/serial\_core/codecs/tactile\_a.rs](/src-tauri/src/serial_core/codecs/tactile_a.rs) | Rust | 220 | 0 | 28 | 248 |
|
||||||
|
| [src-tauri/src/serial\_core/codecs/test.rs](/src-tauri/src/serial_core/codecs/test.rs) | Rust | 215 | 8 | 38 | 261 |
|
||||||
|
| [src-tauri/src/serial\_core/error.rs](/src-tauri/src/serial_core/error.rs) | Rust | 49 | 0 | 6 | 55 |
|
||||||
|
| [src-tauri/src/serial\_core/frame.rs](/src-tauri/src/serial_core/frame.rs) | Rust | 47 | 3 | 8 | 58 |
|
||||||
|
| [src-tauri/src/serial\_core/mod.rs](/src-tauri/src/serial_core/mod.rs) | Rust | 22 | 0 | 7 | 29 |
|
||||||
|
| [src-tauri/src/serial\_core/model.rs](/src-tauri/src/serial_core/model.rs) | Rust | 377 | 57 | 67 | 501 |
|
||||||
|
| [src-tauri/src/serial\_core/record.rs](/src-tauri/src/serial_core/record.rs) | Rust | 50 | 4 | 11 | 65 |
|
||||||
|
| [src-tauri/src/serial\_core/serial.rs](/src-tauri/src/serial_core/serial.rs) | Rust | 141 | 0 | 22 | 163 |
|
||||||
|
| [src-tauri/src/serial\_core/utils.rs](/src-tauri/src/serial_core/utils.rs) | Rust | 47 | 0 | 13 | 60 |
|
||||||
|
| [src-tauri/tauri.conf.json](/src-tauri/tauri.conf.json) | JSON | 36 | 0 | 1 | 37 |
|
||||||
|
| [src/app.html](/src/app.html) | HTML | 13 | 0 | 1 | 14 |
|
||||||
|
| [src/lib/components/CenterStage.svelte](/src/lib/components/CenterStage.svelte) | Svelte | 691 | 0 | 96 | 787 |
|
||||||
|
| [src/lib/components/ConfigPanel.svelte](/src/lib/components/ConfigPanel.svelte) | Svelte | 398 | 0 | 63 | 461 |
|
||||||
|
| [src/lib/components/HudPanel.svelte](/src/lib/components/HudPanel.svelte) | Svelte | 861 | 0 | 110 | 971 |
|
||||||
|
| [src/lib/components/PressureMatrixViewer.svelte](/src/lib/components/PressureMatrixViewer.svelte) | Svelte | 558 | 0 | 97 | 655 |
|
||||||
|
| [src/lib/components/SignalChart.svelte](/src/lib/components/SignalChart.svelte) | Svelte | 382 | 0 | 71 | 453 |
|
||||||
|
| [src/lib/components/SummaryCurve.svelte](/src/lib/components/SummaryCurve.svelte) | Svelte | 497 | 0 | 88 | 585 |
|
||||||
|
| [src/lib/config/color-map.ts](/src/lib/config/color-map.ts) | TypeScript | 55 | 0 | 3 | 58 |
|
||||||
|
| [src/lib/styles/theme.css](/src/lib/styles/theme.css) | PostCSS | 43 | 1 | 7 | 51 |
|
||||||
|
| [src/lib/types/hud.ts](/src/lib/types/hud.ts) | TypeScript | 126 | 0 | 20 | 146 |
|
||||||
|
| [src/routes/+layout.svelte](/src/routes/+layout.svelte) | Svelte | 13 | 0 | 5 | 18 |
|
||||||
|
| [src/routes/+layout.ts](/src/routes/+layout.ts) | TypeScript | 1 | 4 | 1 | 6 |
|
||||||
|
| [src/routes/+page.svelte](/src/routes/+page.svelte) | Svelte | 1,286 | 0 | 176 | 1,462 |
|
||||||
|
| [static/svelte.svg](/static/svelte.svg) | XML | 1 | 0 | 0 | 1 |
|
||||||
|
| [static/tauri.svg](/static/tauri.svg) | XML | 6 | 0 | 1 | 7 |
|
||||||
|
| [static/vite.svg](/static/vite.svg) | XML | 1 | 0 | 0 | 1 |
|
||||||
|
| [svelte.config.js](/svelte.config.js) | JavaScript | 11 | 5 | 3 | 19 |
|
||||||
|
| [tauri-event.md](/tauri-event.md) | Markdown | 374 | 0 | 181 | 555 |
|
||||||
|
| [tsconfig.json](/tsconfig.json) | JSON with Comments | 14 | 5 | 1 | 20 |
|
||||||
|
| [vite.config.js](/vite.config.js) | JavaScript | 22 | 7 | 4 | 33 |
|
||||||
|
|
||||||
|
[Summary](results.md) / Details / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||||
21
.VSCodeCounter/2026-04-02_14-42-07/diff-details.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# Diff Details
|
||||||
|
|
||||||
|
Date : 2026-04-02 14:42:07
|
||||||
|
|
||||||
|
Directory e:\\Workspace\\JE-Skin
|
||||||
|
|
||||||
|
Total : 6 files, 247 codes, 1 comments, 29 blanks, all 277 lines
|
||||||
|
|
||||||
|
[Summary](results.md) / [Details](details.md) / [Diff Summary](diff.md) / Diff Details
|
||||||
|
|
||||||
|
## Files
|
||||||
|
| filename | language | code | comment | blank | total |
|
||||||
|
| :--- | :--- | ---: | ---: | ---: | ---: |
|
||||||
|
| [src-tauri/src/serial\_core/codecs/tactile\_a.rs](/src-tauri/src/serial_core/codecs/tactile_a.rs) | Rust | 153 | 0 | 11 | 164 |
|
||||||
|
| [src-tauri/src/serial\_core/codecs/test.rs](/src-tauri/src/serial_core/codecs/test.rs) | Rust | 2 | 1 | -2 | 1 |
|
||||||
|
| [src-tauri/src/serial\_core/error.rs](/src-tauri/src/serial_core/error.rs) | Rust | 2 | 0 | 0 | 2 |
|
||||||
|
| [src-tauri/src/serial\_core/frame.rs](/src-tauri/src/serial_core/frame.rs) | Rust | 1 | 0 | -1 | 0 |
|
||||||
|
| [src-tauri/src/serial\_core/serial.rs](/src-tauri/src/serial_core/serial.rs) | Rust | 68 | 0 | 14 | 82 |
|
||||||
|
| [src-tauri/src/serial\_core/utils.rs](/src-tauri/src/serial_core/utils.rs) | Rust | 21 | 0 | 7 | 28 |
|
||||||
|
|
||||||
|
[Summary](results.md) / [Details](details.md) / [Diff Summary](diff.md) / Diff Details
|
||||||
8
.VSCodeCounter/2026-04-02_14-42-07/diff.csv
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
"filename", "language", "Rust", "comment", "blank", "total"
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\serial_core\codecs\tactile_a.rs", "Rust", 153, 0, 11, 164
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\serial_core\codecs\test.rs", "Rust", 2, 1, -2, 1
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\serial_core\error.rs", "Rust", 2, 0, 0, 2
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\serial_core\frame.rs", "Rust", 1, 0, -1, 0
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\serial_core\serial.rs", "Rust", 68, 0, 14, 82
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\serial_core\utils.rs", "Rust", 21, 0, 7, 28
|
||||||
|
"Total", "-", 247, 1, 29, 277
|
||||||
|
26
.VSCodeCounter/2026-04-02_14-42-07/diff.md
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
# Diff Summary
|
||||||
|
|
||||||
|
Date : 2026-04-02 14:42:07
|
||||||
|
|
||||||
|
Directory e:\\Workspace\\JE-Skin
|
||||||
|
|
||||||
|
Total : 6 files, 247 codes, 1 comments, 29 blanks, all 277 lines
|
||||||
|
|
||||||
|
[Summary](results.md) / [Details](details.md) / Diff Summary / [Diff Details](diff-details.md)
|
||||||
|
|
||||||
|
## Languages
|
||||||
|
| language | files | code | comment | blank | total |
|
||||||
|
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||||
|
| Rust | 6 | 247 | 1 | 29 | 277 |
|
||||||
|
|
||||||
|
## Directories
|
||||||
|
| path | files | code | comment | blank | total |
|
||||||
|
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||||
|
| . | 6 | 247 | 1 | 29 | 277 |
|
||||||
|
| src-tauri | 6 | 247 | 1 | 29 | 277 |
|
||||||
|
| src-tauri\\src | 6 | 247 | 1 | 29 | 277 |
|
||||||
|
| src-tauri\\src\\serial_core | 6 | 247 | 1 | 29 | 277 |
|
||||||
|
| src-tauri\\src\\serial_core (Files) | 4 | 92 | 0 | 20 | 112 |
|
||||||
|
| src-tauri\\src\\serial_core\\codecs | 2 | 155 | 1 | 9 | 165 |
|
||||||
|
|
||||||
|
[Summary](results.md) / [Details](details.md) / Diff Summary / [Diff Details](diff-details.md)
|
||||||
35
.VSCodeCounter/2026-04-02_14-42-07/diff.txt
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
Date : 2026-04-02 14:42:07
|
||||||
|
Directory : e:\Workspace\JE-Skin
|
||||||
|
Total : 6 files, 247 codes, 1 comments, 29 blanks, all 277 lines
|
||||||
|
|
||||||
|
Languages
|
||||||
|
+----------+------------+------------+------------+------------+------------+
|
||||||
|
| language | files | code | comment | blank | total |
|
||||||
|
+----------+------------+------------+------------+------------+------------+
|
||||||
|
| Rust | 6 | 247 | 1 | 29 | 277 |
|
||||||
|
+----------+------------+------------+------------+------------+------------+
|
||||||
|
|
||||||
|
Directories
|
||||||
|
+--------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||||
|
| path | files | code | comment | blank | total |
|
||||||
|
+--------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||||
|
| . | 6 | 247 | 1 | 29 | 277 |
|
||||||
|
| src-tauri | 6 | 247 | 1 | 29 | 277 |
|
||||||
|
| src-tauri\src | 6 | 247 | 1 | 29 | 277 |
|
||||||
|
| src-tauri\src\serial_core | 6 | 247 | 1 | 29 | 277 |
|
||||||
|
| src-tauri\src\serial_core (Files) | 4 | 92 | 0 | 20 | 112 |
|
||||||
|
| src-tauri\src\serial_core\codecs | 2 | 155 | 1 | 9 | 165 |
|
||||||
|
+--------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||||
|
|
||||||
|
Files
|
||||||
|
+--------------------------------------------------------------------------+----------+------------+------------+------------+------------+
|
||||||
|
| filename | language | code | comment | blank | total |
|
||||||
|
+--------------------------------------------------------------------------+----------+------------+------------+------------+------------+
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\serial_core\codecs\tactile_a.rs | Rust | 153 | 0 | 11 | 164 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\serial_core\codecs\test.rs | Rust | 2 | 1 | -2 | 1 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\serial_core\error.rs | Rust | 2 | 0 | 0 | 2 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\serial_core\frame.rs | Rust | 1 | 0 | -1 | 0 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\serial_core\serial.rs | Rust | 68 | 0 | 14 | 82 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\serial_core\utils.rs | Rust | 21 | 0 | 7 | 28 |
|
||||||
|
| Total | | 247 | 1 | 29 | 277 |
|
||||||
|
+--------------------------------------------------------------------------+----------+------------+------------+------------+------------+
|
||||||
49
.VSCodeCounter/2026-04-02_14-42-07/results.csv
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
"filename", "language", "Markdown", "JSON with Comments", "JSON", "XML", "JavaScript", "HTML", "Rust", "TypeScript", "Svelte", "PostCSS", "comment", "blank", "total"
|
||||||
|
"e:\Workspace\JE-Skin\.idea\modules.xml", "XML", 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 8
|
||||||
|
"e:\Workspace\JE-Skin\.idea\tauri-demo.iml", "XML", 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 11
|
||||||
|
"e:\Workspace\JE-Skin\README.md", "Markdown", 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 54
|
||||||
|
"e:\Workspace\JE-Skin\flowus_tools.json", "JSON", 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2
|
||||||
|
"e:\Workspace\JE-Skin\frontend_prompt.md", "Markdown", 189, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66, 255
|
||||||
|
"e:\Workspace\JE-Skin\package-lock.json", "JSON", 0, 0, 1957, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1958
|
||||||
|
"e:\Workspace\JE-Skin\package.json", "JSON", 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 1, 32
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\build.rs", "Rust", 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1, 4
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\capabilities\default.json", "JSON", 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 1, 16
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\commands\mod.rs", "Rust", 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 3
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\commands\serial.rs", "Rust", 0, 0, 0, 0, 0, 0, 246, 0, 0, 0, 0, 44, 290
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\commands\window.rs", "Rust", 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 0, 6, 33
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\lib.rs", "Rust", 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 2, 24
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\log.rs", "Rust", 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 0, 2, 36
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\main.rs", "Rust", 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 1, 2, 11
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\serial_core\codec.rs", "Rust", 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 1, 7
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\serial_core\codecs\mod.rs", "Rust", 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 1, 5
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\serial_core\codecs\tactile_a.rs", "Rust", 0, 0, 0, 0, 0, 0, 220, 0, 0, 0, 0, 28, 248
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\serial_core\codecs\test.rs", "Rust", 0, 0, 0, 0, 0, 0, 215, 0, 0, 0, 8, 38, 261
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\serial_core\error.rs", "Rust", 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 6, 55
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\serial_core\frame.rs", "Rust", 0, 0, 0, 0, 0, 0, 47, 0, 0, 0, 3, 8, 58
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\serial_core\mod.rs", "Rust", 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 7, 29
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\serial_core\model.rs", "Rust", 0, 0, 0, 0, 0, 0, 377, 0, 0, 0, 57, 67, 501
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\serial_core\record.rs", "Rust", 0, 0, 0, 0, 0, 0, 50, 0, 0, 0, 4, 11, 65
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\serial_core\serial.rs", "Rust", 0, 0, 0, 0, 0, 0, 141, 0, 0, 0, 0, 22, 163
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\src\serial_core\utils.rs", "Rust", 0, 0, 0, 0, 0, 0, 47, 0, 0, 0, 0, 13, 60
|
||||||
|
"e:\Workspace\JE-Skin\src-tauri\tauri.conf.json", "JSON", 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 1, 37
|
||||||
|
"e:\Workspace\JE-Skin\src\app.html", "HTML", 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 1, 14
|
||||||
|
"e:\Workspace\JE-Skin\src\lib\components\CenterStage.svelte", "Svelte", 0, 0, 0, 0, 0, 0, 0, 0, 691, 0, 0, 96, 787
|
||||||
|
"e:\Workspace\JE-Skin\src\lib\components\ConfigPanel.svelte", "Svelte", 0, 0, 0, 0, 0, 0, 0, 0, 398, 0, 0, 63, 461
|
||||||
|
"e:\Workspace\JE-Skin\src\lib\components\HudPanel.svelte", "Svelte", 0, 0, 0, 0, 0, 0, 0, 0, 861, 0, 0, 110, 971
|
||||||
|
"e:\Workspace\JE-Skin\src\lib\components\PressureMatrixViewer.svelte", "Svelte", 0, 0, 0, 0, 0, 0, 0, 0, 558, 0, 0, 97, 655
|
||||||
|
"e:\Workspace\JE-Skin\src\lib\components\SignalChart.svelte", "Svelte", 0, 0, 0, 0, 0, 0, 0, 0, 382, 0, 0, 71, 453
|
||||||
|
"e:\Workspace\JE-Skin\src\lib\components\SummaryCurve.svelte", "Svelte", 0, 0, 0, 0, 0, 0, 0, 0, 497, 0, 0, 88, 585
|
||||||
|
"e:\Workspace\JE-Skin\src\lib\config\color-map.ts", "TypeScript", 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 3, 58
|
||||||
|
"e:\Workspace\JE-Skin\src\lib\styles\theme.css", "PostCSS", 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 1, 7, 51
|
||||||
|
"e:\Workspace\JE-Skin\src\lib\types\hud.ts", "TypeScript", 0, 0, 0, 0, 0, 0, 0, 126, 0, 0, 0, 20, 146
|
||||||
|
"e:\Workspace\JE-Skin\src\routes\+layout.svelte", "Svelte", 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 5, 18
|
||||||
|
"e:\Workspace\JE-Skin\src\routes\+layout.ts", "TypeScript", 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 4, 1, 6
|
||||||
|
"e:\Workspace\JE-Skin\src\routes\+page.svelte", "Svelte", 0, 0, 0, 0, 0, 0, 0, 0, 1286, 0, 0, 176, 1462
|
||||||
|
"e:\Workspace\JE-Skin\static\svelte.svg", "XML", 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1
|
||||||
|
"e:\Workspace\JE-Skin\static\tauri.svg", "XML", 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 1, 7
|
||||||
|
"e:\Workspace\JE-Skin\static\vite.svg", "XML", 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1
|
||||||
|
"e:\Workspace\JE-Skin\svelte.config.js", "JavaScript", 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 5, 3, 19
|
||||||
|
"e:\Workspace\JE-Skin\tauri-event.md", "Markdown", 374, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 181, 555
|
||||||
|
"e:\Workspace\JE-Skin\tsconfig.json", "JSON with Comments", 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 5, 1, 20
|
||||||
|
"e:\Workspace\JE-Skin\vite.config.js", "JavaScript", 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 7, 4, 33
|
||||||
|
"Total", "-", 597, 14, 2040, 27, 33, 13, 1520, 182, 4686, 43, 95, 1279, 10529
|
||||||
|
1
.VSCodeCounter/2026-04-02_14-42-07/results.json
Normal file
50
.VSCodeCounter/2026-04-02_14-42-07/results.md
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
# Summary
|
||||||
|
|
||||||
|
Date : 2026-04-02 14:42:07
|
||||||
|
|
||||||
|
Directory e:\\Workspace\\JE-Skin
|
||||||
|
|
||||||
|
Total : 47 files, 9155 codes, 95 comments, 1279 blanks, all 10529 lines
|
||||||
|
|
||||||
|
Summary / [Details](details.md) / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||||
|
|
||||||
|
## Languages
|
||||||
|
| language | files | code | comment | blank | total |
|
||||||
|
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||||
|
| Svelte | 8 | 4,686 | 0 | 706 | 5,392 |
|
||||||
|
| JSON | 5 | 2,040 | 0 | 5 | 2,045 |
|
||||||
|
| Rust | 18 | 1,520 | 73 | 260 | 1,853 |
|
||||||
|
| Markdown | 3 | 597 | 0 | 267 | 864 |
|
||||||
|
| TypeScript | 3 | 182 | 4 | 24 | 210 |
|
||||||
|
| PostCSS | 1 | 43 | 1 | 7 | 51 |
|
||||||
|
| JavaScript | 2 | 33 | 12 | 7 | 52 |
|
||||||
|
| XML | 5 | 27 | 0 | 1 | 28 |
|
||||||
|
| JSON with Comments | 1 | 14 | 5 | 1 | 20 |
|
||||||
|
| HTML | 1 | 13 | 0 | 1 | 14 |
|
||||||
|
|
||||||
|
## Directories
|
||||||
|
| path | files | code | comment | blank | total |
|
||||||
|
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||||||
|
| . | 47 | 9,155 | 95 | 1,279 | 10,529 |
|
||||||
|
| . (Files) | 9 | 2,633 | 17 | 278 | 2,928 |
|
||||||
|
| .idea | 2 | 19 | 0 | 0 | 19 |
|
||||||
|
| src | 13 | 4,924 | 5 | 738 | 5,667 |
|
||||||
|
| src (Files) | 1 | 13 | 0 | 1 | 14 |
|
||||||
|
| src-tauri | 20 | 1,571 | 73 | 262 | 1,906 |
|
||||||
|
| src-tauri (Files) | 2 | 39 | 0 | 2 | 41 |
|
||||||
|
| src-tauri\\capabilities | 1 | 15 | 0 | 1 | 16 |
|
||||||
|
| src-tauri\\src | 17 | 1,517 | 73 | 259 | 1,849 |
|
||||||
|
| src-tauri\\src (Files) | 3 | 64 | 1 | 6 | 71 |
|
||||||
|
| src-tauri\\src\\commands | 3 | 275 | 0 | 51 | 326 |
|
||||||
|
| src-tauri\\src\\serial_core | 11 | 1,178 | 72 | 202 | 1,452 |
|
||||||
|
| src-tauri\\src\\serial_core (Files) | 8 | 739 | 64 | 135 | 938 |
|
||||||
|
| src-tauri\\src\\serial_core\\codecs | 3 | 439 | 8 | 67 | 514 |
|
||||||
|
| src\\lib | 9 | 3,611 | 1 | 555 | 4,167 |
|
||||||
|
| src\\lib\\components | 6 | 3,387 | 0 | 525 | 3,912 |
|
||||||
|
| src\\lib\\config | 1 | 55 | 0 | 3 | 58 |
|
||||||
|
| src\\lib\\styles | 1 | 43 | 1 | 7 | 51 |
|
||||||
|
| src\\lib\\types | 1 | 126 | 0 | 20 | 146 |
|
||||||
|
| src\\routes | 3 | 1,300 | 4 | 182 | 1,486 |
|
||||||
|
| static | 3 | 8 | 0 | 1 | 9 |
|
||||||
|
|
||||||
|
Summary / [Details](details.md) / [Diff Summary](diff.md) / [Diff Details](diff-details.md)
|
||||||
100
.VSCodeCounter/2026-04-02_14-42-07/results.txt
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
Date : 2026-04-02 14:42:07
|
||||||
|
Directory : e:\Workspace\JE-Skin
|
||||||
|
Total : 47 files, 9155 codes, 95 comments, 1279 blanks, all 10529 lines
|
||||||
|
|
||||||
|
Languages
|
||||||
|
+--------------------+------------+------------+------------+------------+------------+
|
||||||
|
| language | files | code | comment | blank | total |
|
||||||
|
+--------------------+------------+------------+------------+------------+------------+
|
||||||
|
| Svelte | 8 | 4,686 | 0 | 706 | 5,392 |
|
||||||
|
| JSON | 5 | 2,040 | 0 | 5 | 2,045 |
|
||||||
|
| Rust | 18 | 1,520 | 73 | 260 | 1,853 |
|
||||||
|
| Markdown | 3 | 597 | 0 | 267 | 864 |
|
||||||
|
| TypeScript | 3 | 182 | 4 | 24 | 210 |
|
||||||
|
| PostCSS | 1 | 43 | 1 | 7 | 51 |
|
||||||
|
| JavaScript | 2 | 33 | 12 | 7 | 52 |
|
||||||
|
| XML | 5 | 27 | 0 | 1 | 28 |
|
||||||
|
| JSON with Comments | 1 | 14 | 5 | 1 | 20 |
|
||||||
|
| HTML | 1 | 13 | 0 | 1 | 14 |
|
||||||
|
+--------------------+------------+------------+------------+------------+------------+
|
||||||
|
|
||||||
|
Directories
|
||||||
|
+---------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||||
|
| path | files | code | comment | blank | total |
|
||||||
|
+---------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||||
|
| . | 47 | 9,155 | 95 | 1,279 | 10,529 |
|
||||||
|
| . (Files) | 9 | 2,633 | 17 | 278 | 2,928 |
|
||||||
|
| .idea | 2 | 19 | 0 | 0 | 19 |
|
||||||
|
| src | 13 | 4,924 | 5 | 738 | 5,667 |
|
||||||
|
| src (Files) | 1 | 13 | 0 | 1 | 14 |
|
||||||
|
| src-tauri | 20 | 1,571 | 73 | 262 | 1,906 |
|
||||||
|
| src-tauri (Files) | 2 | 39 | 0 | 2 | 41 |
|
||||||
|
| src-tauri\capabilities | 1 | 15 | 0 | 1 | 16 |
|
||||||
|
| src-tauri\src | 17 | 1,517 | 73 | 259 | 1,849 |
|
||||||
|
| src-tauri\src (Files) | 3 | 64 | 1 | 6 | 71 |
|
||||||
|
| src-tauri\src\commands | 3 | 275 | 0 | 51 | 326 |
|
||||||
|
| src-tauri\src\serial_core | 11 | 1,178 | 72 | 202 | 1,452 |
|
||||||
|
| src-tauri\src\serial_core (Files) | 8 | 739 | 64 | 135 | 938 |
|
||||||
|
| src-tauri\src\serial_core\codecs | 3 | 439 | 8 | 67 | 514 |
|
||||||
|
| src\lib | 9 | 3,611 | 1 | 555 | 4,167 |
|
||||||
|
| src\lib\components | 6 | 3,387 | 0 | 525 | 3,912 |
|
||||||
|
| src\lib\config | 1 | 55 | 0 | 3 | 58 |
|
||||||
|
| src\lib\styles | 1 | 43 | 1 | 7 | 51 |
|
||||||
|
| src\lib\types | 1 | 126 | 0 | 20 | 146 |
|
||||||
|
| src\routes | 3 | 1,300 | 4 | 182 | 1,486 |
|
||||||
|
| static | 3 | 8 | 0 | 1 | 9 |
|
||||||
|
+---------------------------------------------------------------------------+------------+------------+------------+------------+------------+
|
||||||
|
|
||||||
|
Files
|
||||||
|
+---------------------------------------------------------------------------+--------------------+------------+------------+------------+------------+
|
||||||
|
| filename | language | code | comment | blank | total |
|
||||||
|
+---------------------------------------------------------------------------+--------------------+------------+------------+------------+------------+
|
||||||
|
| e:\Workspace\JE-Skin\.idea\modules.xml | XML | 8 | 0 | 0 | 8 |
|
||||||
|
| e:\Workspace\JE-Skin\.idea\tauri-demo.iml | XML | 11 | 0 | 0 | 11 |
|
||||||
|
| e:\Workspace\JE-Skin\README.md | Markdown | 34 | 0 | 20 | 54 |
|
||||||
|
| e:\Workspace\JE-Skin\flowus_tools.json | JSON | 1 | 0 | 1 | 2 |
|
||||||
|
| e:\Workspace\JE-Skin\frontend_prompt.md | Markdown | 189 | 0 | 66 | 255 |
|
||||||
|
| e:\Workspace\JE-Skin\package-lock.json | JSON | 1,957 | 0 | 1 | 1,958 |
|
||||||
|
| e:\Workspace\JE-Skin\package.json | JSON | 31 | 0 | 1 | 32 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\build.rs | Rust | 3 | 0 | 1 | 4 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\capabilities\default.json | JSON | 15 | 0 | 1 | 16 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\commands\mod.rs | Rust | 2 | 0 | 1 | 3 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\commands\serial.rs | Rust | 246 | 0 | 44 | 290 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\commands\window.rs | Rust | 27 | 0 | 6 | 33 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\lib.rs | Rust | 22 | 0 | 2 | 24 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\log.rs | Rust | 34 | 0 | 2 | 36 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\main.rs | Rust | 8 | 1 | 2 | 11 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\serial_core\codec.rs | Rust | 6 | 0 | 1 | 7 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\serial_core\codecs\mod.rs | Rust | 4 | 0 | 1 | 5 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\serial_core\codecs\tactile_a.rs | Rust | 220 | 0 | 28 | 248 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\serial_core\codecs\test.rs | Rust | 215 | 8 | 38 | 261 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\serial_core\error.rs | Rust | 49 | 0 | 6 | 55 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\serial_core\frame.rs | Rust | 47 | 3 | 8 | 58 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\serial_core\mod.rs | Rust | 22 | 0 | 7 | 29 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\serial_core\model.rs | Rust | 377 | 57 | 67 | 501 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\serial_core\record.rs | Rust | 50 | 4 | 11 | 65 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\serial_core\serial.rs | Rust | 141 | 0 | 22 | 163 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\src\serial_core\utils.rs | Rust | 47 | 0 | 13 | 60 |
|
||||||
|
| e:\Workspace\JE-Skin\src-tauri\tauri.conf.json | JSON | 36 | 0 | 1 | 37 |
|
||||||
|
| e:\Workspace\JE-Skin\src\app.html | HTML | 13 | 0 | 1 | 14 |
|
||||||
|
| e:\Workspace\JE-Skin\src\lib\components\CenterStage.svelte | Svelte | 691 | 0 | 96 | 787 |
|
||||||
|
| e:\Workspace\JE-Skin\src\lib\components\ConfigPanel.svelte | Svelte | 398 | 0 | 63 | 461 |
|
||||||
|
| e:\Workspace\JE-Skin\src\lib\components\HudPanel.svelte | Svelte | 861 | 0 | 110 | 971 |
|
||||||
|
| e:\Workspace\JE-Skin\src\lib\components\PressureMatrixViewer.svelte | Svelte | 558 | 0 | 97 | 655 |
|
||||||
|
| e:\Workspace\JE-Skin\src\lib\components\SignalChart.svelte | Svelte | 382 | 0 | 71 | 453 |
|
||||||
|
| e:\Workspace\JE-Skin\src\lib\components\SummaryCurve.svelte | Svelte | 497 | 0 | 88 | 585 |
|
||||||
|
| e:\Workspace\JE-Skin\src\lib\config\color-map.ts | TypeScript | 55 | 0 | 3 | 58 |
|
||||||
|
| e:\Workspace\JE-Skin\src\lib\styles\theme.css | PostCSS | 43 | 1 | 7 | 51 |
|
||||||
|
| e:\Workspace\JE-Skin\src\lib\types\hud.ts | TypeScript | 126 | 0 | 20 | 146 |
|
||||||
|
| e:\Workspace\JE-Skin\src\routes\+layout.svelte | Svelte | 13 | 0 | 5 | 18 |
|
||||||
|
| e:\Workspace\JE-Skin\src\routes\+layout.ts | TypeScript | 1 | 4 | 1 | 6 |
|
||||||
|
| e:\Workspace\JE-Skin\src\routes\+page.svelte | Svelte | 1,286 | 0 | 176 | 1,462 |
|
||||||
|
| e:\Workspace\JE-Skin\static\svelte.svg | XML | 1 | 0 | 0 | 1 |
|
||||||
|
| e:\Workspace\JE-Skin\static\tauri.svg | XML | 6 | 0 | 1 | 7 |
|
||||||
|
| e:\Workspace\JE-Skin\static\vite.svg | XML | 1 | 0 | 0 | 1 |
|
||||||
|
| e:\Workspace\JE-Skin\svelte.config.js | JavaScript | 11 | 5 | 3 | 19 |
|
||||||
|
| e:\Workspace\JE-Skin\tauri-event.md | Markdown | 374 | 0 | 181 | 555 |
|
||||||
|
| e:\Workspace\JE-Skin\tsconfig.json | JSON with Comments | 14 | 5 | 1 | 20 |
|
||||||
|
| e:\Workspace\JE-Skin\vite.config.js | JavaScript | 22 | 7 | 4 | 33 |
|
||||||
|
| Total | | 9,155 | 95 | 1,279 | 10,529 |
|
||||||
|
+---------------------------------------------------------------------------+--------------------+------------+------------+------------+------------+
|
||||||
8
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "tauri-demo",
|
"name": "JE-Skin",
|
||||||
"version": "0.1.0",
|
"version": "0.3.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "tauri-demo",
|
"name": "JE-Skin",
|
||||||
"version": "0.1.0",
|
"version": "0.3.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "^2",
|
"@tauri-apps/api": "^2",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "tauri-demo",
|
"name": "JE-Skin",
|
||||||
"version": "0.1.0",
|
"version": "0.3.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
58
src-tauri/Cargo.lock
generated
@@ -2,6 +2,28 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 4
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "JE-Skin"
|
||||||
|
version = "0.3.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"async-trait",
|
||||||
|
"chrono",
|
||||||
|
"crc",
|
||||||
|
"csv",
|
||||||
|
"fern",
|
||||||
|
"humantime",
|
||||||
|
"log",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"tauri",
|
||||||
|
"tauri-build",
|
||||||
|
"tauri-plugin-opener",
|
||||||
|
"tokio",
|
||||||
|
"tokio-serial",
|
||||||
|
"tokio-util",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "adler2"
|
name = "adler2"
|
||||||
version = "2.0.1"
|
version = "2.0.1"
|
||||||
@@ -558,6 +580,21 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crc"
|
||||||
|
version = "3.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d"
|
||||||
|
dependencies = [
|
||||||
|
"crc-catalog",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crc-catalog"
|
||||||
|
version = "2.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crc32fast"
|
name = "crc32fast"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
@@ -3847,27 +3884,6 @@ dependencies = [
|
|||||||
"walkdir",
|
"walkdir",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tauri-demo"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"async-trait",
|
|
||||||
"chrono",
|
|
||||||
"csv",
|
|
||||||
"fern",
|
|
||||||
"humantime",
|
|
||||||
"log",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"tauri",
|
|
||||||
"tauri-build",
|
|
||||||
"tauri-plugin-opener",
|
|
||||||
"tokio",
|
|
||||||
"tokio-serial",
|
|
||||||
"tokio-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-macros"
|
name = "tauri-macros"
|
||||||
version = "2.5.5"
|
version = "2.5.5"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tauri-demo"
|
name = "JE-Skin"
|
||||||
version = "0.1.0"
|
version = "0.3.0"
|
||||||
description = "A Tauri App"
|
description = "A Tauri App"
|
||||||
authors = ["you"]
|
authors = ["you"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
@@ -32,3 +32,4 @@ log = "0.4.29"
|
|||||||
humantime = "2.3.0"
|
humantime = "2.3.0"
|
||||||
csv = "1.4.0"
|
csv = "1.4.0"
|
||||||
chrono = "0.4.44"
|
chrono = "0.4.44"
|
||||||
|
crc = "3.4.0"
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 906 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 906 KiB After Width: | Height: | Size: 28 KiB |
BIN
src-tauri/icons/16x16.png
Normal file
|
After Width: | Height: | Size: 715 B |
BIN
src-tauri/icons/192x192.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
src-tauri/icons/256x256.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 906 KiB After Width: | Height: | Size: 1.6 KiB |
BIN
src-tauri/icons/512x512.png
Normal file
|
After Width: | Height: | Size: 114 KiB |
BIN
src-tauri/icons/64x64.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
src-tauri/icons/Square107x107Logo.png
Normal file
|
After Width: | Height: | Size: 8.2 KiB |
BIN
src-tauri/icons/Square142x142Logo.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
src-tauri/icons/Square150x150Logo.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
src-tauri/icons/Square284x284Logo.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
src-tauri/icons/Square30x30Logo.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
src-tauri/icons/Square310x310Logo.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
src-tauri/icons/Square44x44Logo.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
src-tauri/icons/Square71x71Logo.png
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
src-tauri/icons/Square89x89Logo.png
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
BIN
src-tauri/icons/StoreLogo.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||||
|
<background android:drawable="@color/ic_launcher_background"/>
|
||||||
|
</adaptive-icon>
|
||||||
BIN
src-tauri/icons/android/mipmap-hdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
src-tauri/icons/android/mipmap-mdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 8.4 KiB |
BIN
src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
BIN
src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 63 KiB |
BIN
src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="ic_launcher_background">#fff</color>
|
||||||
|
</resources>
|
||||||
BIN
src-tauri/icons/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
src-tauri/icons/icon.icns
Normal file
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 906 KiB After Width: | Height: | Size: 81 KiB |
BIN
src-tauri/icons/ios/AppIcon-20x20@1x.png
Normal file
|
After Width: | Height: | Size: 806 B |
BIN
src-tauri/icons/ios/AppIcon-20x20@2x-1.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
src-tauri/icons/ios/AppIcon-20x20@2x.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
src-tauri/icons/ios/AppIcon-20x20@3x.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
src-tauri/icons/ios/AppIcon-29x29@1x.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
src-tauri/icons/ios/AppIcon-29x29@2x-1.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
src-tauri/icons/ios/AppIcon-29x29@2x.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
src-tauri/icons/ios/AppIcon-29x29@3x.png
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
BIN
src-tauri/icons/ios/AppIcon-40x40@1x.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
src-tauri/icons/ios/AppIcon-40x40@2x-1.png
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
src-tauri/icons/ios/AppIcon-40x40@2x.png
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
src-tauri/icons/ios/AppIcon-40x40@3x.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
BIN
src-tauri/icons/ios/AppIcon-512@2x.png
Normal file
|
After Width: | Height: | Size: 212 KiB |
BIN
src-tauri/icons/ios/AppIcon-60x60@2x.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
BIN
src-tauri/icons/ios/AppIcon-60x60@3x.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
src-tauri/icons/ios/AppIcon-76x76@1x.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
src-tauri/icons/ios/AppIcon-76x76@2x.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
306
src-tauri/program.log2026-04-08
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
[2026-04-08T03:07:37Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T03:07:37Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T03:09:47Z [37mDEBUG[0m tao::platform_impl::platform::event_loop::runner] NewEvents emitted without explicit RedrawEventsCleared
|
||||||
|
[2026-04-08T03:09:47Z [37mDEBUG[0m tao::platform_impl::platform::event_loop::runner] RedrawEventsCleared emitted without explicit MainEventsCleared
|
||||||
|
[2026-04-08T03:12:49Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T03:12:49Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T03:15:23Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T03:15:23Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T03:15:36Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T03:15:36Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T03:15:36Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T03:15:36Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T03:15:36Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T03:15:55Z [32mINFO[0m tauri_demo_lib::commands::serial] last_record has 1704 frames
|
||||||
|
[2026-04-08T03:16:08Z [37mDEBUG[0m tao::platform_impl::platform::event_loop::runner] NewEvents emitted without explicit RedrawEventsCleared
|
||||||
|
[2026-04-08T03:16:08Z [37mDEBUG[0m tao::platform_impl::platform::event_loop::runner] RedrawEventsCleared emitted without explicit MainEventsCleared
|
||||||
|
[2026-04-08T03:17:59Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T03:17:59Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T03:17:59Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T03:17:59Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T03:17:59Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T03:18:04Z [32mINFO[0m tauri_demo_lib::commands::serial] last_record has 485 frames
|
||||||
|
[2026-04-08T03:18:13Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T03:18:13Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T03:18:13Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T03:18:13Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T03:18:13Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T03:24:54Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T03:24:54Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T03:25:10Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T03:25:10Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T03:25:10Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T03:25:10Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T03:25:10Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T03:25:24Z [32mINFO[0m tauri_demo_lib::commands::serial] last_record has 1226 frames
|
||||||
|
[2026-04-08T03:30:00Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T03:30:00Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T03:30:00Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T03:30:00Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T03:30:00Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T03:30:56Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T03:30:56Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T03:31:17Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T03:31:17Z [37mDEBUG[0m mio_serial] switching COM1 to asynchronous mode
|
||||||
|
[2026-04-08T03:31:17Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T03:31:17Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T03:31:17Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T03:31:20Z [32mINFO[0m tauri_demo_lib::commands::serial] last_record has 0 frames
|
||||||
|
[2026-04-08T03:31:22Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T03:31:22Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T03:31:22Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T03:31:22Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T03:31:22Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T03:34:36Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T03:34:36Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T03:34:42Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T03:34:42Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T03:34:42Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T03:34:42Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T03:34:42Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T03:34:47Z [32mINFO[0m tauri_demo_lib::commands::serial] last_record has 457 frames
|
||||||
|
[2026-04-08T03:34:55Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T03:34:55Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T03:34:55Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T03:34:55Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T03:34:55Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T03:36:11Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T03:36:11Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T03:36:25Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T03:36:25Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T03:36:25Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T03:36:25Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T03:36:25Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T03:38:27Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T03:38:27Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T03:40:51Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T03:40:51Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T03:41:05Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T03:41:05Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T03:41:05Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T03:41:05Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T03:41:05Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T03:42:25Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T03:42:25Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T05:39:52Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T05:39:52Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T05:41:00Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T05:41:00Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T05:41:05Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T05:41:05Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T05:41:05Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T05:41:05Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T05:41:05Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T05:44:17Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T05:44:17Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T05:44:22Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T05:44:22Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T05:44:22Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T05:44:22Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T05:44:22Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T05:48:46Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T05:48:46Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T05:48:56Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T05:48:56Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T05:48:56Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T05:48:56Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T05:48:56Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T05:51:41Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T05:51:41Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T05:51:45Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T05:51:45Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T05:51:45Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T05:51:45Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T05:51:45Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T05:52:07Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T05:52:07Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T05:53:57Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T05:53:57Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T05:54:02Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T05:54:02Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T05:54:02Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T05:54:02Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T05:54:02Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T05:57:11Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T05:57:11Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T05:57:23Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T05:57:23Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T05:57:23Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T05:57:23Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T05:57:23Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T05:59:05Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T05:59:05Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T05:59:21Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T05:59:21Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T05:59:21Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T05:59:21Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T05:59:21Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T06:03:12Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T06:03:12Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T06:03:33Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T06:03:33Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T06:03:33Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T06:03:33Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T06:03:33Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T06:03:50Z [32mINFO[0m tauri_demo_lib::commands::serial] last_record has 1610 frames
|
||||||
|
[2026-04-08T06:04:02Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T06:04:02Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T06:04:02Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T06:04:02Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T06:04:02Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T06:19:31Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T06:19:31Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T06:23:22Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T06:23:22Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T06:25:37Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T06:25:37Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T06:26:54Z [37mDEBUG[0m tao::platform_impl::platform::event_loop::runner] NewEvents emitted without explicit RedrawEventsCleared
|
||||||
|
[2026-04-08T06:26:54Z [37mDEBUG[0m tao::platform_impl::platform::event_loop::runner] RedrawEventsCleared emitted without explicit MainEventsCleared
|
||||||
|
[2026-04-08T06:27:17Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T06:27:17Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T06:27:26Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T06:27:26Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T06:27:27Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T06:27:27Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T06:27:28Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T06:27:28Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T06:27:29Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T06:27:29Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T06:27:30Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T06:27:30Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T06:28:58Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T06:28:58Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T06:29:37Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T06:29:37Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T06:41:34Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T06:41:34Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T06:43:41Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T06:43:41Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T06:46:02Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T06:46:02Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T06:47:57Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T06:47:57Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T06:48:25Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T06:48:25Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:08:08Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T07:08:08Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:08:29Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T07:08:29Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T07:08:29Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T07:08:29Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T07:08:29Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T07:08:33Z [32mINFO[0m tauri_demo_lib::commands::serial] last_record has 381 frames
|
||||||
|
[2026-04-08T07:08:42Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T07:08:42Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T07:08:42Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T07:08:42Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T07:08:42Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T07:11:03Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T07:11:03Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:11:12Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T07:11:12Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T07:11:12Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T07:11:12Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T07:11:12Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T07:11:16Z [32mINFO[0m tauri_demo_lib::commands::serial] last_record has 276 frames
|
||||||
|
[2026-04-08T07:14:06Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T07:14:06Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T07:14:06Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T07:14:06Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T07:14:06Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T07:14:08Z [32mINFO[0m tauri_demo_lib::commands::serial] last_record has 183 frames
|
||||||
|
[2026-04-08T07:16:20Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T07:16:20Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:16:52Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T07:16:52Z [37mDEBUG[0m mio_serial] switching COM1 to asynchronous mode
|
||||||
|
[2026-04-08T07:16:52Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T07:16:52Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T07:16:52Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T07:16:52Z [32mINFO[0m tauri_demo_lib::commands::serial] last_record has 0 frames
|
||||||
|
[2026-04-08T07:16:56Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T07:16:56Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T07:16:56Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T07:16:56Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T07:16:56Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T07:17:36Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T07:17:36Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:17:47Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T07:17:47Z [37mDEBUG[0m mio_serial] switching COM1 to asynchronous mode
|
||||||
|
[2026-04-08T07:17:47Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T07:17:47Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T07:17:47Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T07:17:49Z [32mINFO[0m tauri_demo_lib::commands::serial] last_record has 0 frames
|
||||||
|
[2026-04-08T07:17:53Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T07:17:53Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T07:17:53Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T07:17:53Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T07:17:53Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T07:18:08Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T07:18:08Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:18:50Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T07:18:50Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:18:57Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T07:18:57Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:19:10Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T07:19:10Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:19:14Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T07:19:14Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T07:19:14Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T07:19:14Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T07:19:14Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T07:19:17Z [32mINFO[0m tauri_demo_lib::commands::serial] last_record has 227 frames
|
||||||
|
[2026-04-08T07:19:29Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T07:19:29Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T07:19:29Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T07:19:29Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T07:19:29Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T07:19:38Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T07:19:38Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:19:56Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T07:19:56Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:20:10Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T07:20:10Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T07:20:10Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T07:20:10Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T07:20:10Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T07:20:41Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T07:20:41Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:20:46Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T07:20:46Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T07:20:46Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T07:20:46Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T07:20:46Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T07:20:57Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T07:20:57Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:22:12Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T07:22:12Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:22:30Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T07:22:30Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T07:22:30Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T07:22:30Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T07:22:30Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T07:22:38Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T07:22:38Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:23:10Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T07:23:10Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:23:18Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T07:23:18Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T07:23:18Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T07:23:18Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T07:23:18Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T07:23:24Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T07:23:24Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:33:13Z [37mDEBUG[0m tauri_demo_lib::log] logging initialized
|
||||||
|
[2026-04-08T07:33:13Z [37mDEBUG[0m JE_Skin] logging initialized
|
||||||
|
[2026-04-08T07:33:18Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T07:33:18Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T07:33:18Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T07:33:18Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T07:33:18Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T07:33:24Z [32mINFO[0m tauri_demo_lib::commands::serial] last_record has 499 frames
|
||||||
|
[2026-04-08T07:33:31Z [37mDEBUG[0m mio_serial] opening serial port in synchronous blocking mode
|
||||||
|
[2026-04-08T07:33:31Z [37mDEBUG[0m mio_serial] switching COM5 to asynchronous mode
|
||||||
|
[2026-04-08T07:33:31Z [37mDEBUG[0m mio_serial] reading serial port settings
|
||||||
|
[2026-04-08T07:33:31Z [37mDEBUG[0m mio_serial] closing synchronous port to re-open in FILE_FLAG_OVERLAPPED mode
|
||||||
|
[2026-04-08T07:33:31Z [37mDEBUG[0m mio_serial] re-setting serial port parameters to original values from synchronous port
|
||||||
|
[2026-04-08T07:34:06Z [32mINFO[0m tauri_demo_lib::commands::serial] last_record has 3160 frames
|
||||||
208
src-tauri/src/commands/file_explorer.rs
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
use serde::Serialize;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use std::fs;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::time::UNIX_EPOCH;
|
||||||
|
use tauri::{AppHandle, Manager};
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct FileExplorerRoot {
|
||||||
|
pub label: String,
|
||||||
|
pub path: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct FileExplorerEntry {
|
||||||
|
pub name: String,
|
||||||
|
pub path: String,
|
||||||
|
pub is_dir: bool,
|
||||||
|
pub size_bytes: Option<u64>,
|
||||||
|
pub modified_ms: Option<u128>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct FileExplorerListResponse {
|
||||||
|
pub current_path: String,
|
||||||
|
pub parent_path: Option<String>,
|
||||||
|
pub roots: Vec<FileExplorerRoot>,
|
||||||
|
pub entries: Vec<FileExplorerEntry>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn file_explorer_list(
|
||||||
|
app: AppHandle,
|
||||||
|
path: Option<String>,
|
||||||
|
extensions: Option<Vec<String>>,
|
||||||
|
) -> Result<FileExplorerListResponse, String> {
|
||||||
|
let current_path = resolve_start_path(&app, path)?;
|
||||||
|
let extension_filter = normalize_extensions(extensions);
|
||||||
|
|
||||||
|
let mut entries = fs::read_dir(¤t_path)
|
||||||
|
.map_err(|err| format!("Failed to read '{}': {err}", current_path.display()))?
|
||||||
|
.filter_map(Result::ok)
|
||||||
|
.filter_map(|entry| {
|
||||||
|
let file_type = entry.file_type().ok()?;
|
||||||
|
let metadata = entry.metadata().ok();
|
||||||
|
let is_dir = file_type.is_dir();
|
||||||
|
let path = entry.path();
|
||||||
|
|
||||||
|
if !is_dir && !extension_filter.is_empty() {
|
||||||
|
let extension = path
|
||||||
|
.extension()
|
||||||
|
.and_then(|ext| ext.to_str())
|
||||||
|
.map(|ext| ext.to_ascii_lowercase())
|
||||||
|
.unwrap_or_default();
|
||||||
|
if !extension_filter.contains(&extension) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let name = entry.file_name().to_string_lossy().to_string();
|
||||||
|
let size_bytes = if is_dir {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
metadata.as_ref().map(|value| value.len())
|
||||||
|
};
|
||||||
|
let modified_ms = metadata
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|value| value.modified().ok())
|
||||||
|
.and_then(|value| value.duration_since(UNIX_EPOCH).ok())
|
||||||
|
.map(|value| value.as_millis());
|
||||||
|
|
||||||
|
Some(FileExplorerEntry {
|
||||||
|
name,
|
||||||
|
path: path.display().to_string(),
|
||||||
|
is_dir,
|
||||||
|
size_bytes,
|
||||||
|
modified_ms,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
entries.sort_by(|left, right| {
|
||||||
|
if left.is_dir != right.is_dir {
|
||||||
|
return right.is_dir.cmp(&left.is_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
left.name
|
||||||
|
.to_ascii_lowercase()
|
||||||
|
.cmp(&right.name.to_ascii_lowercase())
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(FileExplorerListResponse {
|
||||||
|
current_path: current_path.display().to_string(),
|
||||||
|
parent_path: current_path.parent().map(|parent| parent.display().to_string()),
|
||||||
|
roots: collect_roots(&app),
|
||||||
|
entries,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn normalize_extensions(extensions: Option<Vec<String>>) -> HashSet<String> {
|
||||||
|
extensions
|
||||||
|
.unwrap_or_default()
|
||||||
|
.into_iter()
|
||||||
|
.map(|value| value.trim().trim_start_matches('.').to_ascii_lowercase())
|
||||||
|
.filter(|value| !value.is_empty())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_start_path(app: &AppHandle, raw_path: Option<String>) -> Result<PathBuf, String> {
|
||||||
|
if let Some(value) = raw_path {
|
||||||
|
let trimmed = value.trim();
|
||||||
|
if trimmed.is_empty() {
|
||||||
|
return resolve_default_path(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut candidate = PathBuf::from(trimmed);
|
||||||
|
if candidate.is_relative() {
|
||||||
|
candidate = std::env::current_dir()
|
||||||
|
.map_err(|err| format!("Failed to read current dir: {err}"))?
|
||||||
|
.join(candidate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !candidate.exists() {
|
||||||
|
return Err(format!("Path does not exist: {}", candidate.display()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if candidate.is_file() {
|
||||||
|
return candidate
|
||||||
|
.parent()
|
||||||
|
.map(|parent| parent.to_path_buf())
|
||||||
|
.ok_or_else(|| format!("No parent directory for {}", candidate.display()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(candidate);
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve_default_path(app)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_default_path(app: &AppHandle) -> Result<PathBuf, String> {
|
||||||
|
if let Ok(path) = app.path().desktop_dir() {
|
||||||
|
return Ok(path);
|
||||||
|
}
|
||||||
|
if let Ok(path) = app.path().document_dir() {
|
||||||
|
return Ok(path);
|
||||||
|
}
|
||||||
|
if let Ok(path) = app.path().download_dir() {
|
||||||
|
return Ok(path);
|
||||||
|
}
|
||||||
|
if let Ok(path) = app.path().home_dir() {
|
||||||
|
return Ok(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::env::current_dir().map_err(|err| format!("Failed to resolve default path: {err}"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_roots(app: &AppHandle) -> Vec<FileExplorerRoot> {
|
||||||
|
let mut roots = Vec::new();
|
||||||
|
let mut seen = HashSet::new();
|
||||||
|
|
||||||
|
let mut push_root = |label: &str, path: PathBuf| {
|
||||||
|
let normalized = path.display().to_string();
|
||||||
|
if normalized.is_empty() || !Path::new(&normalized).exists() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if seen.insert(normalized.clone()) {
|
||||||
|
roots.push(FileExplorerRoot {
|
||||||
|
label: label.to_string(),
|
||||||
|
path: normalized,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Ok(path) = app.path().desktop_dir() {
|
||||||
|
push_root("Desktop", path);
|
||||||
|
}
|
||||||
|
if let Ok(path) = app.path().document_dir() {
|
||||||
|
push_root("Documents", path);
|
||||||
|
}
|
||||||
|
if let Ok(path) = app.path().download_dir() {
|
||||||
|
push_root("Downloads", path);
|
||||||
|
}
|
||||||
|
if let Ok(path) = app.path().home_dir() {
|
||||||
|
push_root("Home", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
{
|
||||||
|
for letter in b'A'..=b'Z' {
|
||||||
|
let drive = format!("{}:\\", letter as char);
|
||||||
|
let drive_path = PathBuf::from(&drive);
|
||||||
|
if drive_path.exists() {
|
||||||
|
push_root(&format!("{}:", letter as char), drive_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
{
|
||||||
|
push_root("Root", PathBuf::from("/"));
|
||||||
|
}
|
||||||
|
|
||||||
|
roots
|
||||||
|
}
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
|
pub mod file_explorer;
|
||||||
pub mod serial;
|
pub mod serial;
|
||||||
pub mod window;
|
pub mod window;
|
||||||
|
|||||||
@@ -1,18 +1,27 @@
|
|||||||
use crate::serial_core::codecs::test::{export_recording_csv, TestCodec, TestCsvImporter, TestHandler};
|
use crate::serial_core::codecs::tactile_a::{
|
||||||
|
export_recording_csv, TactileACodec, TactileACsvImporter, TactileAHandler,
|
||||||
|
};
|
||||||
use crate::serial_core::error::SerialError;
|
use crate::serial_core::error::SerialError;
|
||||||
use crate::serial_core::record::CsvImporter;
|
use crate::serial_core::record::CsvImporter;
|
||||||
use crate::serial_core::{TestRecording, serial};
|
use crate::serial_core::serial::{PollMode, TactileAPollRequester};
|
||||||
|
use crate::serial_core::{serial, TactileARecording};
|
||||||
use log::info;
|
use log::info;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::time::{Instant, SystemTime, UNIX_EPOCH};
|
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
|
||||||
use tauri::{async_runtime::JoinHandle, AppHandle, Manager, State};
|
use tauri::{async_runtime::JoinHandle, AppHandle, Manager, State};
|
||||||
use tokio_serial::{available_ports, SerialPortBuilderExt};
|
use tokio_serial::{available_ports, SerialPortBuilderExt};
|
||||||
use tokio_util::sync::CancellationToken;
|
use tokio_util::sync::CancellationToken;
|
||||||
|
|
||||||
type SharedTestRecording = Arc<Mutex<TestRecording>>;
|
const DEFAULT_TACTILE_COLS: usize = 7;
|
||||||
|
const DEFAULT_TACTILE_ROWS: usize = 12;
|
||||||
|
const DEFAULT_TACTILE_POLL_INTERVAL_MS: u64 = 10;
|
||||||
|
const DEFAULT_TACTILE_REPLY_TIMEOUT_MS: u64 = 140;
|
||||||
|
|
||||||
|
type SharedTactileRecording = Arc<Mutex<TactileARecording>>;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
@@ -48,17 +57,58 @@ pub struct SerialImportResponse {
|
|||||||
pub message: String,
|
pub message: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct SerialRecordStateResponse {
|
||||||
|
pub has_data: bool,
|
||||||
|
pub frame_count: usize,
|
||||||
|
}
|
||||||
|
|
||||||
struct SerialSession {
|
struct SerialSession {
|
||||||
port: String,
|
port: String,
|
||||||
cancel: CancellationToken,
|
cancel: CancellationToken,
|
||||||
task: JoinHandle<()>,
|
task: JoinHandle<()>,
|
||||||
current_record: SharedTestRecording,
|
current_record: SharedTactileRecording,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct SerialConnectionState {
|
pub struct SerialConnectionState {
|
||||||
session: Mutex<Option<SerialSession>>,
|
session: Mutex<Option<SerialSession>>,
|
||||||
last_record: Mutex<Option<SharedTestRecording>>
|
last_record: Mutex<Option<SharedTactileRecording>>
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn shutdown_active_session(
|
||||||
|
state: &SerialConnectionState,
|
||||||
|
) -> Result<Option<(String, SharedTactileRecording)>, SerialError> {
|
||||||
|
let session = {
|
||||||
|
let mut guard = state.session.lock().map_err(|_| SerialError::StateError)?;
|
||||||
|
guard.take()
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(SerialSession {
|
||||||
|
port,
|
||||||
|
cancel,
|
||||||
|
task,
|
||||||
|
current_record,
|
||||||
|
}) = session else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
|
||||||
|
cancel.cancel();
|
||||||
|
let _ = task.await;
|
||||||
|
|
||||||
|
let frame_count = current_record
|
||||||
|
.lock()
|
||||||
|
.map(|record| record.frames.len())
|
||||||
|
.unwrap_or(0);
|
||||||
|
|
||||||
|
info!("last_record has {} frames", frame_count);
|
||||||
|
|
||||||
|
if let Ok(mut last_record) = state.last_record.lock() {
|
||||||
|
*last_record = Some(current_record.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Some((port, current_record)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
@@ -91,22 +141,28 @@ pub async fn serial_connect(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let cancel = CancellationToken::new();
|
let cancel = CancellationToken::new();
|
||||||
let current_record = Arc::new(Mutex::new(TestRecording::new()));
|
let current_record = Arc::new(Mutex::new(TactileARecording::new()));
|
||||||
let task_record = current_record.clone();
|
let task_record = current_record.clone();
|
||||||
let task_cancel = cancel.clone();
|
let task_cancel = cancel.clone();
|
||||||
let task_app = app.clone();
|
let task_app = app.clone();
|
||||||
let task_port_name = port_name.clone();
|
let task_port_name = port_name.clone();
|
||||||
|
|
||||||
let port = tokio_serial::new(&port_name, 115200)
|
let port = tokio_serial::new(&port_name, 921600)
|
||||||
.open_native_async()
|
.open_native_async()
|
||||||
.map_err(|_| SerialError::OpenError)?;
|
.map_err(|_| SerialError::OpenError)?;
|
||||||
let session_started_at = Instant::now();
|
let session_started_at = Instant::now();
|
||||||
|
|
||||||
let task = tauri::async_runtime::spawn(async move {
|
let task = tauri::async_runtime::spawn(async move {
|
||||||
let codec = TestCodec::new();
|
let codec = TactileACodec::new(DEFAULT_TACTILE_COLS, DEFAULT_TACTILE_ROWS);
|
||||||
let handler = TestHandler;
|
let handler = TactileAHandler;
|
||||||
|
let poll_mode = PollMode::Enabled(Box::new(TactileAPollRequester::new(
|
||||||
|
Duration::from_millis(DEFAULT_TACTILE_POLL_INTERVAL_MS),
|
||||||
|
DEFAULT_TACTILE_COLS,
|
||||||
|
DEFAULT_TACTILE_ROWS,
|
||||||
|
Duration::from_millis(DEFAULT_TACTILE_REPLY_TIMEOUT_MS),
|
||||||
|
)));
|
||||||
|
|
||||||
if let Err(error) = serial::run_serial(
|
if let Err(error) = serial::run_serial_with_poll(
|
||||||
task_app.clone(),
|
task_app.clone(),
|
||||||
port,
|
port,
|
||||||
codec,
|
codec,
|
||||||
@@ -114,6 +170,7 @@ pub async fn serial_connect(
|
|||||||
session_started_at,
|
session_started_at,
|
||||||
task_record.clone(),
|
task_record.clone(),
|
||||||
task_cancel,
|
task_cancel,
|
||||||
|
poll_mode,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
@@ -167,17 +224,7 @@ pub async fn serial_connect(
|
|||||||
pub async fn serial_disconnect(
|
pub async fn serial_disconnect(
|
||||||
state: State<'_, SerialConnectionState>,
|
state: State<'_, SerialConnectionState>,
|
||||||
) -> Result<SerialConnectResponse, SerialError> {
|
) -> Result<SerialConnectResponse, SerialError> {
|
||||||
let session = {
|
let Some((port, _current_record)) = shutdown_active_session(&state).await?
|
||||||
let mut guard = state.session.lock().map_err(|_| SerialError::StateError)?;
|
|
||||||
guard.take()
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(SerialSession {
|
|
||||||
port,
|
|
||||||
cancel,
|
|
||||||
task,
|
|
||||||
current_record,
|
|
||||||
}) = session
|
|
||||||
else {
|
else {
|
||||||
return Ok(SerialConnectResponse {
|
return Ok(SerialConnectResponse {
|
||||||
port: String::new(),
|
port: String::new(),
|
||||||
@@ -186,19 +233,6 @@ pub async fn serial_disconnect(
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
cancel.cancel();
|
|
||||||
let _ = task.await;
|
|
||||||
let frame_count = current_record.lock().map(|record| {
|
|
||||||
record.frames.len()
|
|
||||||
}).unwrap_or(0);
|
|
||||||
|
|
||||||
info!("last_record has {} frames", frame_count);
|
|
||||||
|
|
||||||
if let Ok(mut last_record) = state.last_record.lock() {
|
|
||||||
*last_record = Some(current_record);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Ok(SerialConnectResponse {
|
Ok(SerialConnectResponse {
|
||||||
port,
|
port,
|
||||||
connected: false,
|
connected: false,
|
||||||
@@ -211,20 +245,6 @@ pub fn serial_export_csv(
|
|||||||
app: AppHandle,
|
app: AppHandle,
|
||||||
state: State<'_, SerialConnectionState>,
|
state: State<'_, SerialConnectionState>,
|
||||||
) -> Result<SerialExportResponse, SerialError> {
|
) -> Result<SerialExportResponse, SerialError> {
|
||||||
let current_record = {
|
|
||||||
let session = state.session.lock().map_err(|_| SerialError::StateError)?;
|
|
||||||
session
|
|
||||||
.as_ref()
|
|
||||||
.map(|current_session| current_session.current_record.clone())
|
|
||||||
};
|
|
||||||
|
|
||||||
let record = if let Some(recording) = current_record {
|
|
||||||
recording
|
|
||||||
} else {
|
|
||||||
let last_record = state.last_record.lock().map_err(|_| SerialError::StateError)?;
|
|
||||||
last_record.clone().ok_or(SerialError::NoRecordedData)?
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut output_dir = match app.path().desktop_dir() {
|
let mut output_dir = match app.path().desktop_dir() {
|
||||||
Ok(path) => path,
|
Ok(path) => path,
|
||||||
Err(_) => std::env::current_dir().map_err(|_| SerialError::ExportError)?,
|
Err(_) => std::env::current_dir().map_err(|_| SerialError::ExportError)?,
|
||||||
@@ -236,17 +256,8 @@ pub fn serial_export_csv(
|
|||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
output_dir.push(format!("joyson_export_{timestamp}.csv"));
|
output_dir.push(format!("joyson_export_{timestamp}.csv"));
|
||||||
let mut file = File::create(&output_dir).map_err(|_| SerialError::ExportError)?;
|
let record = resolve_record_for_export(&state)?;
|
||||||
|
let frame_count = write_record_to_csv(record, &output_dir)?;
|
||||||
let frame_count = {
|
|
||||||
let recording = record.lock().map_err(|_| SerialError::StateError)?;
|
|
||||||
if recording.frames.is_empty() {
|
|
||||||
return Err(SerialError::NoRecordedData);
|
|
||||||
}
|
|
||||||
|
|
||||||
export_recording_csv(&recording, &mut file).map_err(|_| SerialError::ExportError)?;
|
|
||||||
recording.frames.len()
|
|
||||||
};
|
|
||||||
|
|
||||||
let path = output_dir.display().to_string();
|
let path = output_dir.display().to_string();
|
||||||
info!("csv exported to {path}, frame_count={frame_count}");
|
info!("csv exported to {path}, frame_count={frame_count}");
|
||||||
@@ -258,9 +269,40 @@ pub fn serial_export_csv(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn serial_has_record_data(
|
||||||
|
state: State<'_, SerialConnectionState>,
|
||||||
|
) -> Result<SerialRecordStateResponse, SerialError> {
|
||||||
|
let frame_count = snapshot_record_frame_count(&state)?;
|
||||||
|
|
||||||
|
Ok(SerialRecordStateResponse {
|
||||||
|
has_data: frame_count > 0,
|
||||||
|
frame_count,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn serial_export_csv_to_path(
|
||||||
|
file_path: String,
|
||||||
|
state: State<'_, SerialConnectionState>,
|
||||||
|
) -> Result<SerialExportResponse, SerialError> {
|
||||||
|
let output_path = resolve_export_path(file_path)?;
|
||||||
|
let record = resolve_record_for_export(&state)?;
|
||||||
|
let frame_count = write_record_to_csv(record, &output_path)?;
|
||||||
|
let path = output_path.display().to_string();
|
||||||
|
|
||||||
|
info!("csv exported to {path}, frame_count={frame_count}");
|
||||||
|
|
||||||
|
Ok(SerialExportResponse {
|
||||||
|
path,
|
||||||
|
frame_count,
|
||||||
|
message: "exported".to_string(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn serial_import_csv(file_name: String, csv_content: String) -> Result<SerialImportResponse, SerialError> {
|
pub fn serial_import_csv(file_name: String, csv_content: String) -> Result<SerialImportResponse, SerialError> {
|
||||||
let mut importer = TestCsvImporter::new(file_name.as_str());
|
let mut importer = TactileACsvImporter::new(file_name.as_str());
|
||||||
let packets = importer
|
let packets = importer
|
||||||
.load(Cursor::new(csv_content.into_bytes()))
|
.load(Cursor::new(csv_content.into_bytes()))
|
||||||
.map_err(|_| SerialError::ImportError)?;
|
.map_err(|_| SerialError::ImportError)?;
|
||||||
@@ -287,3 +329,128 @@ pub fn serial_import_csv(file_name: String, csv_content: String) -> Result<Seria
|
|||||||
message: "imported".to_string(),
|
message: "imported".to_string(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub fn serial_import_csv_from_path(file_path: String) -> Result<SerialImportResponse, SerialError> {
|
||||||
|
let path = resolve_import_path(file_path)?;
|
||||||
|
let file_name = path
|
||||||
|
.file_name()
|
||||||
|
.and_then(|value| value.to_str())
|
||||||
|
.map(ToOwned::to_owned)
|
||||||
|
.unwrap_or_else(|| "import.csv".to_string());
|
||||||
|
|
||||||
|
let bytes = std::fs::read(&path).map_err(|_| SerialError::ImportError)?;
|
||||||
|
let csv_content = String::from_utf8_lossy(&bytes).to_string();
|
||||||
|
serial_import_csv(file_name, csv_content)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_record_for_export(
|
||||||
|
state: &State<'_, SerialConnectionState>,
|
||||||
|
) -> Result<SharedTactileRecording, SerialError> {
|
||||||
|
let current_record = {
|
||||||
|
let session = state.session.lock().map_err(|_| SerialError::StateError)?;
|
||||||
|
session
|
||||||
|
.as_ref()
|
||||||
|
.map(|current_session| current_session.current_record.clone())
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(recording) = current_record {
|
||||||
|
return Ok(recording);
|
||||||
|
}
|
||||||
|
|
||||||
|
let last_record = state.last_record.lock().map_err(|_| SerialError::StateError)?;
|
||||||
|
last_record.clone().ok_or(SerialError::NoRecordedData)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn snapshot_record_frame_count(
|
||||||
|
state: &State<'_, SerialConnectionState>,
|
||||||
|
) -> Result<usize, SerialError> {
|
||||||
|
let current_record = {
|
||||||
|
let session = state.session.lock().map_err(|_| SerialError::StateError)?;
|
||||||
|
session
|
||||||
|
.as_ref()
|
||||||
|
.map(|current_session| current_session.current_record.clone())
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(record) = current_record {
|
||||||
|
return record
|
||||||
|
.lock()
|
||||||
|
.map(|recording| recording.frames.len())
|
||||||
|
.map_err(|_| SerialError::StateError);
|
||||||
|
}
|
||||||
|
|
||||||
|
let last_record = state.last_record.lock().map_err(|_| SerialError::StateError)?;
|
||||||
|
let Some(record) = last_record.as_ref() else {
|
||||||
|
return Ok(0);
|
||||||
|
};
|
||||||
|
|
||||||
|
record
|
||||||
|
.lock()
|
||||||
|
.map(|recording| recording.frames.len())
|
||||||
|
.map_err(|_| SerialError::StateError)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_record_to_csv(
|
||||||
|
record: SharedTactileRecording,
|
||||||
|
output_path: &Path,
|
||||||
|
) -> Result<usize, SerialError> {
|
||||||
|
if let Some(parent) = output_path.parent() {
|
||||||
|
if !parent.exists() {
|
||||||
|
return Err(SerialError::ExportError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut file = File::create(output_path).map_err(|_| SerialError::ExportError)?;
|
||||||
|
let frame_count = {
|
||||||
|
let recording = record.lock().map_err(|_| SerialError::StateError)?;
|
||||||
|
if recording.frames.is_empty() {
|
||||||
|
return Err(SerialError::NoRecordedData);
|
||||||
|
}
|
||||||
|
|
||||||
|
export_recording_csv(&recording, &mut file).map_err(|_| SerialError::ExportError)?;
|
||||||
|
recording.frames.len()
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(frame_count)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_export_path(raw_path: String) -> Result<PathBuf, SerialError> {
|
||||||
|
let trimmed = raw_path.trim();
|
||||||
|
if trimmed.is_empty() {
|
||||||
|
return Err(SerialError::ExportError);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut path = resolve_absolute_path(trimmed).map_err(|_| SerialError::ExportError)?;
|
||||||
|
if path.extension().is_none() {
|
||||||
|
path.set_extension("csv");
|
||||||
|
}
|
||||||
|
|
||||||
|
if path.file_name().is_none() {
|
||||||
|
return Err(SerialError::ExportError);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_import_path(raw_path: String) -> Result<PathBuf, SerialError> {
|
||||||
|
let trimmed = raw_path.trim();
|
||||||
|
if trimmed.is_empty() {
|
||||||
|
return Err(SerialError::ImportError);
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = resolve_absolute_path(trimmed).map_err(|_| SerialError::ImportError)?;
|
||||||
|
if !path.exists() || !path.is_file() {
|
||||||
|
return Err(SerialError::ImportError);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_absolute_path(raw_path: &str) -> std::io::Result<PathBuf> {
|
||||||
|
let path = PathBuf::from(raw_path);
|
||||||
|
if path.is_absolute() {
|
||||||
|
Ok(path)
|
||||||
|
} else {
|
||||||
|
Ok(std::env::current_dir()?.join(path))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
use tauri::{AppHandle, Manager, WebviewWindow};
|
use super::serial::SerialConnectionState;
|
||||||
|
use crate::commands::serial::shutdown_active_session;
|
||||||
|
use tauri::{AppHandle, Manager, State, WebviewWindow};
|
||||||
|
|
||||||
fn main_window(app: &AppHandle) -> Result<WebviewWindow, String> {
|
fn main_window(app: &AppHandle) -> Result<WebviewWindow, String> {
|
||||||
app.get_webview_window("main")
|
app.get_webview_window("main")
|
||||||
@@ -25,8 +27,14 @@ pub fn win_toggle_maximize(app: AppHandle) -> Result<(), String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn win_close(app: AppHandle) -> Result<(), String> {
|
pub async fn win_close(
|
||||||
main_window(&app)?
|
app: AppHandle,
|
||||||
.close()
|
state: State<'_, SerialConnectionState>,
|
||||||
.map_err(|error| error.to_string())
|
) -> Result<(), String> {
|
||||||
|
shutdown_active_session(&state)
|
||||||
|
.await
|
||||||
|
.map_err(|error| error.to_string())?;
|
||||||
|
|
||||||
|
app.exit(0);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,11 +9,15 @@ pub fn run() {
|
|||||||
.manage(SerialConnectionState::default())
|
.manage(SerialConnectionState::default())
|
||||||
.plugin(tauri_plugin_opener::init())
|
.plugin(tauri_plugin_opener::init())
|
||||||
.invoke_handler(tauri::generate_handler![
|
.invoke_handler(tauri::generate_handler![
|
||||||
|
commands::file_explorer::file_explorer_list,
|
||||||
commands::serial::serial_enum,
|
commands::serial::serial_enum,
|
||||||
commands::serial::serial_connect,
|
commands::serial::serial_connect,
|
||||||
commands::serial::serial_disconnect,
|
commands::serial::serial_disconnect,
|
||||||
commands::serial::serial_export_csv,
|
commands::serial::serial_export_csv,
|
||||||
|
commands::serial::serial_has_record_data,
|
||||||
|
commands::serial::serial_export_csv_to_path,
|
||||||
commands::serial::serial_import_csv,
|
commands::serial::serial_import_csv,
|
||||||
|
commands::serial::serial_import_csv_from_path,
|
||||||
commands::window::win_minimize,
|
commands::window::win_minimize,
|
||||||
commands::window::win_toggle_maximize,
|
commands::window::win_toggle_maximize,
|
||||||
commands::window::win_close
|
commands::window::win_close
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use fern::colors::{Color, ColoredLevelConfig};
|
use fern::{Dispatch, colors::{Color, ColoredLevelConfig}};
|
||||||
use log::{debug, error, info, trace, warn};
|
use log::{debug};
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
pub fn setup_logger() {
|
pub fn setup_logger() {
|
||||||
let colors_line = ColoredLevelConfig::new()
|
let colors_line = ColoredLevelConfig::new()
|
||||||
@@ -10,7 +10,13 @@ pub fn setup_logger() {
|
|||||||
.trace(Color::BrightBlack);
|
.trace(Color::BrightBlack);
|
||||||
|
|
||||||
let colors_level = colors_line.info(Color::Green);
|
let colors_level = colors_line.info(Color::Green);
|
||||||
fern::Dispatch::new()
|
let level = if cfg!(debug_assertions) {
|
||||||
|
log::LevelFilter::Debug
|
||||||
|
} else {
|
||||||
|
log::LevelFilter::Info
|
||||||
|
};
|
||||||
|
|
||||||
|
let console_config = fern::Dispatch::new()
|
||||||
.format(move |out, message, record| {
|
.format(move |out, message, record| {
|
||||||
out.finish(
|
out.finish(
|
||||||
format_args!(
|
format_args!(
|
||||||
@@ -26,9 +32,31 @@ pub fn setup_logger() {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.level(log::LevelFilter::Info)
|
.level(level)
|
||||||
.chain(std::io::stdout())
|
.chain(std::io::stdout());
|
||||||
.chain(fern::DateBased::new("program.log", "%Y-%m-%d"))
|
// .chain(fern::DateBased::new("program.log", "%Y-%m-%d"))
|
||||||
|
// .apply()
|
||||||
|
// .unwrap();
|
||||||
|
|
||||||
|
let file_config = fern::Dispatch::new()
|
||||||
|
.format(move |out, message, record| {
|
||||||
|
out.finish(
|
||||||
|
format_args!(
|
||||||
|
"[{data} {level} {target}] {message}",
|
||||||
|
data = humantime::format_rfc3339_seconds(SystemTime::now()),
|
||||||
|
target = record.target(),
|
||||||
|
level = colors_level.color(record.level()),
|
||||||
|
message = message,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.level(level)
|
||||||
|
.chain(fern::DateBased::new("program.log", "%Y-%m-%d"));
|
||||||
|
|
||||||
|
Dispatch::new()
|
||||||
|
.level(log::LevelFilter::Debug)
|
||||||
|
.chain(console_config)
|
||||||
|
.chain(file_config)
|
||||||
.apply()
|
.apply()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
|
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
|
||||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||||
use log::{debug, error, info, trace, warn};
|
use log::debug;
|
||||||
use tauri_demo_lib::log::setup_logger;
|
use tauri_demo_lib::log::setup_logger;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use crate::serial_core::{frame::TestFrame, record::Recording};
|
use crate::serial_core::{frame::TestFrame, record::Recording};
|
||||||
|
|
||||||
pub mod test;
|
pub mod test;
|
||||||
|
pub mod tactile_a;
|
||||||
pub type TestRecording = Recording<TestFrame>;
|
pub type TestRecording = Recording<TestFrame>;
|
||||||
379
src-tauri/src/serial_core/codecs/tactile_a.rs
Normal file
@@ -0,0 +1,379 @@
|
|||||||
|
use crate::serial_core::error::CodecError;
|
||||||
|
use crate::serial_core::frame::{
|
||||||
|
FrameHandler, TactileAFrameMetaData, TactileARepFrame, TactileAReqFrame,
|
||||||
|
};
|
||||||
|
use crate::serial_core::record::{write_csv, CsvExporter, CsvImporter, RecordedFrame, Recording};
|
||||||
|
use crate::serial_core::utils::{calc_crc8_itu, elapsed_millis};
|
||||||
|
use crate::serial_core::{
|
||||||
|
codec::Codec,
|
||||||
|
frame::{TactileAFrame, TactileAFrameStatusCode},
|
||||||
|
};
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use csv::StringRecord;
|
||||||
|
use anyhow::anyhow;
|
||||||
|
use std::io::Read;
|
||||||
|
use log::debug;
|
||||||
|
|
||||||
|
const FRAME_BUFFER_MIN_LENGTH: usize = 15;
|
||||||
|
|
||||||
|
pub struct TactileACodec {
|
||||||
|
buffer: Vec<u8>,
|
||||||
|
expected_data_len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TactileACsvExporter {
|
||||||
|
channels: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TactileACsvImporter {
|
||||||
|
channels: usize,
|
||||||
|
data_row: usize,
|
||||||
|
packets: Vec<TactileADataPacket>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TactileAHandler;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct TactileADataPacket {
|
||||||
|
pub data: Vec<i32>,
|
||||||
|
pub dts_ms: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u8> for TactileAFrameStatusCode {
|
||||||
|
fn from(value: u8) -> Self {
|
||||||
|
match value {
|
||||||
|
0 => TactileAFrameStatusCode::Success,
|
||||||
|
_ => TactileAFrameStatusCode::Failure,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&TactileARepFrame> for TactileADataPacket {
|
||||||
|
type Error = CodecError;
|
||||||
|
fn try_from(value: &TactileARepFrame) -> Result<TactileADataPacket, Self::Error> {
|
||||||
|
let data = TactileACodec::parse_data_frame(&value.payload)?;
|
||||||
|
let dts_ms = value.dts_ms;
|
||||||
|
Ok(TactileADataPacket {
|
||||||
|
data: data,
|
||||||
|
dts_ms: dts_ms,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TactileACodec {
|
||||||
|
pub fn new(cols: usize, rows: usize) -> TactileACodec {
|
||||||
|
Self {
|
||||||
|
buffer: Vec::new(),
|
||||||
|
expected_data_len: cols * rows * 2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_data_frame(data: &[u8]) -> Result<Vec<i32>, CodecError> {
|
||||||
|
if data.len() % 2 != 0 {
|
||||||
|
return Err(CodecError::InvalidLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
let vals: Vec<i32> = data
|
||||||
|
.chunks_exact(2)
|
||||||
|
.map(|chunk| {
|
||||||
|
let raw = u16::from_le_bytes([chunk[0], chunk[1]]) as i32;
|
||||||
|
if raw < 15 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
raw
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<i32>>();
|
||||||
|
|
||||||
|
Ok(vals)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_req_frame(cols: usize, rows: usize) -> anyhow::Result<TactileAFrame> {
|
||||||
|
let header = [0x55, 0xAA];
|
||||||
|
let payload_len: usize = 9;
|
||||||
|
let device_addr: u8 = 0x34;
|
||||||
|
let extend_code: u8 = 0x00;
|
||||||
|
let func_code: u8 = 0xFB;
|
||||||
|
let start_addr: u32 = 7168;
|
||||||
|
let except_data_len: usize = cols * rows * 2;
|
||||||
|
let checksum: u8 = 0;
|
||||||
|
Ok(TactileAFrame::Req(TactileAReqFrame {
|
||||||
|
meta: TactileAFrameMetaData {
|
||||||
|
header,
|
||||||
|
payload_len,
|
||||||
|
device_addr,
|
||||||
|
extend_code,
|
||||||
|
func_code,
|
||||||
|
start_addr,
|
||||||
|
except_data_len,
|
||||||
|
checksum,
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Codec<TactileAFrame> for TactileACodec {
|
||||||
|
fn decode(
|
||||||
|
&mut self,
|
||||||
|
input: &[u8],
|
||||||
|
session_started_at: std::time::Instant,
|
||||||
|
) -> Result<Vec<TactileAFrame>, CodecError> {
|
||||||
|
self.buffer.extend_from_slice(input);
|
||||||
|
let mut frames: Vec<TactileAFrame> = Vec::new();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if self.buffer.len() < FRAME_BUFFER_MIN_LENGTH {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let header_pos = self.buffer.windows(2).position(|w| w == [0xAA, 0x55]);
|
||||||
|
|
||||||
|
let Some(pos) = header_pos else {
|
||||||
|
self.buffer.clear();
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
if pos > 0 {
|
||||||
|
self.buffer.drain(0..pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.buffer.len() < FRAME_BUFFER_MIN_LENGTH {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let header = [self.buffer[0], self.buffer[1]];
|
||||||
|
let payload_len = u16::from_le_bytes([self.buffer[2], self.buffer[3]]) as usize;
|
||||||
|
let device_addr = self.buffer[4];
|
||||||
|
let extend_code = self.buffer[5];
|
||||||
|
let func_code = self.buffer[6];
|
||||||
|
let start_addr = u32::from_le_bytes([
|
||||||
|
self.buffer[7],
|
||||||
|
self.buffer[8],
|
||||||
|
self.buffer[9],
|
||||||
|
self.buffer[10],
|
||||||
|
]);
|
||||||
|
let except_data_len = u16::from_le_bytes([self.buffer[11], self.buffer[12]]) as usize;
|
||||||
|
let status = TactileAFrameStatusCode::from(self.buffer[13]);
|
||||||
|
if except_data_len != self.expected_data_len {
|
||||||
|
debug!(
|
||||||
|
"unexpected payload length: expected {}, got {}, buffer_len={}",
|
||||||
|
self.expected_data_len,
|
||||||
|
except_data_len,
|
||||||
|
self.buffer.len()
|
||||||
|
);
|
||||||
|
self.buffer.drain(0..1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let frame_length = except_data_len + FRAME_BUFFER_MIN_LENGTH;
|
||||||
|
if self.buffer.len() < frame_length {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let need_check_data = self.buffer[0..14 + except_data_len].to_vec();
|
||||||
|
let payload = self.buffer[14..14 + except_data_len].to_vec();
|
||||||
|
let crc8_itu_alg = crc::Crc::<u8>::new(&crc::CRC_8_I_432_1);
|
||||||
|
let checksum = crc8_itu_alg.checksum(&need_check_data.as_slice());
|
||||||
|
if self.buffer[frame_length - 1] != checksum {
|
||||||
|
debug!(
|
||||||
|
"checksum mismatch: expected {:02X}, got {:02X}, frame_len={}",
|
||||||
|
checksum,
|
||||||
|
self.buffer[frame_length - 1],
|
||||||
|
frame_length
|
||||||
|
);
|
||||||
|
self.buffer.drain(0..1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let dts_ms = elapsed_millis(session_started_at);
|
||||||
|
let meta: TactileAFrameMetaData = TactileAFrameMetaData {
|
||||||
|
header,
|
||||||
|
payload_len,
|
||||||
|
device_addr,
|
||||||
|
extend_code,
|
||||||
|
func_code,
|
||||||
|
start_addr,
|
||||||
|
except_data_len,
|
||||||
|
checksum,
|
||||||
|
};
|
||||||
|
frames.push(TactileAFrame::Rep({
|
||||||
|
TactileARepFrame {
|
||||||
|
meta,
|
||||||
|
status,
|
||||||
|
payload,
|
||||||
|
dts_ms,
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
self.buffer.drain(0..frame_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(frames)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encode(
|
||||||
|
&self,
|
||||||
|
frame: &TactileAFrame,
|
||||||
|
) -> Result<Vec<u8>, crate::serial_core::error::CodecError> {
|
||||||
|
match frame {
|
||||||
|
TactileAFrame::Req(f) => {
|
||||||
|
let mut req_bytes: Vec<u8> = Vec::new();
|
||||||
|
req_bytes.extend_from_slice(f.meta.header.as_slice());
|
||||||
|
req_bytes.extend_from_slice((f.meta.payload_len as u16).to_le_bytes().as_slice());
|
||||||
|
req_bytes.push(f.meta.device_addr);
|
||||||
|
req_bytes.push(f.meta.extend_code);
|
||||||
|
req_bytes.push(f.meta.func_code);
|
||||||
|
|
||||||
|
req_bytes.extend_from_slice(f.meta.start_addr.to_le_bytes().as_slice());
|
||||||
|
req_bytes.extend_from_slice((f.meta.except_data_len as u16).to_le_bytes().as_slice());
|
||||||
|
let checksum = calc_crc8_itu(req_bytes.as_slice());
|
||||||
|
req_bytes.push(checksum);
|
||||||
|
Ok(req_bytes)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
Err(CodecError::InvalidFrameType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl FrameHandler<TactileAFrame, i32> for TactileAHandler {
|
||||||
|
async fn on_frame(&mut self, frame: &TactileAFrame) -> anyhow::Result<Option<Vec<i32>>> {
|
||||||
|
match frame {
|
||||||
|
TactileAFrame::Rep(rep) => {
|
||||||
|
let vals = TactileACodec::parse_data_frame(&rep.payload)?;
|
||||||
|
Ok(Some(vals))
|
||||||
|
}
|
||||||
|
_ => Ok(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TactileACsvExporter {
|
||||||
|
fn new(channels: usize) -> Self {
|
||||||
|
TactileACsvExporter { channels }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CsvExporter<TactileARepFrame> for TactileACsvExporter {
|
||||||
|
type Error = CodecError;
|
||||||
|
fn csv_header(&self, _recording: &Recording<TactileARepFrame>) -> Vec<String> {
|
||||||
|
let mut header: Vec<String> = Vec::new();
|
||||||
|
for i in 0..self.channels {
|
||||||
|
header.push(format!("channel{}", i + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
header.push("dts".to_string());
|
||||||
|
header
|
||||||
|
}
|
||||||
|
|
||||||
|
fn csv_row(
|
||||||
|
&self,
|
||||||
|
item: &RecordedFrame<TactileARepFrame>,
|
||||||
|
) -> anyhow::Result<Vec<String>> {
|
||||||
|
let packet = TactileADataPacket::try_from(&item.frame)?;
|
||||||
|
let mut row: Vec<String> = packet.data.iter().map(|x| x.to_string()).collect();
|
||||||
|
row.push(packet.dts_ms.to_string());
|
||||||
|
Ok(row)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CsvExporter<TactileAFrame> for TactileACsvExporter {
|
||||||
|
type Error = CodecError;
|
||||||
|
|
||||||
|
fn csv_header(&self, _recording: &Recording<TactileAFrame>) -> Vec<String> {
|
||||||
|
let mut header: Vec<String> = Vec::new();
|
||||||
|
for i in 0..self.channels {
|
||||||
|
header.push(format!("channel{}", i + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
header.push("dts".to_string());
|
||||||
|
header
|
||||||
|
}
|
||||||
|
|
||||||
|
fn csv_row(
|
||||||
|
&self,
|
||||||
|
item: &RecordedFrame<TactileAFrame>,
|
||||||
|
) -> anyhow::Result<Vec<String>> {
|
||||||
|
let rep = match &item.frame {
|
||||||
|
TactileAFrame::Rep(rep) => rep,
|
||||||
|
TactileAFrame::Req(_) => return Err(anyhow!("request frame cannot be exported to csv row")),
|
||||||
|
};
|
||||||
|
|
||||||
|
let packet = TactileADataPacket::try_from(rep)?;
|
||||||
|
let mut row: Vec<String> = packet.data.iter().map(|x| x.to_string()).collect();
|
||||||
|
row.push(packet.dts_ms.to_string());
|
||||||
|
Ok(row)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TactileACsvImporter {
|
||||||
|
pub fn new(_path: &str) -> TactileACsvImporter {
|
||||||
|
Self {
|
||||||
|
channels: 0,
|
||||||
|
data_row: 0,
|
||||||
|
packets: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_record(&mut self, record: StringRecord) -> anyhow::Result<TactileADataPacket> {
|
||||||
|
if self.channels == 0 {
|
||||||
|
return Err(anyhow!("csv header is missing channel columns"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if record.len() < self.channels + 1 {
|
||||||
|
return Err(anyhow!("csv row has insufficient columns"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut data = Vec::with_capacity(self.channels);
|
||||||
|
for index in 0..self.channels {
|
||||||
|
let cell = record.get(index).ok_or_else(|| anyhow!("missing channel cell"))?;
|
||||||
|
data.push(cell.parse::<i32>()?);
|
||||||
|
}
|
||||||
|
|
||||||
|
let dts_cell = record
|
||||||
|
.get(self.channels)
|
||||||
|
.ok_or_else(|| anyhow!("missing dts cell"))?;
|
||||||
|
let dts_ms = dts_cell.parse::<u64>()?;
|
||||||
|
|
||||||
|
Ok(TactileADataPacket {
|
||||||
|
data: data,
|
||||||
|
dts_ms: dts_ms,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CsvImporter<TactileADataPacket> for TactileACsvImporter {
|
||||||
|
fn load<R: Read>(&mut self, reader: R) -> anyhow::Result<Vec<TactileADataPacket>> {
|
||||||
|
let mut rdr = csv::Reader::from_reader(reader);
|
||||||
|
let headers = rdr.headers()?.clone();
|
||||||
|
self.channels = headers.len().saturating_sub(1);
|
||||||
|
self.data_row = 0;
|
||||||
|
self.packets.clear();
|
||||||
|
|
||||||
|
for record in rdr.records() {
|
||||||
|
let record = record?;
|
||||||
|
let packet = self.parse_record(record)?;
|
||||||
|
self.packets.push(packet);
|
||||||
|
self.data_row += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(self.packets.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn export_recording_csv<W>(recording: &Recording<TactileAFrame>, writer: W) -> anyhow::Result<()>
|
||||||
|
where
|
||||||
|
W: std::io::Write,
|
||||||
|
{
|
||||||
|
let channel_nb = recording
|
||||||
|
.frames
|
||||||
|
.iter()
|
||||||
|
.find_map(|frame| match &frame.frame {
|
||||||
|
TactileAFrame::Rep(rep) => Some(rep.payload.len() / 2),
|
||||||
|
TactileAFrame::Req(_) => None,
|
||||||
|
})
|
||||||
|
.unwrap_or(0);
|
||||||
|
|
||||||
|
let exporter = TactileACsvExporter::new(channel_nb);
|
||||||
|
write_csv(recording, &exporter, writer)
|
||||||
|
}
|
||||||
@@ -1,13 +1,15 @@
|
|||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use crate::serial_core::frame::{crc8, usize_to_u16_be_bytes, FrameHandler};
|
use crate::serial_core::frame::{FrameHandler};
|
||||||
use crate::serial_core::{codec::Codec, error::CodecError, frame::TestFrame};
|
use crate::serial_core::{codec::Codec, error::CodecError, frame::TestFrame};
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use chrono::Local;
|
|
||||||
use csv::StringRecord;
|
use csv::StringRecord;
|
||||||
use crate::serial_core::record::{write_csv, CsvExporter, CsvImporter, RecordedFrame, Recording};
|
use crate::serial_core::record::{write_csv, CsvExporter, CsvImporter, RecordedFrame, Recording};
|
||||||
|
use crate::serial_core::utils::{
|
||||||
|
elapsed_millis,
|
||||||
|
usize_to_u16_be_bytes
|
||||||
|
};
|
||||||
pub struct TestCodec {
|
pub struct TestCodec {
|
||||||
buffer: Vec<u8>,
|
buffer: Vec<u8>,
|
||||||
}
|
}
|
||||||
@@ -52,7 +54,9 @@ impl Codec<TestFrame> for TestCodec {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
let payload = self.buffer[5..5 + length].to_vec();
|
let payload = self.buffer[5..5 + length].to_vec();
|
||||||
let checksum = crc8(payload.as_slice());
|
// let checksum = crc8(payload.as_slice());
|
||||||
|
let crc8_alg = crc::Crc::<u8>::new(&crc::CRC_8_SMBUS);
|
||||||
|
let checksum = crc8_alg.checksum(payload.as_slice());
|
||||||
if self.buffer[frame_length - 1] != checksum {
|
if self.buffer[frame_length - 1] != checksum {
|
||||||
self.buffer.drain(0..1);
|
self.buffer.drain(0..1);
|
||||||
continue;
|
continue;
|
||||||
@@ -112,10 +116,6 @@ fn parse_data_frame(data: &[u8]) -> Result<Vec<i32>, CodecError> {
|
|||||||
Ok(vals)
|
Ok(vals)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn elapsed_millis(start_at: Instant) -> u64 {
|
|
||||||
start_at.elapsed().as_millis() as u64
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct TestCsvExporter;
|
pub struct TestCsvExporter;
|
||||||
pub struct TestCsvImporter {
|
pub struct TestCsvImporter {
|
||||||
channels: usize,
|
channels: usize,
|
||||||
@@ -231,9 +231,7 @@ pub fn export_recording_csv<W>(recording: &Recording<TestFrame>, writer: W) -> a
|
|||||||
where
|
where
|
||||||
W: std::io::Write,
|
W: std::io::Write,
|
||||||
{
|
{
|
||||||
let now = Local::now();
|
write_csv(recording, &TestCsvExporter, writer)
|
||||||
let filename = format!("joyson_{}", now.format("%Y%m%d_%H%M%S"));
|
|
||||||
write_csv(recording, &TestCsvExporter, &filename)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ pub enum CodecError {
|
|||||||
InvalidHeader,
|
InvalidHeader,
|
||||||
InvalidTail,
|
InvalidTail,
|
||||||
InvalidLength,
|
InvalidLength,
|
||||||
|
InvalidFrameType,
|
||||||
PayloadTooLarge,
|
PayloadTooLarge,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,6 +45,7 @@ impl fmt::Display for CodecError {
|
|||||||
CodecError::InvalidHeader => write!(f, "Invalid Header"),
|
CodecError::InvalidHeader => write!(f, "Invalid Header"),
|
||||||
CodecError::InvalidTail => write!(f, "Invalid Tail"),
|
CodecError::InvalidTail => write!(f, "Invalid Tail"),
|
||||||
CodecError::InvalidLength => write!(f, "Invalid Length"),
|
CodecError::InvalidLength => write!(f, "Invalid Length"),
|
||||||
|
CodecError::InvalidFrameType => write!(f, "Invalid Frame Type"),
|
||||||
CodecError::PayloadTooLarge => write!(f, "Payload too large"),
|
CodecError::PayloadTooLarge => write!(f, "Payload too large"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,34 +10,48 @@ pub struct TestFrame {
|
|||||||
pub dts_ms: u64
|
pub dts_ms: u64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct TactileAFrameMetaData {
|
||||||
|
pub header: [u8; 2],
|
||||||
|
pub payload_len: usize,
|
||||||
|
pub device_addr: u8,
|
||||||
|
pub extend_code: u8,
|
||||||
|
pub func_code: u8,
|
||||||
|
pub start_addr: u32,
|
||||||
|
pub except_data_len: usize,
|
||||||
|
// pub status: u8,
|
||||||
|
// pub payload_data: Vec<u8>,
|
||||||
|
pub checksum: u8,
|
||||||
|
// pub dts_ms: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct TactileAReqFrame {
|
||||||
|
pub meta: TactileAFrameMetaData,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct TactileARepFrame {
|
||||||
|
pub meta: TactileAFrameMetaData,
|
||||||
|
pub status: TactileAFrameStatusCode,
|
||||||
|
pub payload: Vec<u8>,
|
||||||
|
pub dts_ms: u64
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum TactileAFrameStatusCode {
|
||||||
|
Success,
|
||||||
|
Failure
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum TactileAFrame {
|
||||||
|
Req(TactileAReqFrame),
|
||||||
|
Rep(TactileARepFrame)
|
||||||
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait FrameHandler<F, T>: Send {
|
pub trait FrameHandler<F, T>: Send {
|
||||||
async fn on_frame(&mut self, frame: &F) -> Result<Option<Vec<T>>>;
|
async fn on_frame(&mut self, frame: &F) -> Result<Option<Vec<T>>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn usize_to_u16_be_bytes(n: usize) -> [u8; 2] {
|
|
||||||
(n as u16).to_be_bytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn usize_to_u16_le_bytes(n: usize) -> [u8; 2] {
|
|
||||||
(n as u16).to_be_bytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn crc8(data: &[u8]) -> u8 {
|
|
||||||
let mut crc: u8 = 0x00;
|
|
||||||
|
|
||||||
for &byte in data {
|
|
||||||
crc ^= byte;
|
|
||||||
for _ in 0..8 {
|
|
||||||
if (crc & 0x80) != 0 {
|
|
||||||
crc = (crc << 1) ^ 0x07;
|
|
||||||
} else {
|
|
||||||
crc <<= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
crc
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
use crate::serial_core::{frame::TestFrame, record::Recording};
|
use crate::serial_core::{
|
||||||
|
frame::{TactileAFrame, TestFrame},
|
||||||
|
record::Recording,
|
||||||
|
};
|
||||||
|
|
||||||
pub mod codec;
|
pub mod codec;
|
||||||
pub mod codecs;
|
pub mod codecs;
|
||||||
@@ -7,8 +10,10 @@ pub mod frame;
|
|||||||
pub mod model;
|
pub mod model;
|
||||||
pub mod serial;
|
pub mod serial;
|
||||||
pub mod record;
|
pub mod record;
|
||||||
|
pub mod utils;
|
||||||
|
|
||||||
pub type TestRecording = Recording<TestFrame>;
|
pub type TestRecording = Recording<TestFrame>;
|
||||||
|
pub type TactileARecording = Recording<TactileAFrame>;
|
||||||
|
|
||||||
pub struct SerialConnection {
|
pub struct SerialConnection {
|
||||||
pub port: String,
|
pub port: String,
|
||||||
|
|||||||
@@ -1,8 +1,3 @@
|
|||||||
use std::fs::{write, File};
|
|
||||||
use std::io;
|
|
||||||
use anyhow::{Result, anyhow};
|
|
||||||
use csv::Reader;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct FrameTiming {
|
pub struct FrameTiming {
|
||||||
pub pts_ms: Option<u64>,
|
pub pts_ms: Option<u64>,
|
||||||
@@ -38,20 +33,17 @@ pub trait CsvImporter<P> {
|
|||||||
fn load<R: std::io::Read>(&mut self, reader: R) -> anyhow::Result<Vec<P>>;
|
fn load<R: std::io::Read>(&mut self, reader: R) -> anyhow::Result<Vec<P>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_csv<F, E>(
|
pub fn write_csv<F, E, W>(
|
||||||
recording: &Recording<F>,
|
recording: &Recording<F>,
|
||||||
exporter: &E,
|
exporter: &E,
|
||||||
path: &str
|
writer: W,
|
||||||
// mut writer: W,
|
|
||||||
) -> anyhow::Result<()>
|
) -> anyhow::Result<()>
|
||||||
where
|
where
|
||||||
E: CsvExporter<F>,
|
E: CsvExporter<F>,
|
||||||
// W: std::io::Write
|
W: std::io::Write,
|
||||||
{
|
{
|
||||||
let header = exporter.csv_header(&recording);
|
let header = exporter.csv_header(&recording);
|
||||||
// let mut wrt = csv::Writer::from_writer(io::stdout());
|
let mut wrt = csv::Writer::from_writer(writer);
|
||||||
|
|
||||||
let mut wrt = csv::Writer::from_path(format!("{}.csv", path))?;
|
|
||||||
wrt.write_record(header)?;
|
wrt.write_record(header)?;
|
||||||
for f in &recording.frames {
|
for f in &recording.frames {
|
||||||
let row = exporter.csv_row(f)?;
|
let row = exporter.csv_row(f)?;
|
||||||
|
|||||||
@@ -1,40 +1,236 @@
|
|||||||
use crate::serial_core::codec::Codec;
|
use crate::serial_core::codec::Codec;
|
||||||
use crate::serial_core::frame::{FrameHandler, TestFrame};
|
use crate::serial_core::codecs::tactile_a::TactileACodec;
|
||||||
use crate::serial_core::model::HudChartState;
|
use crate::serial_core::frame::{FrameHandler, TactileAFrame, TestFrame};
|
||||||
|
use crate::serial_core::model::{HudChartState, HudPacket};
|
||||||
|
use crate::serial_core::record::Recording;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use tauri::{AppHandle, Emitter};
|
use tauri::{AppHandle, Emitter};
|
||||||
use tokio::io::AsyncReadExt;
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
use tokio::time::{self, Duration, MissedTickBehavior};
|
use tokio::time::{self, Duration, MissedTickBehavior};
|
||||||
use tokio_serial::SerialStream;
|
use tokio_serial::SerialStream;
|
||||||
use tokio_util::sync::CancellationToken;
|
use tokio_util::sync::CancellationToken;
|
||||||
|
use std::future::pending;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use log::info;
|
|
||||||
use crate::serial_core::record::{FrameTiming, RecordedFrame};
|
use crate::serial_core::record::{FrameTiming, RecordedFrame};
|
||||||
use crate::serial_core::TestRecording;
|
|
||||||
|
|
||||||
pub async fn run_serial<C, H, T>(
|
pub enum PollMode<F> {
|
||||||
|
Disable,
|
||||||
|
Enabled(Box<dyn PollRequester<F>>)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait SerialFrame: Clone + Send + 'static {
|
||||||
|
fn dts_ms(&self) -> u64;
|
||||||
|
|
||||||
|
fn to_hud_packet(
|
||||||
|
&self,
|
||||||
|
chart_state: &mut HudChartState,
|
||||||
|
display_values: Option<&[i32]>,
|
||||||
|
) -> Option<HudPacket>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SerialFrame for TestFrame {
|
||||||
|
fn dts_ms(&self) -> u64 {
|
||||||
|
self.dts_ms
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_hud_packet(
|
||||||
|
&self,
|
||||||
|
chart_state: &mut HudChartState,
|
||||||
|
display_values: Option<&[i32]>,
|
||||||
|
) -> Option<HudPacket> {
|
||||||
|
Some(chart_state.apply_frame(self, display_values))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SerialFrame for TactileAFrame {
|
||||||
|
fn dts_ms(&self) -> u64 {
|
||||||
|
match self {
|
||||||
|
TactileAFrame::Req(_) => 0,
|
||||||
|
TactileAFrame::Rep(rep) => rep.dts_ms,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_hud_packet(
|
||||||
|
&self,
|
||||||
|
chart_state: &mut HudChartState,
|
||||||
|
display_values: Option<&[i32]>,
|
||||||
|
) -> Option<HudPacket> {
|
||||||
|
match self {
|
||||||
|
TactileAFrame::Req(_) => None,
|
||||||
|
TactileAFrame::Rep(rep) => {
|
||||||
|
let proxy = TestFrame {
|
||||||
|
header: rep.meta.header,
|
||||||
|
cmd: rep.meta.func_code,
|
||||||
|
length: rep.meta.except_data_len,
|
||||||
|
payload: rep.payload.clone(),
|
||||||
|
checksum: rep.meta.checksum,
|
||||||
|
dts_ms: rep.dts_ms,
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(chart_state.apply_frame(&proxy, display_values))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait PollRequester<F>: Send {
|
||||||
|
fn poll_interval(&self) -> Option<Duration> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn should_request(&mut self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_request(&mut self) -> Result<Option<F>> {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_rx_frame(&mut self, _frame: &F) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct NoopPollRequester;
|
||||||
|
|
||||||
|
impl<F> PollRequester<F> for NoopPollRequester {}
|
||||||
|
|
||||||
|
pub struct TactileAPollRequester {
|
||||||
|
period: Duration,
|
||||||
|
cols: usize,
|
||||||
|
rows: usize,
|
||||||
|
awaiting_reply: bool,
|
||||||
|
last_request_at: Option<Instant>,
|
||||||
|
reply_timeout: Duration,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TactileAPollRequester {
|
||||||
|
pub fn new(period: Duration, cols: usize, rows: usize, reply_timeout: Duration) -> Self {
|
||||||
|
Self {
|
||||||
|
period,
|
||||||
|
cols,
|
||||||
|
rows,
|
||||||
|
awaiting_reply: false,
|
||||||
|
last_request_at: None,
|
||||||
|
reply_timeout,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PollRequester<TactileAFrame> for TactileAPollRequester {
|
||||||
|
fn poll_interval(&self) -> Option<Duration> {
|
||||||
|
Some(self.period)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn should_request(&mut self) -> bool {
|
||||||
|
if !self.awaiting_reply {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
let timed_out = self
|
||||||
|
.last_request_at
|
||||||
|
.map(|t| t.elapsed() >= self.reply_timeout)
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
|
if timed_out {
|
||||||
|
self.awaiting_reply = false;
|
||||||
|
self.last_request_at = None;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_request(&mut self) -> Result<Option<TactileAFrame>> {
|
||||||
|
let req = TactileACodec::build_req_frame(self.cols, self.rows)?;
|
||||||
|
self.awaiting_reply = true;
|
||||||
|
self.last_request_at = Some(Instant::now());
|
||||||
|
Ok(Some(req))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_rx_frame(&mut self, frame: &TactileAFrame) {
|
||||||
|
if matches!(frame, TactileAFrame::Rep(_)) {
|
||||||
|
self.awaiting_reply = false;
|
||||||
|
self.last_request_at = None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn run_serial<C, H, T, F>(
|
||||||
|
app: AppHandle,
|
||||||
|
port: SerialStream,
|
||||||
|
codec: C,
|
||||||
|
handler: H,
|
||||||
|
session_started_at: Instant,
|
||||||
|
recording: Arc<Mutex<Recording<F>>>,
|
||||||
|
cancel: CancellationToken,
|
||||||
|
) -> Result<()>
|
||||||
|
where
|
||||||
|
F: SerialFrame,
|
||||||
|
C: Codec<F> + Send + 'static,
|
||||||
|
H: FrameHandler<F, T> + Send + 'static,
|
||||||
|
T: Into<i32>
|
||||||
|
{
|
||||||
|
run_serial_with_poll(
|
||||||
|
app, port, codec, handler, session_started_at, recording, cancel, PollMode::Disable
|
||||||
|
).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn run_serial_with_poll<C, H, T, F>(
|
||||||
app: AppHandle,
|
app: AppHandle,
|
||||||
mut port: SerialStream,
|
mut port: SerialStream,
|
||||||
mut codec: C,
|
mut codec: C,
|
||||||
mut handler: H,
|
mut handler: H,
|
||||||
session_started_at: Instant,
|
session_started_at: Instant,
|
||||||
recording: Arc<Mutex<TestRecording>>,
|
recording: Arc<Mutex<Recording<F>>>,
|
||||||
cancel: CancellationToken,
|
cancel: CancellationToken,
|
||||||
|
poll_mode: PollMode<F>
|
||||||
) -> Result<()>
|
) -> Result<()>
|
||||||
where
|
where
|
||||||
C: Codec<TestFrame> + Send + 'static,
|
F: SerialFrame,
|
||||||
H: FrameHandler<TestFrame, T> + Send + 'static,
|
C: Codec<F> + Send + 'static,
|
||||||
|
H: FrameHandler<F, T> + Send + 'static,
|
||||||
T: Into<i32>,
|
T: Into<i32>,
|
||||||
{
|
{
|
||||||
|
let mut requester = match poll_mode {
|
||||||
|
PollMode::Disable => None,
|
||||||
|
PollMode::Enabled(r) => Some(r),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut poll_interval = requester
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|r| r.poll_interval())
|
||||||
|
.map(|d| {
|
||||||
|
let mut it = time::interval(d);
|
||||||
|
it.set_missed_tick_behavior(MissedTickBehavior::Skip);
|
||||||
|
it
|
||||||
|
});
|
||||||
|
|
||||||
let mut chart_state = HudChartState::new();
|
let mut chart_state = HudChartState::new();
|
||||||
let mut buffer = [0u8; 1024];
|
let mut buffer = [0u8; 1024];
|
||||||
let mut prune_interval = time::interval(Duration::from_millis(450));
|
let mut prune_interval = time::interval(Duration::from_millis(450));
|
||||||
prune_interval.set_missed_tick_behavior(MissedTickBehavior::Delay);
|
prune_interval.set_missed_tick_behavior(MissedTickBehavior::Delay);
|
||||||
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
_ = cancel.cancelled() => break,
|
_ = cancel.cancelled() => break,
|
||||||
|
_ = async {
|
||||||
|
match poll_interval.as_mut() {
|
||||||
|
Some(it) => {
|
||||||
|
it.tick().await;
|
||||||
|
}
|
||||||
|
None => pending::<()>().await,
|
||||||
|
}
|
||||||
|
} => {
|
||||||
|
if let Some(r) = requester.as_mut() {
|
||||||
|
if r.should_request() {
|
||||||
|
if let Some(req) = r.next_request()? {
|
||||||
|
let bytes = codec.encode(&req)?;
|
||||||
|
port.write_all(&bytes).await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
_ = prune_interval.tick() => {
|
_ = prune_interval.tick() => {
|
||||||
if let Some(packet) = chart_state.prune_stale() {
|
if let Some(packet) = chart_state.prune_stale() {
|
||||||
app.emit("hud_stream", packet)?;
|
app.emit("hud_stream", packet)?;
|
||||||
@@ -43,11 +239,18 @@ where
|
|||||||
read_result = port.read(&mut buffer) => {
|
read_result = port.read(&mut buffer) => {
|
||||||
let n = read_result?;
|
let n = read_result?;
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
|
// Some serial drivers can resolve reads with 0 bytes repeatedly.
|
||||||
|
// Yield here so timer-driven poll requests are not starved by a busy loop.
|
||||||
|
tokio::task::yield_now().await;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let frames = codec.decode(&buffer[..n], session_started_at)?;
|
let frames = codec.decode(&buffer[..n], session_started_at)?;
|
||||||
for frame in frames {
|
for frame in frames {
|
||||||
|
if let Some(r) = requester.as_mut() {
|
||||||
|
r.on_rx_frame(&frame);
|
||||||
|
}
|
||||||
|
|
||||||
let decode_res = handler
|
let decode_res = handler
|
||||||
.on_frame(&frame)
|
.on_frame(&frame)
|
||||||
.await?
|
.await?
|
||||||
@@ -55,26 +258,59 @@ where
|
|||||||
|
|
||||||
let mut record = recording.lock().map_err(|_| anyhow::anyhow!("recording state poisoned"))?;
|
let mut record = recording.lock().map_err(|_| anyhow::anyhow!("recording state poisoned"))?;
|
||||||
record.push(RecordedFrame{
|
record.push(RecordedFrame{
|
||||||
timing: FrameTiming { pts_ms: None, dts_ms: frame.dts_ms },
|
timing: FrameTiming { pts_ms: None, dts_ms: frame.dts_ms() },
|
||||||
frame: frame.clone(),
|
frame: frame.clone(),
|
||||||
});
|
});
|
||||||
|
|
||||||
let display_values = if let Some(vals) = decode_res.as_ref() {
|
let display_values = if let Some(vals) = decode_res.as_ref() {
|
||||||
let summary = vals.iter().copied().sum::<i32>();
|
let summary = vals.iter().copied().sum::<i32>();
|
||||||
info!("dot value summary: {}", summary);
|
let force = raw_to_g1(summary as u32);
|
||||||
chart_state.record_summary(summary as f32);
|
chart_state.record_summary(force as f32);
|
||||||
chart_state.record_pressure_matrix(vals.as_slice());
|
chart_state.record_pressure_matrix(vals.as_slice());
|
||||||
Some(vec![summary])
|
Some(vec![summary])
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let packet = chart_state.apply_frame(&frame, display_values.as_deref());
|
if let Some(packet) = frame.to_hud_packet(&mut chart_state, display_values.as_deref()) {
|
||||||
app.emit("hud_stream", packet)?;
|
app.emit("hud_stream", packet)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn raw_to_g1(raw: u32) -> f64 {
|
||||||
|
const X: [u32; 11] = [
|
||||||
|
0, 74602, 105503, 131459, 153512, 172041, 193794, 218947, 240580, 295118, 332346,
|
||||||
|
];
|
||||||
|
|
||||||
|
const Y: [f64; 11] = [
|
||||||
|
0.0, 160.0, 260.0, 360.0, 460.0, 560.0, 660.0, 860.0, 1060.0, 1560.0, 2060.0,
|
||||||
|
];
|
||||||
|
|
||||||
|
let n = X.len();
|
||||||
|
if raw <= X[0] {
|
||||||
|
return Y[0] / 100.0;
|
||||||
|
}
|
||||||
|
if raw >= X[n - 1] {
|
||||||
|
return Y[n - 1] / 100.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut left = 0;
|
||||||
|
let mut right = n - 1;
|
||||||
|
|
||||||
|
while left + 1 < right {
|
||||||
|
let mid = (left + right) / 2;
|
||||||
|
if raw < X[mid] {
|
||||||
|
right = mid;
|
||||||
|
} else {
|
||||||
|
left = mid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let ratio = (raw - X[left]) as f64 / (X[right] - X[left]) as f64;
|
||||||
|
Y[left] / 100.0 + ratio * (Y[right] - Y[left]) / 100.0
|
||||||
|
}
|
||||||
|
|||||||
59
src-tauri/src/serial_core/utils.rs
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
pub fn usize_to_u16_be_bytes(n: usize) -> [u8; 2] {
|
||||||
|
(n as u16).to_be_bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn usize_to_u16_le_bytes(n: usize) -> [u8; 2] {
|
||||||
|
(n as u16).to_be_bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn u16_to_hex_be_bytes(n: u16) -> [u8; 2] {
|
||||||
|
(n as u16).to_be_bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn u16_to_hex_le_bytes(n: u16) -> [u8; 2] {
|
||||||
|
(n as u16).to_le_bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn calc_crc8_smbus(c: &[u8]) -> u8 {
|
||||||
|
let crc8_smbus = crc::Crc::<u8>::new(&crc::CRC_8_SMBUS);
|
||||||
|
let checksum = crc8_smbus.checksum(c);
|
||||||
|
return checksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn calc_crc8_itu(c: &[u8]) -> u8 {
|
||||||
|
let crc8_itu_alg = crc::Crc::<u8>::new(&crc::CRC_8_I_432_1);
|
||||||
|
let checksum = crc8_itu_alg.checksum(c);
|
||||||
|
return checksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn elapsed_millis(start_at: Instant) -> u64 {
|
||||||
|
start_at.elapsed().as_millis() as u64
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use anyhow::Ok;
|
||||||
|
|
||||||
|
use crate::serial_core::utils::{calc_crc8_itu, calc_crc8_smbus};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_crc8_itu() -> anyhow::Result<()> {
|
||||||
|
let req_vec = vec![0x55, 0xAA, 0x09, 0x00, 0x34, 0x00, 0xFB, 0x00, 0x1C, 0x00, 0x00, 0x18, 0x00];
|
||||||
|
let checksum = calc_crc8_itu(req_vec.as_slice());
|
||||||
|
assert_eq!(checksum, 0x7A);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_crc8_smbus() -> anyhow::Result<()> {
|
||||||
|
let req_vec = vec![0x55, 0xAA, 0x09, 0x00, 0x34, 0x00, 0xFB, 0x00, 0x1C, 0x00, 0x00, 0x18, 0x00];
|
||||||
|
let checksum = calc_crc8_smbus(req_vec.as_slice());
|
||||||
|
assert_eq!(checksum, 0x2F);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
3
src-tauri/target-codex-checkfqvNiz/CACHEDIR.TAG
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
Signature: 8a477f597d28d172789f06886806bc55
|
||||||
|
# This file is a cache directory tag created by cargo.
|
||||||
|
# For information about cache directory tags see https://bford.info/cachedir/
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://schema.tauri.app/config/2",
|
"$schema": "https://schema.tauri.app/config/2",
|
||||||
"productName": "tauri-demo",
|
"productName": "JE-Skin",
|
||||||
"version": "0.1.0",
|
"version": "0.3.0",
|
||||||
"identifier": "com.lenn.tauri-serial",
|
"identifier": "com.lenn.tauri-serial",
|
||||||
"build": {
|
"build": {
|
||||||
"beforeDevCommand": "npm run dev",
|
"beforeDevCommand": "npm run dev",
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
"app": {
|
"app": {
|
||||||
"windows": [
|
"windows": [
|
||||||
{
|
{
|
||||||
"title": "joyson-serial",
|
"title": "JE-Skin",
|
||||||
"width": 1366,
|
"width": 1366,
|
||||||
"height": 860,
|
"height": 860,
|
||||||
"decorations": false
|
"decorations": false
|
||||||
@@ -29,8 +29,8 @@
|
|||||||
"icons/32x32.png",
|
"icons/32x32.png",
|
||||||
"icons/128x128.png",
|
"icons/128x128.png",
|
||||||
"icons/128x128@2x.png",
|
"icons/128x128@2x.png",
|
||||||
"icons/icon.ico",
|
"icons/icon.icns",
|
||||||
"icons/icon.png"
|
"icons/icon.ico"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { fly } from "svelte/transition";
|
import { fly } from "svelte/transition";
|
||||||
import ConfigPanel from "$lib/components/ConfigPanel.svelte";
|
import ConfigPanel from "$lib/components/ConfigPanel.svelte";
|
||||||
|
import NeonBreakoutArena from "$lib/components/NeonBreakoutArena.svelte";
|
||||||
import PressureMatrixViewer from "$lib/components/PressureMatrixViewer.svelte";
|
import PressureMatrixViewer from "$lib/components/PressureMatrixViewer.svelte";
|
||||||
import SignalChart from "$lib/components/SignalChart.svelte";
|
import SignalChart from "$lib/components/SignalChart.svelte";
|
||||||
import SummaryCurve from "$lib/components/SummaryCurve.svelte";
|
import SummaryCurve from "$lib/components/SummaryCurve.svelte";
|
||||||
@@ -12,14 +13,12 @@
|
|||||||
HudColorMapOption,
|
HudColorMapOption,
|
||||||
HudSignalPanel,
|
HudSignalPanel,
|
||||||
HudSummary,
|
HudSummary,
|
||||||
PressureColorMapPreset,
|
LocaleCode,
|
||||||
StageStatusTone
|
MatrixDisplayMode,
|
||||||
|
PressureColorMapPreset
|
||||||
} from "$lib/types/hud";
|
} from "$lib/types/hud";
|
||||||
|
|
||||||
export let title = "";
|
export let locale: LocaleCode = "zh-CN";
|
||||||
export let hint = "";
|
|
||||||
export let statusText = "";
|
|
||||||
export let statusTone: StageStatusTone = "idle";
|
|
||||||
export let leftPanels: HudSignalPanel[] = [];
|
export let leftPanels: HudSignalPanel[] = [];
|
||||||
export let rightPanels: HudSignalPanel[] = [];
|
export let rightPanels: HudSignalPanel[] = [];
|
||||||
export let summary: HudSummary;
|
export let summary: HudSummary;
|
||||||
@@ -39,8 +38,9 @@
|
|||||||
export let matrixRows = 12;
|
export let matrixRows = 12;
|
||||||
export let matrixCols = 7;
|
export let matrixCols = 7;
|
||||||
export let rangeMin = 0;
|
export let rangeMin = 0;
|
||||||
export let rangeMax = 5000;
|
export let rangeMax = 16000;
|
||||||
export let colorMapPreset: PressureColorMapPreset = "emerald";
|
export let colorMapPreset: PressureColorMapPreset = "emerald";
|
||||||
|
export let matrixDisplayMode: MatrixDisplayMode = "dots";
|
||||||
export let colorMapOptions: HudColorMapOption[] = [];
|
export let colorMapOptions: HudColorMapOption[] = [];
|
||||||
export let replaySectionLabel = "";
|
export let replaySectionLabel = "";
|
||||||
export let replayPlayLabel = "";
|
export let replayPlayLabel = "";
|
||||||
@@ -54,9 +54,9 @@
|
|||||||
export let replayProgress = 0;
|
export let replayProgress = 0;
|
||||||
export let replayFileName = "";
|
export let replayFileName = "";
|
||||||
export let replayFrameInfo = "";
|
export let replayFrameInfo = "";
|
||||||
|
export let showPrecisionTestPanel = false;
|
||||||
|
|
||||||
let stagePlaneEl: HTMLDivElement | undefined;
|
let stagePlaneEl: HTMLDivElement | undefined;
|
||||||
let topOverlayEl: HTMLDivElement | undefined;
|
|
||||||
let panelZoneEl: HTMLDivElement | undefined;
|
let panelZoneEl: HTMLDivElement | undefined;
|
||||||
let leftStackEl: HTMLDivElement | undefined;
|
let leftStackEl: HTMLDivElement | undefined;
|
||||||
let rightStackEl: HTMLDivElement | undefined;
|
let rightStackEl: HTMLDivElement | undefined;
|
||||||
@@ -81,6 +81,9 @@
|
|||||||
$: replaySide = summarySide === "left" ? "right" : "left";
|
$: replaySide = summarySide === "left" ? "right" : "left";
|
||||||
$: replayToggleButtonText = replayIsPlaying ? replayPauseLabel : replayPlayLabel;
|
$: replayToggleButtonText = replayIsPlaying ? replayPauseLabel : replayPlayLabel;
|
||||||
$: replayProgressPercent = Math.round(Math.min(1, Math.max(0, replayProgress)) * 100);
|
$: replayProgressPercent = Math.round(Math.min(1, Math.max(0, replayProgress)) * 100);
|
||||||
|
$: summaryCurveVisible = summary.points.length > 0 && summary.points.some((value) => Number.isFinite(value) && Math.abs(value) >= 0.0001);
|
||||||
|
$: splitMatrixTitle = locale === "zh-CN" ? "数字矩阵" : "Matrix";
|
||||||
|
$: splitMatrixHint = locale === "zh-CN" ? "实时压力数据 / 数字矩阵" : "Live pressure matrix";
|
||||||
|
|
||||||
function toPxNumber(rawValue: string): number {
|
function toPxNumber(rawValue: string): number {
|
||||||
const value = Number.parseFloat(rawValue);
|
const value = Number.parseFloat(rawValue);
|
||||||
@@ -101,15 +104,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function recomputePanelLayout(): void {
|
function recomputePanelLayout(): void {
|
||||||
if (!stagePlaneEl || !topOverlayEl) {
|
if (!stagePlaneEl) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const planeRect = stagePlaneEl.getBoundingClientRect();
|
panelZoneTopPx = showPrecisionTestPanel ? 24 : 16;
|
||||||
const overlayRect = topOverlayEl.getBoundingClientRect();
|
|
||||||
const overlayBottom = overlayRect.bottom - planeRect.top;
|
|
||||||
const upperTopLimit = Math.max(72, Math.round(stagePlaneEl.clientHeight * 0.34));
|
|
||||||
panelZoneTopPx = clamp(Math.round(overlayBottom + 8), 56, upperTopLimit);
|
|
||||||
|
|
||||||
const panelZoneBottomPx = panelZoneEl ? toPxNumber(getComputedStyle(panelZoneEl).bottom) : 0;
|
const panelZoneBottomPx = panelZoneEl ? toPxNumber(getComputedStyle(panelZoneEl).bottom) : 0;
|
||||||
const zoneHeight = Math.max(0, stagePlaneEl.clientHeight - panelZoneTopPx - panelZoneBottomPx);
|
const zoneHeight = Math.max(0, stagePlaneEl.clientHeight - panelZoneTopPx - panelZoneBottomPx);
|
||||||
@@ -153,10 +152,6 @@
|
|||||||
resizeObserver.observe(stagePlaneEl);
|
resizeObserver.observe(stagePlaneEl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (topOverlayEl) {
|
|
||||||
resizeObserver.observe(topOverlayEl);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (leftStackEl) {
|
if (leftStackEl) {
|
||||||
resizeObserver.observe(leftStackEl);
|
resizeObserver.observe(leftStackEl);
|
||||||
}
|
}
|
||||||
@@ -181,20 +176,33 @@
|
|||||||
bind:this={stagePlaneEl}
|
bind:this={stagePlaneEl}
|
||||||
style="--panel-zone-top-dyn: {panelZoneTopPx}px; --rail-scale-left: {leftRailScale}; --rail-scale-right: {rightRailScale};"
|
style="--panel-zone-top-dyn: {panelZoneTopPx}px; --rail-scale-left: {leftRailScale}; --rail-scale-right: {rightRailScale};"
|
||||||
>
|
>
|
||||||
<div class="stage-top-overlay" bind:this={topOverlayEl}>
|
{#if showPrecisionTestPanel}
|
||||||
<div class="stage-meta">
|
<div class="split-game-wrap">
|
||||||
<p class="meta-label">WebGL2 Stage</p>
|
<section class="split-panel split-matrix-panel">
|
||||||
<h2>{title}</h2>
|
<header class="split-panel-head">
|
||||||
<p class="meta-hint">{hint}</p>
|
<p>{splitMatrixTitle}</p>
|
||||||
</div>
|
<span>{splitMatrixHint}</span>
|
||||||
<p class="runtime-status" class:is-ok={statusTone === "ok"} class:is-warn={statusTone === "warn"}>
|
</header>
|
||||||
{statusText}
|
<div class="split-panel-body">
|
||||||
</p>
|
{#key `${matrixRows}x${matrixCols}:${colorMapPreset}:split`}
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="canvas-wrap">
|
|
||||||
{#key `${matrixRows}x${matrixCols}`}
|
|
||||||
<PressureMatrixViewer
|
<PressureMatrixViewer
|
||||||
|
{summary}
|
||||||
|
{pressureMatrix}
|
||||||
|
{matrixRows}
|
||||||
|
{matrixCols}
|
||||||
|
{rangeMin}
|
||||||
|
{rangeMax}
|
||||||
|
{colorMapPreset}
|
||||||
|
{matrixDisplayMode}
|
||||||
|
showStatsPanel={true}
|
||||||
|
/>
|
||||||
|
{/key}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="split-panel split-breakout-panel">
|
||||||
|
<NeonBreakoutArena
|
||||||
|
{locale}
|
||||||
{pressureMatrix}
|
{pressureMatrix}
|
||||||
{matrixRows}
|
{matrixRows}
|
||||||
{matrixCols}
|
{matrixCols}
|
||||||
@@ -202,10 +210,27 @@
|
|||||||
{rangeMax}
|
{rangeMax}
|
||||||
{colorMapPreset}
|
{colorMapPreset}
|
||||||
/>
|
/>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<div class="canvas-wrap">
|
||||||
|
{#key `${matrixRows}x${matrixCols}:${colorMapPreset}`}
|
||||||
|
<PressureMatrixViewer
|
||||||
|
{summary}
|
||||||
|
{pressureMatrix}
|
||||||
|
{matrixRows}
|
||||||
|
{matrixCols}
|
||||||
|
{rangeMin}
|
||||||
|
{rangeMax}
|
||||||
|
{colorMapPreset}
|
||||||
|
{matrixDisplayMode}
|
||||||
|
showStatsPanel={true}
|
||||||
|
/>
|
||||||
{/key}
|
{/key}
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
{#if showConfigPanel}
|
{#if showConfigPanel && !showPrecisionTestPanel}
|
||||||
<div class="config-panel-wrap">
|
<div class="config-panel-wrap">
|
||||||
<ConfigPanel
|
<ConfigPanel
|
||||||
bind:matrixRows
|
bind:matrixRows
|
||||||
@@ -230,6 +255,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
{#if !showPrecisionTestPanel}
|
||||||
<div class="panel-zone" bind:this={panelZoneEl}>
|
<div class="panel-zone" bind:this={panelZoneEl}>
|
||||||
<aside class="side-rail left-rail">
|
<aside class="side-rail left-rail">
|
||||||
<div class="rail-stack" bind:this={leftStackEl}>
|
<div class="rail-stack" bind:this={leftStackEl}>
|
||||||
@@ -244,7 +270,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
{#if summary.points.length > 0 && summarySide === "left"}
|
{#if summaryCurveVisible && summarySide === "left"}
|
||||||
<div
|
<div
|
||||||
class="panel-motion-shell"
|
class="panel-motion-shell"
|
||||||
in:fly={{ x: -180, duration: 340, opacity: 0.08, easing: cubicOut }}
|
in:fly={{ x: -180, duration: 340, opacity: 0.08, easing: cubicOut }}
|
||||||
@@ -275,7 +301,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
{#if summary.points.length > 0 && summarySide === "right"}
|
{#if summaryCurveVisible && summarySide === "right"}
|
||||||
<div
|
<div
|
||||||
class="panel-motion-shell"
|
class="panel-motion-shell"
|
||||||
in:fly={{ x: 180, duration: 340, opacity: 0.08, easing: cubicOut }}
|
in:fly={{ x: 180, duration: 340, opacity: 0.08, easing: cubicOut }}
|
||||||
@@ -293,8 +319,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
{#if replayHasData}
|
{#if replayHasData && !showPrecisionTestPanel}
|
||||||
<aside class="replay-floating-panel" class:is-left={replaySide === "left"} class:is-right={replaySide === "right"}>
|
<aside class="replay-floating-panel" class:is-left={replaySide === "left"} class:is-right={replaySide === "right"}>
|
||||||
<div class="replay-panel-head">
|
<div class="replay-panel-head">
|
||||||
<div class="replay-panel-title-group">
|
<div class="replay-panel-title-group">
|
||||||
@@ -332,9 +359,11 @@
|
|||||||
</aside>
|
</aside>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
{#if !showPrecisionTestPanel}
|
||||||
<div class="stage-bottom-overlay">
|
<div class="stage-bottom-overlay">
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
</section>
|
</section>
|
||||||
@@ -351,12 +380,17 @@
|
|||||||
min-height: 0;
|
min-height: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border-radius: 0.72rem;
|
border-radius: 0.72rem;
|
||||||
border: 1px solid rgb(101 133 152 / 0.2);
|
border: 1px solid rgb(var(--hud-border-rgb) / 0.2);
|
||||||
background:
|
background:
|
||||||
linear-gradient(170deg, rgb(8 12 16 / 0.86) 0%, rgb(0 0 0 / 0.96) 58%, rgb(6 10 14 / 0.9) 100%),
|
linear-gradient(
|
||||||
radial-gradient(circle at 50% 0, rgb(62 232 255 / 0.04), transparent 48%);
|
170deg,
|
||||||
|
rgb(var(--hud-surface-rgb) / 0.86) 0%,
|
||||||
|
rgb(var(--hud-surface-deep-rgb) / 0.96) 58%,
|
||||||
|
rgb(var(--hud-surface-alt-rgb) / 0.9) 100%
|
||||||
|
),
|
||||||
|
radial-gradient(circle at 50% 0, rgb(var(--hud-glow-rgb) / 0.04), transparent 48%);
|
||||||
box-shadow:
|
box-shadow:
|
||||||
inset 0 1px 0 rgb(175 216 240 / 0.08),
|
inset 0 1px 0 rgb(var(--hud-border-strong-rgb) / 0.08),
|
||||||
inset 0 -36px 72px rgb(0 0 0 / 0.4);
|
inset 0 -36px 72px rgb(0 0 0 / 0.4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,75 +407,6 @@
|
|||||||
block-size: 100%;
|
block-size: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stage-top-overlay {
|
|
||||||
position: absolute;
|
|
||||||
top: clamp(0.55rem, 1.1vw, 0.9rem);
|
|
||||||
left: calc(var(--rail-width) + var(--safe-gap) + var(--rail-edge-inset));
|
|
||||||
right: calc(var(--rail-width) + var(--safe-gap) + var(--rail-edge-inset));
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: flex-start;
|
|
||||||
gap: 0.7rem;
|
|
||||||
z-index: 7;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stage-meta {
|
|
||||||
min-width: 0;
|
|
||||||
max-inline-size: min(22rem, 62%);
|
|
||||||
padding: 0.3rem 0.5rem 0.35rem;
|
|
||||||
border: 1px solid rgb(112 146 166 / 0.2);
|
|
||||||
border-radius: 0.45rem;
|
|
||||||
background: rgb(2 8 12 / 0.45);
|
|
||||||
backdrop-filter: blur(2px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.meta-label {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 0.56rem;
|
|
||||||
color: rgb(148 171 189 / 0.8);
|
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 0.1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
margin: 0.08rem 0 0;
|
|
||||||
font-size: clamp(0.75rem, 1.1vw, 0.92rem);
|
|
||||||
color: rgb(222 241 255 / 0.96);
|
|
||||||
letter-spacing: 0.03em;
|
|
||||||
font-weight: 500;
|
|
||||||
line-height: 1.2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.meta-hint {
|
|
||||||
margin: 0.09rem 0 0;
|
|
||||||
font-size: 0.62rem;
|
|
||||||
color: rgb(142 165 183 / 0.76);
|
|
||||||
line-height: 1.15;
|
|
||||||
}
|
|
||||||
|
|
||||||
.runtime-status {
|
|
||||||
margin: 0;
|
|
||||||
align-self: center;
|
|
||||||
border: 1px solid rgb(95 128 149 / 0.35);
|
|
||||||
border-radius: 999px;
|
|
||||||
padding: 0.3rem 0.66rem;
|
|
||||||
font-size: 0.66rem;
|
|
||||||
letter-spacing: 0.08em;
|
|
||||||
color: rgb(150 174 194 / 0.9);
|
|
||||||
text-transform: uppercase;
|
|
||||||
white-space: nowrap;
|
|
||||||
background: rgb(3 10 15 / 0.62);
|
|
||||||
}
|
|
||||||
|
|
||||||
.runtime-status.is-ok {
|
|
||||||
color: rgb(204 248 184 / 0.94);
|
|
||||||
}
|
|
||||||
|
|
||||||
.runtime-status.is-warn {
|
|
||||||
color: rgb(255 205 188 / 0.92);
|
|
||||||
}
|
|
||||||
|
|
||||||
.canvas-wrap {
|
.canvas-wrap {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
@@ -458,6 +423,70 @@
|
|||||||
max-inline-size: min(24rem, 40vw);
|
max-inline-size: min(24rem, 40vw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.split-game-wrap {
|
||||||
|
position: absolute;
|
||||||
|
inset: clamp(0.46rem, 1vw, 0.82rem);
|
||||||
|
z-index: 6;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 0.98fr) minmax(0, 1.02fr);
|
||||||
|
gap: clamp(0.45rem, 1vw, 0.9rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.split-panel {
|
||||||
|
position: relative;
|
||||||
|
min-block-size: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid rgb(var(--hud-border-rgb) / 0.26);
|
||||||
|
border-radius: 0.58rem;
|
||||||
|
background:
|
||||||
|
linear-gradient(180deg, rgb(var(--hud-surface-rgb) / 0.84), rgb(var(--hud-surface-deep-rgb) / 0.9)),
|
||||||
|
radial-gradient(circle at 50% 0, rgb(var(--hud-glow-rgb) / 0.06), transparent 56%);
|
||||||
|
box-shadow:
|
||||||
|
inset 0 1px 0 rgb(var(--hud-border-strong-rgb) / 0.07),
|
||||||
|
0 0 20px rgb(var(--hud-glow-rgb) / 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.split-panel-head {
|
||||||
|
position: absolute;
|
||||||
|
top: 0.42rem;
|
||||||
|
left: 0.52rem;
|
||||||
|
z-index: 5;
|
||||||
|
display: grid;
|
||||||
|
gap: 0.1rem;
|
||||||
|
margin: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.split-panel-head p {
|
||||||
|
margin: 0;
|
||||||
|
color: rgb(var(--hud-text-main-rgb) / 0.96);
|
||||||
|
font-size: 0.62rem;
|
||||||
|
letter-spacing: 0.12em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.split-panel-head span {
|
||||||
|
color: rgb(var(--hud-text-dim-rgb) / 0.82);
|
||||||
|
font-size: 0.52rem;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.split-panel-body {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.split-matrix-panel :global(.viewer-controls) {
|
||||||
|
left: clamp(0.7rem, 1.7vw, 1.15rem);
|
||||||
|
top: clamp(3.8rem, 8.8vh, 4.9rem);
|
||||||
|
max-inline-size: min(13.2rem, 65%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.split-matrix-panel :global(.stats-panel) {
|
||||||
|
padding: 0.62rem 0.68rem 0.72rem;
|
||||||
|
}
|
||||||
|
|
||||||
.panel-zone {
|
.panel-zone {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: var(--panel-zone-top-dyn, var(--panel-zone-top));
|
top: var(--panel-zone-top-dyn, var(--panel-zone-top));
|
||||||
@@ -533,15 +562,15 @@
|
|||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 0.52rem;
|
gap: 0.52rem;
|
||||||
border: 1px solid rgb(95 136 159 / 0.34);
|
border: 1px solid rgb(var(--hud-border-rgb) / 0.34);
|
||||||
border-radius: 0.66rem;
|
border-radius: 0.66rem;
|
||||||
padding: 0.66rem 0.72rem;
|
padding: 0.66rem 0.72rem;
|
||||||
background:
|
background:
|
||||||
linear-gradient(180deg, rgb(8 14 19 / 0.86), rgb(4 8 12 / 0.8)),
|
linear-gradient(180deg, rgb(var(--hud-surface-rgb) / 0.86), rgb(var(--hud-surface-deep-rgb) / 0.8)),
|
||||||
radial-gradient(circle at 50% 0, rgb(62 232 255 / 0.07), transparent 56%);
|
radial-gradient(circle at 50% 0, rgb(var(--hud-glow-rgb) / 0.07), transparent 56%);
|
||||||
box-shadow:
|
box-shadow:
|
||||||
inset 0 1px 0 rgb(183 218 239 / 0.08),
|
inset 0 1px 0 rgb(var(--hud-border-strong-rgb) / 0.08),
|
||||||
0 0 18px rgb(62 232 255 / 0.1);
|
0 0 18px rgb(var(--hud-glow-rgb) / 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.replay-floating-panel.is-right {
|
.replay-floating-panel.is-right {
|
||||||
@@ -582,24 +611,24 @@
|
|||||||
font-size: 0.58rem;
|
font-size: 0.58rem;
|
||||||
letter-spacing: 0.11em;
|
letter-spacing: 0.11em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: rgb(152 185 206 / 0.86);
|
color: rgb(var(--hud-text-dim-rgb) / 0.86);
|
||||||
}
|
}
|
||||||
|
|
||||||
.replay-panel-file {
|
.replay-panel-file {
|
||||||
font-size: 0.73rem;
|
font-size: 0.73rem;
|
||||||
letter-spacing: 0.03em;
|
letter-spacing: 0.03em;
|
||||||
color: rgb(221 241 255 / 0.94);
|
color: rgb(var(--hud-text-main-rgb) / 0.94);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
.replay-panel-frame {
|
.replay-panel-frame {
|
||||||
border: 1px solid rgb(133 255 68 / 0.36);
|
border: 1px solid rgb(var(--hud-lime-rgb) / 0.36);
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
padding: 0.16rem 0.52rem;
|
padding: 0.16rem 0.52rem;
|
||||||
background: rgb(17 28 15 / 0.64);
|
background: rgb(var(--hud-surface-alt-rgb) / 0.64);
|
||||||
color: rgb(204 255 178 / 0.94);
|
color: rgb(var(--hud-lime-rgb) / 0.94);
|
||||||
font-size: 0.67rem;
|
font-size: 0.67rem;
|
||||||
letter-spacing: 0.07em;
|
letter-spacing: 0.07em;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
@@ -608,10 +637,10 @@
|
|||||||
.replay-close-btn {
|
.replay-close-btn {
|
||||||
inline-size: 1.82rem;
|
inline-size: 1.82rem;
|
||||||
block-size: 1.82rem;
|
block-size: 1.82rem;
|
||||||
border: 1px solid rgb(255 98 76 / 0.44);
|
border: 1px solid rgb(var(--hud-orange-rgb) / 0.44);
|
||||||
border-radius: 0.32rem;
|
border-radius: 0.32rem;
|
||||||
background: rgb(24 10 12 / 0.88);
|
background: rgb(var(--hud-surface-deep-rgb) / 0.88);
|
||||||
color: rgb(255 210 203 / 0.96);
|
color: rgb(var(--hud-orange-rgb) / 0.96);
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
display: grid;
|
display: grid;
|
||||||
@@ -624,9 +653,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.replay-close-btn:hover {
|
.replay-close-btn:hover {
|
||||||
border-color: rgb(255 132 115 / 0.66);
|
border-color: rgb(var(--hud-orange-rgb) / 0.66);
|
||||||
color: rgb(255 234 228 / 0.98);
|
color: rgb(var(--hud-text-main-rgb) / 0.98);
|
||||||
box-shadow: 0 0 12px rgb(255 91 63 / 0.2);
|
box-shadow: 0 0 12px rgb(var(--hud-orange-rgb) / 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.replay-panel-controls {
|
.replay-panel-controls {
|
||||||
@@ -643,11 +672,11 @@
|
|||||||
|
|
||||||
.replay-action-btn {
|
.replay-action-btn {
|
||||||
min-block-size: 1.82rem;
|
min-block-size: 1.82rem;
|
||||||
border: 1px solid rgb(62 232 255 / 0.36);
|
border: 1px solid rgb(var(--hud-cyan-rgb) / 0.36);
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
padding: 0.2rem 0.66rem;
|
padding: 0.2rem 0.66rem;
|
||||||
background: rgb(8 19 25 / 0.9);
|
background: rgb(var(--hud-surface-alt-rgb) / 0.9);
|
||||||
color: rgb(225 246 255 / 0.96);
|
color: rgb(var(--hud-text-main-rgb) / 0.96);
|
||||||
font-size: 0.7rem;
|
font-size: 0.7rem;
|
||||||
letter-spacing: 0.05em;
|
letter-spacing: 0.05em;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -657,19 +686,19 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.replay-action-btn:hover {
|
.replay-action-btn:hover {
|
||||||
border-color: rgb(116 245 255 / 0.58);
|
border-color: rgb(var(--hud-cyan-rgb) / 0.58);
|
||||||
box-shadow: 0 0 10px rgb(62 232 255 / 0.14);
|
box-shadow: 0 0 10px rgb(var(--hud-cyan-rgb) / 0.14);
|
||||||
}
|
}
|
||||||
|
|
||||||
.replay-action-btn.is-stop {
|
.replay-action-btn.is-stop {
|
||||||
border-color: rgb(255 91 63 / 0.44);
|
border-color: rgb(var(--hud-orange-rgb) / 0.44);
|
||||||
color: rgb(255 223 214 / 0.94);
|
color: rgb(var(--hud-orange-rgb) / 0.94);
|
||||||
background: rgb(27 12 10 / 0.86);
|
background: rgb(var(--hud-surface-deep-rgb) / 0.86);
|
||||||
}
|
}
|
||||||
|
|
||||||
.replay-action-btn.is-stop:hover {
|
.replay-action-btn.is-stop:hover {
|
||||||
border-color: rgb(255 124 101 / 0.64);
|
border-color: rgb(var(--hud-orange-rgb) / 0.64);
|
||||||
box-shadow: 0 0 10px rgb(255 91 63 / 0.18);
|
box-shadow: 0 0 10px rgb(var(--hud-orange-rgb) / 0.18);
|
||||||
}
|
}
|
||||||
|
|
||||||
.replay-speed-select,
|
.replay-speed-select,
|
||||||
@@ -678,15 +707,15 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.36rem;
|
gap: 0.36rem;
|
||||||
min-block-size: 1.92rem;
|
min-block-size: 1.92rem;
|
||||||
border: 1px solid rgb(95 132 158 / 0.32);
|
border: 1px solid rgb(var(--hud-border-rgb) / 0.32);
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
padding: 0.16rem 0.2rem 0.16rem 0.48rem;
|
padding: 0.16rem 0.2rem 0.16rem 0.48rem;
|
||||||
background: rgb(8 15 21 / 0.78);
|
background: rgb(var(--hud-surface-rgb) / 0.78);
|
||||||
}
|
}
|
||||||
|
|
||||||
.replay-speed-select span,
|
.replay-speed-select span,
|
||||||
.replay-progress-slider span {
|
.replay-progress-slider span {
|
||||||
color: rgb(154 176 194 / 0.84);
|
color: rgb(var(--hud-text-dim-rgb) / 0.84);
|
||||||
font-size: 0.62rem;
|
font-size: 0.62rem;
|
||||||
letter-spacing: 0.08em;
|
letter-spacing: 0.08em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
@@ -694,11 +723,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.replay-speed-select select {
|
.replay-speed-select select {
|
||||||
border: 1px solid rgb(95 132 158 / 0.34);
|
border: 1px solid rgb(var(--hud-border-rgb) / 0.34);
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
padding: 0.22rem 0.48rem;
|
padding: 0.22rem 0.48rem;
|
||||||
background: rgb(4 11 16 / 0.88);
|
background: rgb(var(--hud-surface-deep-rgb) / 0.88);
|
||||||
color: rgb(216 235 248 / 0.96);
|
color: rgb(var(--hud-text-main-rgb) / 0.96);
|
||||||
font-size: 0.72rem;
|
font-size: 0.72rem;
|
||||||
letter-spacing: 0.05em;
|
letter-spacing: 0.05em;
|
||||||
outline: none;
|
outline: none;
|
||||||
@@ -710,7 +739,7 @@
|
|||||||
|
|
||||||
.replay-progress-slider input {
|
.replay-progress-slider input {
|
||||||
inline-size: 100%;
|
inline-size: 100%;
|
||||||
accent-color: rgb(133 255 68 / 0.92);
|
accent-color: rgb(var(--hud-lime-rgb) / 0.92);
|
||||||
}
|
}
|
||||||
|
|
||||||
.stage-bottom-overlay {
|
.stage-bottom-overlay {
|
||||||
@@ -739,6 +768,10 @@
|
|||||||
.replay-floating-panel {
|
.replay-floating-panel {
|
||||||
inline-size: min(var(--rail-width), 20.8rem);
|
inline-size: min(var(--rail-width), 20.8rem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.split-game-wrap {
|
||||||
|
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-height: 900px) {
|
@media (max-height: 900px) {
|
||||||
@@ -782,5 +815,10 @@
|
|||||||
right: calc(var(--rail-edge-inset) + 0.1rem);
|
right: calc(var(--rail-edge-inset) + 0.1rem);
|
||||||
inline-size: auto;
|
inline-size: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.split-game-wrap {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-template-rows: minmax(0, 0.92fr) minmax(0, 1.08fr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||