Compare commits
11 Commits
91307f1985
...
0528-5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de0d397dcd | ||
|
|
da424d1637 | ||
|
|
2c6fee9aad | ||
|
|
2828eaafb5 | ||
|
|
821800beb1 | ||
|
|
8533747670 | ||
|
|
160ff54368 | ||
|
|
79faa67dd8 | ||
|
|
78c4445b93 | ||
|
|
0812142359 | ||
|
|
39840f469f |
Binary file not shown.
Binary file not shown.
BIN
ad_solver.exe
BIN
ad_solver.exe
Binary file not shown.
BIN
ad_solver.pdb
BIN
ad_solver.pdb
Binary file not shown.
BIN
devkit/__pycache__/sensor_server.cpython-313.pyc
Normal file
BIN
devkit/__pycache__/sensor_server.cpython-313.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
devkit/__pycache__/sensor_stream_pb2.cpython-313.pyc
Normal file
BIN
devkit/__pycache__/sensor_stream_pb2.cpython-313.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
devkit/__pycache__/sensor_stream_pb2_grpc.cpython-313.pyc
Normal file
BIN
devkit/__pycache__/sensor_stream_pb2_grpc.cpython-313.pyc
Normal file
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,8 @@
|
||||
('d:\\JE-Skin-main\\devkit\\dist\\je-skin-devkit-server.exe',
|
||||
('D:\\Workspace\\je-skin-customer-demo\\devkit\\dist\\je-skin-devkit-server.exe',
|
||||
True,
|
||||
False,
|
||||
False,
|
||||
'C:\\Python314\\Lib\\site-packages\\PyInstaller\\bootloader\\images\\icon-console.ico',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\PyInstaller\\bootloader\\images\\icon-console.ico',
|
||||
None,
|
||||
False,
|
||||
False,
|
||||
@@ -29,142 +29,173 @@
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
'd:\\JE-Skin-main\\devkit\\build\\je-skin-devkit-server\\je-skin-devkit-server.pkg',
|
||||
'D:\\Workspace\\je-skin-customer-demo\\devkit\\build\\je-skin-devkit-server\\je-skin-devkit-server.pkg',
|
||||
[('pyi-contents-directory _internal', '', 'OPTION'),
|
||||
('PYZ-00.pyz',
|
||||
'd:\\JE-Skin-main\\devkit\\build\\je-skin-devkit-server\\PYZ-00.pyz',
|
||||
'D:\\Workspace\\je-skin-customer-demo\\devkit\\build\\je-skin-devkit-server\\PYZ-00.pyz',
|
||||
'PYZ'),
|
||||
('struct',
|
||||
'd:\\JE-Skin-main\\devkit\\build\\je-skin-devkit-server\\localpycs\\struct.pyc',
|
||||
'D:\\Workspace\\je-skin-customer-demo\\devkit\\build\\je-skin-devkit-server\\localpycs\\struct.pyc',
|
||||
'PYMODULE'),
|
||||
('pyimod01_archive',
|
||||
'd:\\JE-Skin-main\\devkit\\build\\je-skin-devkit-server\\localpycs\\pyimod01_archive.pyc',
|
||||
'D:\\Workspace\\je-skin-customer-demo\\devkit\\build\\je-skin-devkit-server\\localpycs\\pyimod01_archive.pyc',
|
||||
'PYMODULE'),
|
||||
('pyimod02_importers',
|
||||
'd:\\JE-Skin-main\\devkit\\build\\je-skin-devkit-server\\localpycs\\pyimod02_importers.pyc',
|
||||
'D:\\Workspace\\je-skin-customer-demo\\devkit\\build\\je-skin-devkit-server\\localpycs\\pyimod02_importers.pyc',
|
||||
'PYMODULE'),
|
||||
('pyimod03_ctypes',
|
||||
'd:\\JE-Skin-main\\devkit\\build\\je-skin-devkit-server\\localpycs\\pyimod03_ctypes.pyc',
|
||||
'D:\\Workspace\\je-skin-customer-demo\\devkit\\build\\je-skin-devkit-server\\localpycs\\pyimod03_ctypes.pyc',
|
||||
'PYMODULE'),
|
||||
('pyimod04_pywin32',
|
||||
'd:\\JE-Skin-main\\devkit\\build\\je-skin-devkit-server\\localpycs\\pyimod04_pywin32.pyc',
|
||||
'D:\\Workspace\\je-skin-customer-demo\\devkit\\build\\je-skin-devkit-server\\localpycs\\pyimod04_pywin32.pyc',
|
||||
'PYMODULE'),
|
||||
('pyiboot01_bootstrap',
|
||||
'C:\\Python314\\Lib\\site-packages\\PyInstaller\\loader\\pyiboot01_bootstrap.py',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\PyInstaller\\loader\\pyiboot01_bootstrap.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_inspect',
|
||||
'C:\\Python314\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_inspect.py',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_inspect.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_pkgutil',
|
||||
'C:\\Python314\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pkgutil.py',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pkgutil.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_multiprocessing',
|
||||
'C:\\Python314\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_multiprocessing.py',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_multiprocessing.py',
|
||||
'PYSOURCE'),
|
||||
('sensor_server', 'D:\\JE-Skin-main\\devkit\\sensor_server.py', 'PYSOURCE'),
|
||||
('python314.dll', 'C:\\Python314\\python314.dll', 'BINARY'),
|
||||
('numpy.libs\\msvcp140-a4c2229bdc2a2a630acdc095b4d86008.dll',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy.libs\\msvcp140-a4c2229bdc2a2a630acdc095b4d86008.dll',
|
||||
('sensor_server',
|
||||
'D:\\Workspace\\je-skin-customer-demo\\devkit\\sensor_server.py',
|
||||
'PYSOURCE'),
|
||||
('python313.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\python313.dll',
|
||||
'BINARY'),
|
||||
('numpy.libs\\libscipy_openblas64_-63c857e738469261263c764a36be9436.dll',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy.libs\\libscipy_openblas64_-63c857e738469261263c764a36be9436.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy.libs\\libscipy_openblas64_-63c857e738469261263c764a36be9436.dll',
|
||||
'BINARY'),
|
||||
('select.pyd', 'C:\\Python314\\DLLs\\select.pyd', 'EXTENSION'),
|
||||
('numpy.libs\\msvcp140-a4c2229bdc2a2a630acdc095b4d86008.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy.libs\\msvcp140-a4c2229bdc2a2a630acdc095b4d86008.dll',
|
||||
'BINARY'),
|
||||
('select.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\DLLs\\select.pyd',
|
||||
'EXTENSION'),
|
||||
('_multiprocessing.pyd',
|
||||
'C:\\Python314\\DLLs\\_multiprocessing.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\DLLs\\_multiprocessing.pyd',
|
||||
'EXTENSION'),
|
||||
('_zstd.pyd', 'C:\\Python314\\DLLs\\_zstd.pyd', 'EXTENSION'),
|
||||
('pyexpat.pyd', 'C:\\Python314\\DLLs\\pyexpat.pyd', 'EXTENSION'),
|
||||
('_lzma.pyd', 'C:\\Python314\\DLLs\\_lzma.pyd', 'EXTENSION'),
|
||||
('_bz2.pyd', 'C:\\Python314\\DLLs\\_bz2.pyd', 'EXTENSION'),
|
||||
('_ssl.pyd', 'C:\\Python314\\DLLs\\_ssl.pyd', 'EXTENSION'),
|
||||
('_hashlib.pyd', 'C:\\Python314\\DLLs\\_hashlib.pyd', 'EXTENSION'),
|
||||
('unicodedata.pyd', 'C:\\Python314\\DLLs\\unicodedata.pyd', 'EXTENSION'),
|
||||
('_decimal.pyd', 'C:\\Python314\\DLLs\\_decimal.pyd', 'EXTENSION'),
|
||||
('_socket.pyd', 'C:\\Python314\\DLLs\\_socket.pyd', 'EXTENSION'),
|
||||
('_ctypes.pyd', 'C:\\Python314\\DLLs\\_ctypes.pyd', 'EXTENSION'),
|
||||
('_queue.pyd', 'C:\\Python314\\DLLs\\_queue.pyd', 'EXTENSION'),
|
||||
('numpy\\_core\\_multiarray_tests.cp314-win_amd64.pyd',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy\\_core\\_multiarray_tests.cp314-win_amd64.pyd',
|
||||
('pyexpat.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\DLLs\\pyexpat.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\_core\\_multiarray_umath.cp314-win_amd64.pyd',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy\\_core\\_multiarray_umath.cp314-win_amd64.pyd',
|
||||
('_ssl.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\DLLs\\_ssl.pyd',
|
||||
'EXTENSION'),
|
||||
('_wmi.pyd', 'C:\\Python314\\DLLs\\_wmi.pyd', 'EXTENSION'),
|
||||
('_overlapped.pyd', 'C:\\Python314\\DLLs\\_overlapped.pyd', 'EXTENSION'),
|
||||
('_asyncio.pyd', 'C:\\Python314\\DLLs\\_asyncio.pyd', 'EXTENSION'),
|
||||
('numpy\\linalg\\_umath_linalg.cp314-win_amd64.pyd',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy\\linalg\\_umath_linalg.cp314-win_amd64.pyd',
|
||||
('_hashlib.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\DLLs\\_hashlib.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\mtrand.cp314-win_amd64.pyd',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\mtrand.cp314-win_amd64.pyd',
|
||||
('unicodedata.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\DLLs\\unicodedata.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\bit_generator.cp314-win_amd64.pyd',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\bit_generator.cp314-win_amd64.pyd',
|
||||
('_decimal.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\DLLs\\_decimal.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_sfc64.cp314-win_amd64.pyd',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\_sfc64.cp314-win_amd64.pyd',
|
||||
('_socket.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\DLLs\\_socket.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_philox.cp314-win_amd64.pyd',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\_philox.cp314-win_amd64.pyd',
|
||||
('_lzma.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\DLLs\\_lzma.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_pcg64.cp314-win_amd64.pyd',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\_pcg64.cp314-win_amd64.pyd',
|
||||
('_bz2.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\DLLs\\_bz2.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_mt19937.cp314-win_amd64.pyd',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\_mt19937.cp314-win_amd64.pyd',
|
||||
('_ctypes.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\DLLs\\_ctypes.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_generator.cp314-win_amd64.pyd',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\_generator.cp314-win_amd64.pyd',
|
||||
('_queue.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\DLLs\\_queue.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_common.cp314-win_amd64.pyd',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\_common.cp314-win_amd64.pyd',
|
||||
('numpy\\_core\\_multiarray_tests.cp313-win_amd64.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy\\_core\\_multiarray_tests.cp313-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_bounded_integers.cp314-win_amd64.pyd',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\_bounded_integers.cp314-win_amd64.pyd',
|
||||
('numpy\\_core\\_multiarray_umath.cp313-win_amd64.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy\\_core\\_multiarray_umath.cp313-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\fft\\_pocketfft_umath.cp314-win_amd64.pyd',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy\\fft\\_pocketfft_umath.cp314-win_amd64.pyd',
|
||||
('_overlapped.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\DLLs\\_overlapped.pyd',
|
||||
'EXTENSION'),
|
||||
('_elementtree.pyd', 'C:\\Python314\\DLLs\\_elementtree.pyd', 'EXTENSION'),
|
||||
('grpc\\_cython\\cygrpc.cp314-win_amd64.pyd',
|
||||
'C:\\Python314\\Lib\\site-packages\\grpc\\_cython\\cygrpc.cp314-win_amd64.pyd',
|
||||
('_asyncio.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\DLLs\\_asyncio.pyd',
|
||||
'EXTENSION'),
|
||||
('_wmi.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\DLLs\\_wmi.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\linalg\\_umath_linalg.cp313-win_amd64.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy\\linalg\\_umath_linalg.cp313-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\mtrand.cp313-win_amd64.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy\\random\\mtrand.cp313-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\bit_generator.cp313-win_amd64.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy\\random\\bit_generator.cp313-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_sfc64.cp313-win_amd64.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy\\random\\_sfc64.cp313-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_philox.cp313-win_amd64.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy\\random\\_philox.cp313-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_pcg64.cp313-win_amd64.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy\\random\\_pcg64.cp313-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_mt19937.cp313-win_amd64.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy\\random\\_mt19937.cp313-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_generator.cp313-win_amd64.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy\\random\\_generator.cp313-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_common.cp313-win_amd64.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy\\random\\_common.cp313-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_bounded_integers.cp313-win_amd64.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy\\random\\_bounded_integers.cp313-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\fft\\_pocketfft_umath.cp313-win_amd64.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy\\fft\\_pocketfft_umath.cp313-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('_elementtree.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\DLLs\\_elementtree.pyd',
|
||||
'EXTENSION'),
|
||||
('grpc\\_cython\\cygrpc.cp313-win_amd64.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\grpc\\_cython\\cygrpc.cp313-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('google\\_upb\\_message.pyd',
|
||||
'C:\\Python314\\Lib\\site-packages\\google\\_upb\\_message.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\google\\_upb\\_message.pyd',
|
||||
'EXTENSION'),
|
||||
('grpc_tools\\_protoc_compiler.cp314-win_amd64.pyd',
|
||||
'C:\\Python314\\Lib\\site-packages\\grpc_tools\\_protoc_compiler.cp314-win_amd64.pyd',
|
||||
('grpc_tools\\_protoc_compiler.cp313-win_amd64.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\grpc_tools\\_protoc_compiler.cp313-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('api-ms-win-crt-filesystem-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-filesystem-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-crt-locale-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-locale-l1-1-0.dll',
|
||||
('api-ms-win-crt-process-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-process-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-crt-time-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-time-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-crt-environment-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-environment-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-crt-runtime-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-runtime-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-crt-convert-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-convert-l1-1-0.dll',
|
||||
('api-ms-win-crt-locale-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-locale-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-crt-heap-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-heap-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('zlib.dll', 'C:\\Users\\Administrator\\miniconda3\\zlib.dll', 'BINARY'),
|
||||
('api-ms-win-crt-string-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-string-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-crt-process-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-process-l1-1-0.dll',
|
||||
('api-ms-win-crt-filesystem-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-filesystem-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-crt-math-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-math-l1-1-0.dll',
|
||||
('api-ms-win-crt-environment-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-environment-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-crt-convert-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-convert-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-crt-stdio-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-stdio-l1-1-0.dll',
|
||||
@@ -172,188 +203,221 @@
|
||||
('api-ms-win-crt-conio-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-conio-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('VCRUNTIME140.dll', 'C:\\Python314\\VCRUNTIME140.dll', 'BINARY'),
|
||||
('VCRUNTIME140_1.dll', 'C:\\Python314\\VCRUNTIME140_1.dll', 'BINARY'),
|
||||
('api-ms-win-crt-utility-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-utility-l1-1-0.dll',
|
||||
('VCRUNTIME140.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\VCRUNTIME140.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-crt-math-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-math-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-crt-private-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-private-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('libcrypto-3.dll', 'C:\\Python314\\DLLs\\libcrypto-3.dll', 'BINARY'),
|
||||
('libssl-3.dll', 'C:\\Python314\\DLLs\\libssl-3.dll', 'BINARY'),
|
||||
('libffi-8.dll', 'C:\\Python314\\DLLs\\libffi-8.dll', 'BINARY'),
|
||||
('python3.dll', 'C:\\Python314\\python3.dll', 'BINARY'),
|
||||
('api-ms-win-crt-utility-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-utility-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('VCRUNTIME140_1.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\VCRUNTIME140_1.dll',
|
||||
'BINARY'),
|
||||
('libexpat.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Library\\bin\\libexpat.dll',
|
||||
'BINARY'),
|
||||
('libssl-3-x64.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Library\\bin\\libssl-3-x64.dll',
|
||||
'BINARY'),
|
||||
('libcrypto-3-x64.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Library\\bin\\libcrypto-3-x64.dll',
|
||||
'BINARY'),
|
||||
('libmpdec-4.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Library\\bin\\libmpdec-4.dll',
|
||||
'BINARY'),
|
||||
('liblzma.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Library\\bin\\liblzma.dll',
|
||||
'BINARY'),
|
||||
('LIBBZ2.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Library\\bin\\LIBBZ2.dll',
|
||||
'BINARY'),
|
||||
('ffi.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Library\\bin\\ffi.dll',
|
||||
'BINARY'),
|
||||
('python3.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\python3.dll',
|
||||
'BINARY'),
|
||||
('ucrtbase.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\ucrtbase.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-profile-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-profile-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-processthreads-l1-1-1.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-processthreads-l1-1-1.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-errorhandling-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-errorhandling-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-memory-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-memory-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-file-l2-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-file-l2-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-processthreads-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-processthreads-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-debug-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-debug-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-file-l1-2-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-file-l1-2-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-string-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-string-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-namedpipe-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-namedpipe-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-timezone-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-timezone-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-rtlsupport-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-rtlsupport-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-localization-l1-2-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-localization-l1-2-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-datetime-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-datetime-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-util-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-util-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-console-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-console-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-synch-l1-2-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-synch-l1-2-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-interlocked-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-interlocked-l1-1-0.dll',
|
||||
('api-ms-win-core-errorhandling-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-errorhandling-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-handle-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-handle-l1-1-0.dll',
|
||||
('api-ms-win-core-console-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-console-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-libraryloader-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-libraryloader-l1-1-0.dll',
|
||||
('api-ms-win-core-processthreads-l1-1-1.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-processthreads-l1-1-1.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-fibers-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-fibers-l1-1-0.dll',
|
||||
('api-ms-win-core-debug-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-debug-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-heap-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-heap-l1-1-0.dll',
|
||||
('api-ms-win-core-string-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-string-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-profile-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-profile-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-localization-l1-2-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-localization-l1-2-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-file-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-file-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-sysinfo-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-sysinfo-l1-1-0.dll',
|
||||
('api-ms-win-core-timezone-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-timezone-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-processenvironment-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-processenvironment-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-sysinfo-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-sysinfo-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-rtlsupport-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-rtlsupport-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-heap-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-heap-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-memory-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-memory-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-file-l1-2-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-file-l1-2-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-interlocked-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-interlocked-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-util-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-util-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-libraryloader-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-libraryloader-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-handle-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-handle-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-synch-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-synch-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('grpc\\_cython\\_credentials\\roots.pem',
|
||||
'C:\\Python314\\Lib\\site-packages\\grpc\\_cython\\_credentials\\roots.pem',
|
||||
('api-ms-win-core-fibers-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-fibers-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-processthreads-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-processthreads-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-datetime-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-datetime-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-namedpipe-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-namedpipe-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-file-l2-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-file-l2-1-0.dll',
|
||||
'BINARY'),
|
||||
('sensor_stream_pb2.py',
|
||||
'D:\\Workspace\\je-skin-customer-demo\\devkit\\sensor_stream_pb2.py',
|
||||
'DATA'),
|
||||
('grpc\\_cython\\_cygrpc\\private_key_signing\\private_key_signer_py_wrapper.h',
|
||||
'C:\\Python314\\Lib\\site-packages\\grpc\\_cython\\_cygrpc\\private_key_signing\\private_key_signer_py_wrapper.h',
|
||||
('sensor_stream_pb2_grpc.py',
|
||||
'D:\\Workspace\\je-skin-customer-demo\\devkit\\sensor_stream_pb2_grpc.py',
|
||||
'DATA'),
|
||||
('grpc\\_cython\\_cygrpc\\private_key_signing\\private_key_signer_py_wrapper.cc',
|
||||
'C:\\Python314\\Lib\\site-packages\\grpc\\_cython\\_cygrpc\\private_key_signing\\private_key_signer_py_wrapper.cc',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\grpc\\_cython\\_cygrpc\\private_key_signing\\private_key_signer_py_wrapper.cc',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\common\\pythoncapi-compat\\COPYING',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\common\\pythoncapi-compat\\COPYING',
|
||||
('grpc\\_cython\\_cygrpc\\private_key_signing\\private_key_signer_py_wrapper.h',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\grpc\\_cython\\_cygrpc\\private_key_signing\\private_key_signer_py_wrapper.h',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\INSTALLER',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\INSTALLER',
|
||||
('grpc\\_cython\\_credentials\\roots.pem',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\grpc\\_cython\\_credentials\\roots.pem',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\REQUESTED',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\REQUESTED',
|
||||
('numpy-2.4.6.dist-info\\WHEEL',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\WHEEL',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\licenses\\numpy\\random\\LICENSE.md',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\random\\LICENSE.md',
|
||||
('numpy-2.4.6.dist-info\\licenses\\numpy\\random\\src\\distributions\\LICENSE.md',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\licenses\\numpy\\random\\src\\distributions\\LICENSE.md',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\licenses\\numpy\\fft\\pocketfft\\LICENSE.md',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\fft\\pocketfft\\LICENSE.md',
|
||||
('numpy-2.4.6.dist-info\\REQUESTED',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\REQUESTED',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\splitmix64\\LICENSE.md',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\splitmix64\\LICENSE.md',
|
||||
('numpy-2.4.6.dist-info\\licenses\\numpy\\random\\src\\mt19937\\LICENSE.md',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\licenses\\numpy\\random\\src\\mt19937\\LICENSE.md',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\licenses\\numpy\\linalg\\lapack_lite\\LICENSE.txt',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\linalg\\lapack_lite\\LICENSE.txt',
|
||||
('numpy-2.4.6.dist-info\\licenses\\numpy\\random\\src\\sfc64\\LICENSE.md',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\licenses\\numpy\\random\\src\\sfc64\\LICENSE.md',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\include\\numpy\\libdivide\\LICENSE.txt',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\include\\numpy\\libdivide\\LICENSE.txt',
|
||||
('numpy-2.4.6.dist-info\\licenses\\numpy\\linalg\\lapack_lite\\LICENSE.txt',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\licenses\\numpy\\linalg\\lapack_lite\\LICENSE.txt',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\RECORD',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\RECORD',
|
||||
('numpy-2.4.6.dist-info\\licenses\\numpy\\random\\LICENSE.md',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\licenses\\numpy\\random\\LICENSE.md',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\WHEEL',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\WHEEL',
|
||||
('numpy-2.4.6.dist-info\\INSTALLER',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\INSTALLER',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\sfc64\\LICENSE.md',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\sfc64\\LICENSE.md',
|
||||
('numpy-2.4.6.dist-info\\licenses\\numpy\\_core\\src\\multiarray\\dragon4_LICENSE.txt',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\licenses\\numpy\\_core\\src\\multiarray\\dragon4_LICENSE.txt',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\philox\\LICENSE.md',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\philox\\LICENSE.md',
|
||||
('numpy-2.4.6.dist-info\\licenses\\numpy\\fft\\pocketfft\\LICENSE.md',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\licenses\\numpy\\fft\\pocketfft\\LICENSE.md',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\pcg64\\LICENSE.md',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\pcg64\\LICENSE.md',
|
||||
('numpy-2.4.6.dist-info\\licenses\\numpy\\ma\\LICENSE',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\licenses\\numpy\\ma\\LICENSE',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\licenses\\numpy\\ma\\LICENSE',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\ma\\LICENSE',
|
||||
('numpy-2.4.6.dist-info\\entry_points.txt',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\entry_points.txt',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\umath\\svml\\LICENSE',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\umath\\svml\\LICENSE',
|
||||
('numpy-2.4.6.dist-info\\licenses\\numpy\\_core\\src\\common\\pythoncapi-compat\\COPYING',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\licenses\\numpy\\_core\\src\\common\\pythoncapi-compat\\COPYING',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\entry_points.txt',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\entry_points.txt',
|
||||
('numpy-2.4.6.dist-info\\licenses\\LICENSE.txt',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\licenses\\LICENSE.txt',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\mt19937\\LICENSE.md',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\mt19937\\LICENSE.md',
|
||||
('numpy-2.4.6.dist-info\\licenses\\numpy\\random\\src\\splitmix64\\LICENSE.md',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\licenses\\numpy\\random\\src\\splitmix64\\LICENSE.md',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\licenses\\LICENSE.txt',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\LICENSE.txt',
|
||||
('numpy-2.4.6.dist-info\\licenses\\numpy\\_core\\src\\umath\\svml\\LICENSE',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\licenses\\numpy\\_core\\src\\umath\\svml\\LICENSE',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\multiarray\\dragon4_LICENSE.txt',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\multiarray\\dragon4_LICENSE.txt',
|
||||
('numpy-2.4.6.dist-info\\licenses\\numpy\\_core\\include\\numpy\\libdivide\\LICENSE.txt',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\licenses\\numpy\\_core\\include\\numpy\\libdivide\\LICENSE.txt',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\METADATA',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\METADATA',
|
||||
('numpy-2.4.6.dist-info\\DELVEWHEEL',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\DELVEWHEEL',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\DELVEWHEEL',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\DELVEWHEEL',
|
||||
('numpy-2.4.6.dist-info\\licenses\\numpy\\_core\\src\\npysort\\x86-simd-sort\\LICENSE.md',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\licenses\\numpy\\_core\\src\\npysort\\x86-simd-sort\\LICENSE.md',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\highway\\LICENSE',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\highway\\LICENSE',
|
||||
('numpy-2.4.6.dist-info\\METADATA',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\METADATA',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\distributions\\LICENSE.md',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\distributions\\LICENSE.md',
|
||||
('numpy-2.4.6.dist-info\\licenses\\numpy\\random\\src\\philox\\LICENSE.md',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\licenses\\numpy\\random\\src\\philox\\LICENSE.md',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\npysort\\x86-simd-sort\\LICENSE.md',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\npysort\\x86-simd-sort\\LICENSE.md',
|
||||
('numpy-2.4.6.dist-info\\RECORD',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\RECORD',
|
||||
'DATA'),
|
||||
('numpy-2.4.6.dist-info\\licenses\\numpy\\_core\\src\\highway\\LICENSE',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\licenses\\numpy\\_core\\src\\highway\\LICENSE',
|
||||
'DATA'),
|
||||
('numpy-2.4.6.dist-info\\licenses\\numpy\\random\\src\\pcg64\\LICENSE.md',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\licenses\\numpy\\random\\src\\pcg64\\LICENSE.md',
|
||||
'DATA'),
|
||||
('base_library.zip',
|
||||
'd:\\JE-Skin-main\\devkit\\build\\je-skin-devkit-server\\base_library.zip',
|
||||
'D:\\Workspace\\je-skin-customer-demo\\devkit\\build\\je-skin-devkit-server\\base_library.zip',
|
||||
'DATA')],
|
||||
[],
|
||||
False,
|
||||
False,
|
||||
1779678963,
|
||||
1780277624,
|
||||
[('run.exe',
|
||||
'C:\\Python314\\Lib\\site-packages\\PyInstaller\\bootloader\\Windows-64bit-intel\\run.exe',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\PyInstaller\\bootloader\\Windows-64bit-intel\\run.exe',
|
||||
'EXECUTABLE')],
|
||||
'C:\\Python314\\python314.dll')
|
||||
'C:\\Users\\Administrator\\miniconda3\\python313.dll')
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
('d:\\JE-Skin-main\\devkit\\build\\je-skin-devkit-server\\je-skin-devkit-server.pkg',
|
||||
('D:\\Workspace\\je-skin-customer-demo\\devkit\\build\\je-skin-devkit-server\\je-skin-devkit-server.pkg',
|
||||
{'BINARY': True,
|
||||
'DATA': True,
|
||||
'EXECUTABLE': True,
|
||||
@@ -10,139 +10,170 @@
|
||||
'SYMLINK': False},
|
||||
[('pyi-contents-directory _internal', '', 'OPTION'),
|
||||
('PYZ-00.pyz',
|
||||
'd:\\JE-Skin-main\\devkit\\build\\je-skin-devkit-server\\PYZ-00.pyz',
|
||||
'D:\\Workspace\\je-skin-customer-demo\\devkit\\build\\je-skin-devkit-server\\PYZ-00.pyz',
|
||||
'PYZ'),
|
||||
('struct',
|
||||
'd:\\JE-Skin-main\\devkit\\build\\je-skin-devkit-server\\localpycs\\struct.pyc',
|
||||
'D:\\Workspace\\je-skin-customer-demo\\devkit\\build\\je-skin-devkit-server\\localpycs\\struct.pyc',
|
||||
'PYMODULE'),
|
||||
('pyimod01_archive',
|
||||
'd:\\JE-Skin-main\\devkit\\build\\je-skin-devkit-server\\localpycs\\pyimod01_archive.pyc',
|
||||
'D:\\Workspace\\je-skin-customer-demo\\devkit\\build\\je-skin-devkit-server\\localpycs\\pyimod01_archive.pyc',
|
||||
'PYMODULE'),
|
||||
('pyimod02_importers',
|
||||
'd:\\JE-Skin-main\\devkit\\build\\je-skin-devkit-server\\localpycs\\pyimod02_importers.pyc',
|
||||
'D:\\Workspace\\je-skin-customer-demo\\devkit\\build\\je-skin-devkit-server\\localpycs\\pyimod02_importers.pyc',
|
||||
'PYMODULE'),
|
||||
('pyimod03_ctypes',
|
||||
'd:\\JE-Skin-main\\devkit\\build\\je-skin-devkit-server\\localpycs\\pyimod03_ctypes.pyc',
|
||||
'D:\\Workspace\\je-skin-customer-demo\\devkit\\build\\je-skin-devkit-server\\localpycs\\pyimod03_ctypes.pyc',
|
||||
'PYMODULE'),
|
||||
('pyimod04_pywin32',
|
||||
'd:\\JE-Skin-main\\devkit\\build\\je-skin-devkit-server\\localpycs\\pyimod04_pywin32.pyc',
|
||||
'D:\\Workspace\\je-skin-customer-demo\\devkit\\build\\je-skin-devkit-server\\localpycs\\pyimod04_pywin32.pyc',
|
||||
'PYMODULE'),
|
||||
('pyiboot01_bootstrap',
|
||||
'C:\\Python314\\Lib\\site-packages\\PyInstaller\\loader\\pyiboot01_bootstrap.py',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\PyInstaller\\loader\\pyiboot01_bootstrap.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_inspect',
|
||||
'C:\\Python314\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_inspect.py',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_inspect.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_pkgutil',
|
||||
'C:\\Python314\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pkgutil.py',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pkgutil.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_multiprocessing',
|
||||
'C:\\Python314\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_multiprocessing.py',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_multiprocessing.py',
|
||||
'PYSOURCE'),
|
||||
('sensor_server', 'D:\\JE-Skin-main\\devkit\\sensor_server.py', 'PYSOURCE'),
|
||||
('python314.dll', 'C:\\Python314\\python314.dll', 'BINARY'),
|
||||
('numpy.libs\\msvcp140-a4c2229bdc2a2a630acdc095b4d86008.dll',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy.libs\\msvcp140-a4c2229bdc2a2a630acdc095b4d86008.dll',
|
||||
('sensor_server',
|
||||
'D:\\Workspace\\je-skin-customer-demo\\devkit\\sensor_server.py',
|
||||
'PYSOURCE'),
|
||||
('python313.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\python313.dll',
|
||||
'BINARY'),
|
||||
('numpy.libs\\libscipy_openblas64_-63c857e738469261263c764a36be9436.dll',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy.libs\\libscipy_openblas64_-63c857e738469261263c764a36be9436.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy.libs\\libscipy_openblas64_-63c857e738469261263c764a36be9436.dll',
|
||||
'BINARY'),
|
||||
('select.pyd', 'C:\\Python314\\DLLs\\select.pyd', 'EXTENSION'),
|
||||
('numpy.libs\\msvcp140-a4c2229bdc2a2a630acdc095b4d86008.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy.libs\\msvcp140-a4c2229bdc2a2a630acdc095b4d86008.dll',
|
||||
'BINARY'),
|
||||
('select.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\DLLs\\select.pyd',
|
||||
'EXTENSION'),
|
||||
('_multiprocessing.pyd',
|
||||
'C:\\Python314\\DLLs\\_multiprocessing.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\DLLs\\_multiprocessing.pyd',
|
||||
'EXTENSION'),
|
||||
('_zstd.pyd', 'C:\\Python314\\DLLs\\_zstd.pyd', 'EXTENSION'),
|
||||
('pyexpat.pyd', 'C:\\Python314\\DLLs\\pyexpat.pyd', 'EXTENSION'),
|
||||
('_lzma.pyd', 'C:\\Python314\\DLLs\\_lzma.pyd', 'EXTENSION'),
|
||||
('_bz2.pyd', 'C:\\Python314\\DLLs\\_bz2.pyd', 'EXTENSION'),
|
||||
('_ssl.pyd', 'C:\\Python314\\DLLs\\_ssl.pyd', 'EXTENSION'),
|
||||
('_hashlib.pyd', 'C:\\Python314\\DLLs\\_hashlib.pyd', 'EXTENSION'),
|
||||
('unicodedata.pyd', 'C:\\Python314\\DLLs\\unicodedata.pyd', 'EXTENSION'),
|
||||
('_decimal.pyd', 'C:\\Python314\\DLLs\\_decimal.pyd', 'EXTENSION'),
|
||||
('_socket.pyd', 'C:\\Python314\\DLLs\\_socket.pyd', 'EXTENSION'),
|
||||
('_ctypes.pyd', 'C:\\Python314\\DLLs\\_ctypes.pyd', 'EXTENSION'),
|
||||
('_queue.pyd', 'C:\\Python314\\DLLs\\_queue.pyd', 'EXTENSION'),
|
||||
('numpy\\_core\\_multiarray_tests.cp314-win_amd64.pyd',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy\\_core\\_multiarray_tests.cp314-win_amd64.pyd',
|
||||
('pyexpat.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\DLLs\\pyexpat.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\_core\\_multiarray_umath.cp314-win_amd64.pyd',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy\\_core\\_multiarray_umath.cp314-win_amd64.pyd',
|
||||
('_ssl.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\DLLs\\_ssl.pyd',
|
||||
'EXTENSION'),
|
||||
('_wmi.pyd', 'C:\\Python314\\DLLs\\_wmi.pyd', 'EXTENSION'),
|
||||
('_overlapped.pyd', 'C:\\Python314\\DLLs\\_overlapped.pyd', 'EXTENSION'),
|
||||
('_asyncio.pyd', 'C:\\Python314\\DLLs\\_asyncio.pyd', 'EXTENSION'),
|
||||
('numpy\\linalg\\_umath_linalg.cp314-win_amd64.pyd',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy\\linalg\\_umath_linalg.cp314-win_amd64.pyd',
|
||||
('_hashlib.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\DLLs\\_hashlib.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\mtrand.cp314-win_amd64.pyd',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\mtrand.cp314-win_amd64.pyd',
|
||||
('unicodedata.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\DLLs\\unicodedata.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\bit_generator.cp314-win_amd64.pyd',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\bit_generator.cp314-win_amd64.pyd',
|
||||
('_decimal.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\DLLs\\_decimal.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_sfc64.cp314-win_amd64.pyd',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\_sfc64.cp314-win_amd64.pyd',
|
||||
('_socket.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\DLLs\\_socket.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_philox.cp314-win_amd64.pyd',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\_philox.cp314-win_amd64.pyd',
|
||||
('_lzma.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\DLLs\\_lzma.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_pcg64.cp314-win_amd64.pyd',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\_pcg64.cp314-win_amd64.pyd',
|
||||
('_bz2.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\DLLs\\_bz2.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_mt19937.cp314-win_amd64.pyd',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\_mt19937.cp314-win_amd64.pyd',
|
||||
('_ctypes.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\DLLs\\_ctypes.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_generator.cp314-win_amd64.pyd',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\_generator.cp314-win_amd64.pyd',
|
||||
('_queue.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\DLLs\\_queue.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_common.cp314-win_amd64.pyd',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\_common.cp314-win_amd64.pyd',
|
||||
('numpy\\_core\\_multiarray_tests.cp313-win_amd64.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy\\_core\\_multiarray_tests.cp313-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_bounded_integers.cp314-win_amd64.pyd',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\_bounded_integers.cp314-win_amd64.pyd',
|
||||
('numpy\\_core\\_multiarray_umath.cp313-win_amd64.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy\\_core\\_multiarray_umath.cp313-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\fft\\_pocketfft_umath.cp314-win_amd64.pyd',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy\\fft\\_pocketfft_umath.cp314-win_amd64.pyd',
|
||||
('_overlapped.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\DLLs\\_overlapped.pyd',
|
||||
'EXTENSION'),
|
||||
('_elementtree.pyd', 'C:\\Python314\\DLLs\\_elementtree.pyd', 'EXTENSION'),
|
||||
('grpc\\_cython\\cygrpc.cp314-win_amd64.pyd',
|
||||
'C:\\Python314\\Lib\\site-packages\\grpc\\_cython\\cygrpc.cp314-win_amd64.pyd',
|
||||
('_asyncio.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\DLLs\\_asyncio.pyd',
|
||||
'EXTENSION'),
|
||||
('_wmi.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\DLLs\\_wmi.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\linalg\\_umath_linalg.cp313-win_amd64.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy\\linalg\\_umath_linalg.cp313-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\mtrand.cp313-win_amd64.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy\\random\\mtrand.cp313-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\bit_generator.cp313-win_amd64.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy\\random\\bit_generator.cp313-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_sfc64.cp313-win_amd64.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy\\random\\_sfc64.cp313-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_philox.cp313-win_amd64.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy\\random\\_philox.cp313-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_pcg64.cp313-win_amd64.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy\\random\\_pcg64.cp313-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_mt19937.cp313-win_amd64.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy\\random\\_mt19937.cp313-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_generator.cp313-win_amd64.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy\\random\\_generator.cp313-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_common.cp313-win_amd64.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy\\random\\_common.cp313-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\random\\_bounded_integers.cp313-win_amd64.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy\\random\\_bounded_integers.cp313-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('numpy\\fft\\_pocketfft_umath.cp313-win_amd64.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy\\fft\\_pocketfft_umath.cp313-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('_elementtree.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\DLLs\\_elementtree.pyd',
|
||||
'EXTENSION'),
|
||||
('grpc\\_cython\\cygrpc.cp313-win_amd64.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\grpc\\_cython\\cygrpc.cp313-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('google\\_upb\\_message.pyd',
|
||||
'C:\\Python314\\Lib\\site-packages\\google\\_upb\\_message.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\google\\_upb\\_message.pyd',
|
||||
'EXTENSION'),
|
||||
('grpc_tools\\_protoc_compiler.cp314-win_amd64.pyd',
|
||||
'C:\\Python314\\Lib\\site-packages\\grpc_tools\\_protoc_compiler.cp314-win_amd64.pyd',
|
||||
('grpc_tools\\_protoc_compiler.cp313-win_amd64.pyd',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\grpc_tools\\_protoc_compiler.cp313-win_amd64.pyd',
|
||||
'EXTENSION'),
|
||||
('api-ms-win-crt-filesystem-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-filesystem-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-crt-locale-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-locale-l1-1-0.dll',
|
||||
('api-ms-win-crt-process-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-process-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-crt-time-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-time-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-crt-environment-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-environment-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-crt-runtime-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-runtime-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-crt-convert-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-convert-l1-1-0.dll',
|
||||
('api-ms-win-crt-locale-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-locale-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-crt-heap-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-heap-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('zlib.dll', 'C:\\Users\\Administrator\\miniconda3\\zlib.dll', 'BINARY'),
|
||||
('api-ms-win-crt-string-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-string-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-crt-process-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-process-l1-1-0.dll',
|
||||
('api-ms-win-crt-filesystem-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-filesystem-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-crt-math-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-math-l1-1-0.dll',
|
||||
('api-ms-win-crt-environment-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-environment-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-crt-convert-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-convert-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-crt-stdio-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-stdio-l1-1-0.dll',
|
||||
@@ -150,184 +181,217 @@
|
||||
('api-ms-win-crt-conio-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-conio-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('VCRUNTIME140.dll', 'C:\\Python314\\VCRUNTIME140.dll', 'BINARY'),
|
||||
('VCRUNTIME140_1.dll', 'C:\\Python314\\VCRUNTIME140_1.dll', 'BINARY'),
|
||||
('api-ms-win-crt-utility-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-utility-l1-1-0.dll',
|
||||
('VCRUNTIME140.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\VCRUNTIME140.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-crt-math-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-math-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-crt-private-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-private-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('libcrypto-3.dll', 'C:\\Python314\\DLLs\\libcrypto-3.dll', 'BINARY'),
|
||||
('libssl-3.dll', 'C:\\Python314\\DLLs\\libssl-3.dll', 'BINARY'),
|
||||
('libffi-8.dll', 'C:\\Python314\\DLLs\\libffi-8.dll', 'BINARY'),
|
||||
('python3.dll', 'C:\\Python314\\python3.dll', 'BINARY'),
|
||||
('api-ms-win-crt-utility-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-utility-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('VCRUNTIME140_1.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\VCRUNTIME140_1.dll',
|
||||
'BINARY'),
|
||||
('libexpat.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Library\\bin\\libexpat.dll',
|
||||
'BINARY'),
|
||||
('libssl-3-x64.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Library\\bin\\libssl-3-x64.dll',
|
||||
'BINARY'),
|
||||
('libcrypto-3-x64.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Library\\bin\\libcrypto-3-x64.dll',
|
||||
'BINARY'),
|
||||
('libmpdec-4.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Library\\bin\\libmpdec-4.dll',
|
||||
'BINARY'),
|
||||
('liblzma.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Library\\bin\\liblzma.dll',
|
||||
'BINARY'),
|
||||
('LIBBZ2.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Library\\bin\\LIBBZ2.dll',
|
||||
'BINARY'),
|
||||
('ffi.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Library\\bin\\ffi.dll',
|
||||
'BINARY'),
|
||||
('python3.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\python3.dll',
|
||||
'BINARY'),
|
||||
('ucrtbase.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\ucrtbase.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-profile-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-profile-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-processthreads-l1-1-1.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-processthreads-l1-1-1.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-errorhandling-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-errorhandling-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-memory-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-memory-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-file-l2-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-file-l2-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-processthreads-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-processthreads-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-debug-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-debug-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-file-l1-2-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-file-l1-2-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-string-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-string-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-namedpipe-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-namedpipe-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-timezone-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-timezone-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-rtlsupport-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-rtlsupport-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-localization-l1-2-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-localization-l1-2-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-datetime-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-datetime-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-util-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-util-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-console-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-console-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-synch-l1-2-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-synch-l1-2-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-interlocked-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-interlocked-l1-1-0.dll',
|
||||
('api-ms-win-core-errorhandling-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-errorhandling-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-handle-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-handle-l1-1-0.dll',
|
||||
('api-ms-win-core-console-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-console-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-libraryloader-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-libraryloader-l1-1-0.dll',
|
||||
('api-ms-win-core-processthreads-l1-1-1.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-processthreads-l1-1-1.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-fibers-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-fibers-l1-1-0.dll',
|
||||
('api-ms-win-core-debug-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-debug-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-heap-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-heap-l1-1-0.dll',
|
||||
('api-ms-win-core-string-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-string-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-profile-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-profile-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-localization-l1-2-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-localization-l1-2-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-file-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-file-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-sysinfo-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-sysinfo-l1-1-0.dll',
|
||||
('api-ms-win-core-timezone-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-timezone-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-processenvironment-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-processenvironment-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-sysinfo-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-sysinfo-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-rtlsupport-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-rtlsupport-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-heap-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-heap-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-memory-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-memory-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-file-l1-2-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-file-l1-2-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-interlocked-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-interlocked-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-util-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-util-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-libraryloader-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-libraryloader-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-handle-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-handle-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-synch-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-synch-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('grpc\\_cython\\_credentials\\roots.pem',
|
||||
'C:\\Python314\\Lib\\site-packages\\grpc\\_cython\\_credentials\\roots.pem',
|
||||
('api-ms-win-core-fibers-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-fibers-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-processthreads-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-processthreads-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-datetime-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-datetime-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-namedpipe-l1-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-namedpipe-l1-1-0.dll',
|
||||
'BINARY'),
|
||||
('api-ms-win-core-file-l2-1-0.dll',
|
||||
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-file-l2-1-0.dll',
|
||||
'BINARY'),
|
||||
('sensor_stream_pb2.py',
|
||||
'D:\\Workspace\\je-skin-customer-demo\\devkit\\sensor_stream_pb2.py',
|
||||
'DATA'),
|
||||
('grpc\\_cython\\_cygrpc\\private_key_signing\\private_key_signer_py_wrapper.h',
|
||||
'C:\\Python314\\Lib\\site-packages\\grpc\\_cython\\_cygrpc\\private_key_signing\\private_key_signer_py_wrapper.h',
|
||||
('sensor_stream_pb2_grpc.py',
|
||||
'D:\\Workspace\\je-skin-customer-demo\\devkit\\sensor_stream_pb2_grpc.py',
|
||||
'DATA'),
|
||||
('grpc\\_cython\\_cygrpc\\private_key_signing\\private_key_signer_py_wrapper.cc',
|
||||
'C:\\Python314\\Lib\\site-packages\\grpc\\_cython\\_cygrpc\\private_key_signing\\private_key_signer_py_wrapper.cc',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\grpc\\_cython\\_cygrpc\\private_key_signing\\private_key_signer_py_wrapper.cc',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\common\\pythoncapi-compat\\COPYING',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\common\\pythoncapi-compat\\COPYING',
|
||||
('grpc\\_cython\\_cygrpc\\private_key_signing\\private_key_signer_py_wrapper.h',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\grpc\\_cython\\_cygrpc\\private_key_signing\\private_key_signer_py_wrapper.h',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\INSTALLER',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\INSTALLER',
|
||||
('grpc\\_cython\\_credentials\\roots.pem',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\grpc\\_cython\\_credentials\\roots.pem',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\REQUESTED',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\REQUESTED',
|
||||
('numpy-2.4.6.dist-info\\WHEEL',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\WHEEL',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\licenses\\numpy\\random\\LICENSE.md',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\random\\LICENSE.md',
|
||||
('numpy-2.4.6.dist-info\\licenses\\numpy\\random\\src\\distributions\\LICENSE.md',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\licenses\\numpy\\random\\src\\distributions\\LICENSE.md',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\licenses\\numpy\\fft\\pocketfft\\LICENSE.md',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\fft\\pocketfft\\LICENSE.md',
|
||||
('numpy-2.4.6.dist-info\\REQUESTED',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\REQUESTED',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\splitmix64\\LICENSE.md',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\splitmix64\\LICENSE.md',
|
||||
('numpy-2.4.6.dist-info\\licenses\\numpy\\random\\src\\mt19937\\LICENSE.md',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\licenses\\numpy\\random\\src\\mt19937\\LICENSE.md',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\licenses\\numpy\\linalg\\lapack_lite\\LICENSE.txt',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\linalg\\lapack_lite\\LICENSE.txt',
|
||||
('numpy-2.4.6.dist-info\\licenses\\numpy\\random\\src\\sfc64\\LICENSE.md',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\licenses\\numpy\\random\\src\\sfc64\\LICENSE.md',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\include\\numpy\\libdivide\\LICENSE.txt',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\include\\numpy\\libdivide\\LICENSE.txt',
|
||||
('numpy-2.4.6.dist-info\\licenses\\numpy\\linalg\\lapack_lite\\LICENSE.txt',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\licenses\\numpy\\linalg\\lapack_lite\\LICENSE.txt',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\RECORD',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\RECORD',
|
||||
('numpy-2.4.6.dist-info\\licenses\\numpy\\random\\LICENSE.md',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\licenses\\numpy\\random\\LICENSE.md',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\WHEEL',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\WHEEL',
|
||||
('numpy-2.4.6.dist-info\\INSTALLER',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\INSTALLER',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\sfc64\\LICENSE.md',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\sfc64\\LICENSE.md',
|
||||
('numpy-2.4.6.dist-info\\licenses\\numpy\\_core\\src\\multiarray\\dragon4_LICENSE.txt',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\licenses\\numpy\\_core\\src\\multiarray\\dragon4_LICENSE.txt',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\philox\\LICENSE.md',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\philox\\LICENSE.md',
|
||||
('numpy-2.4.6.dist-info\\licenses\\numpy\\fft\\pocketfft\\LICENSE.md',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\licenses\\numpy\\fft\\pocketfft\\LICENSE.md',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\pcg64\\LICENSE.md',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\pcg64\\LICENSE.md',
|
||||
('numpy-2.4.6.dist-info\\licenses\\numpy\\ma\\LICENSE',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\licenses\\numpy\\ma\\LICENSE',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\licenses\\numpy\\ma\\LICENSE',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\ma\\LICENSE',
|
||||
('numpy-2.4.6.dist-info\\entry_points.txt',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\entry_points.txt',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\umath\\svml\\LICENSE',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\umath\\svml\\LICENSE',
|
||||
('numpy-2.4.6.dist-info\\licenses\\numpy\\_core\\src\\common\\pythoncapi-compat\\COPYING',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\licenses\\numpy\\_core\\src\\common\\pythoncapi-compat\\COPYING',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\entry_points.txt',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\entry_points.txt',
|
||||
('numpy-2.4.6.dist-info\\licenses\\LICENSE.txt',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\licenses\\LICENSE.txt',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\mt19937\\LICENSE.md',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\mt19937\\LICENSE.md',
|
||||
('numpy-2.4.6.dist-info\\licenses\\numpy\\random\\src\\splitmix64\\LICENSE.md',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\licenses\\numpy\\random\\src\\splitmix64\\LICENSE.md',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\licenses\\LICENSE.txt',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\LICENSE.txt',
|
||||
('numpy-2.4.6.dist-info\\licenses\\numpy\\_core\\src\\umath\\svml\\LICENSE',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\licenses\\numpy\\_core\\src\\umath\\svml\\LICENSE',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\multiarray\\dragon4_LICENSE.txt',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\multiarray\\dragon4_LICENSE.txt',
|
||||
('numpy-2.4.6.dist-info\\licenses\\numpy\\_core\\include\\numpy\\libdivide\\LICENSE.txt',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\licenses\\numpy\\_core\\include\\numpy\\libdivide\\LICENSE.txt',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\METADATA',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\METADATA',
|
||||
('numpy-2.4.6.dist-info\\DELVEWHEEL',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\DELVEWHEEL',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\DELVEWHEEL',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\DELVEWHEEL',
|
||||
('numpy-2.4.6.dist-info\\licenses\\numpy\\_core\\src\\npysort\\x86-simd-sort\\LICENSE.md',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\licenses\\numpy\\_core\\src\\npysort\\x86-simd-sort\\LICENSE.md',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\highway\\LICENSE',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\highway\\LICENSE',
|
||||
('numpy-2.4.6.dist-info\\METADATA',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\METADATA',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\distributions\\LICENSE.md',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\distributions\\LICENSE.md',
|
||||
('numpy-2.4.6.dist-info\\licenses\\numpy\\random\\src\\philox\\LICENSE.md',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\licenses\\numpy\\random\\src\\philox\\LICENSE.md',
|
||||
'DATA'),
|
||||
('numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\npysort\\x86-simd-sort\\LICENSE.md',
|
||||
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\npysort\\x86-simd-sort\\LICENSE.md',
|
||||
('numpy-2.4.6.dist-info\\RECORD',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\RECORD',
|
||||
'DATA'),
|
||||
('numpy-2.4.6.dist-info\\licenses\\numpy\\_core\\src\\highway\\LICENSE',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\licenses\\numpy\\_core\\src\\highway\\LICENSE',
|
||||
'DATA'),
|
||||
('numpy-2.4.6.dist-info\\licenses\\numpy\\random\\src\\pcg64\\LICENSE.md',
|
||||
'C:\\Users\\Administrator\\miniconda3\\Lib\\site-packages\\numpy-2.4.6.dist-info\\licenses\\numpy\\random\\src\\pcg64\\LICENSE.md',
|
||||
'DATA'),
|
||||
('base_library.zip',
|
||||
'd:\\JE-Skin-main\\devkit\\build\\je-skin-devkit-server\\base_library.zip',
|
||||
'D:\\Workspace\\je-skin-customer-demo\\devkit\\build\\je-skin-devkit-server\\base_library.zip',
|
||||
'DATA')],
|
||||
'python314.dll',
|
||||
'python313.dll',
|
||||
False,
|
||||
False,
|
||||
False,
|
||||
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -14,40 +14,41 @@ Types of import:
|
||||
IMPORTANT: Do NOT post this list to the issue-tracker. Use it as a basis for
|
||||
tracking down the missing module yourself. Thanks!
|
||||
|
||||
missing module named pwd - imported by posixpath (delayed, conditional, optional), shutil (delayed, optional), tarfile (optional), pathlib (optional), netrc (delayed, optional), subprocess (delayed, conditional, optional), http.server (delayed, optional)
|
||||
missing module named grp - imported by shutil (delayed, optional), tarfile (optional), pathlib (optional), subprocess (delayed, conditional, optional)
|
||||
missing module named 'collections.abc' - imported by _colorize (top-level), typing (top-level), traceback (top-level), logging (top-level), selectors (top-level), http.client (top-level), importlib.resources.readers (top-level), inspect (top-level), tracemalloc (top-level), multiprocessing.managers (top-level), typing_extensions (top-level), asyncio.base_events (top-level), asyncio.coroutines (top-level), grpc.aio._metadata (top-level), google.protobuf.internal.containers (top-level), google.protobuf.internal.well_known_types (top-level), numpy._typing._array_like (top-level), numpy._typing._nested_sequence (conditional), numpy._typing._shape (top-level), numpy._typing._dtype_like (top-level), numpy.lib._function_base_impl (top-level), _pyrepl.types (top-level), numpy.lib._npyio_impl (top-level), numpy.random._common (top-level), numpy.random._generator (top-level), numpy.random.bit_generator (top-level), numpy.random.mtrand (top-level), numpy.polynomial._polybase (top-level), xml.etree.ElementTree (top-level)
|
||||
missing module named pwd - imported by posixpath (delayed, conditional, optional), shutil (delayed, optional), tarfile (optional), pathlib._local (optional), subprocess (delayed, conditional, optional), http.server (delayed, optional), netrc (delayed, optional), getpass (delayed, optional)
|
||||
missing module named grp - imported by shutil (delayed, optional), tarfile (optional), pathlib._local (optional), subprocess (delayed, conditional, optional)
|
||||
missing module named 'collections.abc' - imported by traceback (top-level), typing (top-level), inspect (top-level), logging (top-level), importlib.resources.readers (top-level), selectors (top-level), tracemalloc (top-level), http.client (top-level), typing_extensions (top-level), asyncio.base_events (top-level), asyncio.coroutines (top-level), grpc.aio._metadata (top-level), google.protobuf.internal.containers (top-level), google.protobuf.internal.well_known_types (top-level), numpy._typing._array_like (top-level), numpy._typing._nested_sequence (conditional), numpy._typing._shape (top-level), numpy._typing._dtype_like (top-level), numpy.lib._function_base_impl (top-level), numpy.lib._npyio_impl (top-level), numpy.random._common (top-level), numpy.random._generator (top-level), numpy.random.bit_generator (top-level), numpy.random.mtrand (top-level), numpy.polynomial._polybase (top-level), xml.etree.ElementTree (top-level)
|
||||
missing module named _posixsubprocess - imported by subprocess (conditional), multiprocessing.util (delayed)
|
||||
missing module named fcntl - imported by pathlib._os (optional), subprocess (optional)
|
||||
missing module named fcntl - imported by subprocess (optional)
|
||||
missing module named _posixshmem - imported by multiprocessing.resource_tracker (conditional), multiprocessing.shared_memory (conditional)
|
||||
missing module named _scproxy - imported by urllib.request (conditional)
|
||||
missing module named posix - imported by posixpath (optional), shutil (conditional), importlib._bootstrap_external (conditional), pathlib._os (optional), os (conditional, optional), _pyrepl.trace (conditional)
|
||||
missing module named resource - imported by posix (top-level)
|
||||
missing module named termios - imported by tty (top-level), _pyrepl.pager (delayed, optional), getpass (optional)
|
||||
missing module named multiprocessing.BufferTooShort - imported by multiprocessing (top-level), multiprocessing.connection (top-level)
|
||||
missing module named multiprocessing.AuthenticationError - imported by multiprocessing (top-level), multiprocessing.connection (top-level)
|
||||
missing module named _frozen_importlib_external - imported by importlib._bootstrap (delayed), importlib (optional), importlib.abc (optional), zipimport (top-level)
|
||||
excluded module named _frozen_importlib - imported by importlib (optional), importlib.abc (optional), zipimport (top-level)
|
||||
missing module named multiprocessing.BufferTooShort - imported by multiprocessing (top-level), multiprocessing.connection (top-level)
|
||||
missing module named multiprocessing.AuthenticationError - imported by multiprocessing (top-level), multiprocessing.forkserver (top-level), multiprocessing.connection (top-level)
|
||||
missing module named posix - imported by os (conditional, optional), posixpath (optional), shutil (conditional), importlib._bootstrap_external (conditional)
|
||||
missing module named resource - imported by posix (top-level)
|
||||
missing module named multiprocessing.get_context - imported by multiprocessing (top-level), multiprocessing.pool (top-level), multiprocessing.managers (top-level), multiprocessing.sharedctypes (top-level)
|
||||
missing module named multiprocessing.TimeoutError - imported by multiprocessing (top-level), multiprocessing.pool (top-level)
|
||||
missing module named multiprocessing.set_start_method - imported by multiprocessing (top-level), multiprocessing.spawn (top-level)
|
||||
missing module named multiprocessing.get_start_method - imported by multiprocessing (top-level), multiprocessing.spawn (top-level)
|
||||
missing module named pyimod02_importers - imported by C:\Python314\Lib\site-packages\PyInstaller\hooks\rthooks\pyi_rth_pkgutil.py (delayed)
|
||||
missing module named pyimod02_importers - imported by C:\Users\Administrator\miniconda3\Lib\site-packages\PyInstaller\hooks\rthooks\pyi_rth_pkgutil.py (delayed)
|
||||
missing module named _dummy_thread - imported by numpy._core.arrayprint (optional)
|
||||
missing module named asyncio.DefaultEventLoopPolicy - imported by asyncio (delayed, conditional), asyncio.events (delayed, conditional)
|
||||
missing module named annotationlib - imported by typing_extensions (conditional)
|
||||
missing module named 'numpy_distutils.cpuinfo' - imported by numpy.f2py.diagnose (delayed, conditional, optional)
|
||||
missing module named 'numpy_distutils.fcompiler' - imported by numpy.f2py.diagnose (delayed, conditional, optional)
|
||||
missing module named 'numpy_distutils.command' - imported by numpy.f2py.diagnose (delayed, conditional, optional)
|
||||
missing module named numpy_distutils - imported by numpy.f2py.diagnose (delayed, optional)
|
||||
missing module named charset_normalizer - imported by numpy.f2py.crackfortran (optional)
|
||||
missing module named vms_lib - imported by platform (delayed, optional)
|
||||
missing module named 'java.lang' - imported by platform (delayed, optional)
|
||||
missing module named java - imported by platform (delayed)
|
||||
missing module named psutil - imported by numpy.testing._private.utils (delayed, optional)
|
||||
missing module named termios - imported by tty (top-level), _pyrepl.pager (delayed, optional)
|
||||
missing module named readline - imported by cmd (delayed, conditional, optional), code (delayed, conditional, optional), pdb (delayed, conditional, optional), rlcompleter (optional)
|
||||
missing module named win32pdh - imported by numpy.testing._private.utils (delayed, conditional)
|
||||
missing module named _typeshed - imported by numpy.random.bit_generator (top-level)
|
||||
missing module named numpy.random.RandomState - imported by numpy.random (top-level), numpy.random._generator (top-level)
|
||||
missing module named pyodide_js - imported by threadpoolctl (delayed, optional)
|
||||
missing module named threadpoolctl - imported by numpy.lib._utils_impl (delayed, optional)
|
||||
missing module named numpy._core.zeros - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.vstack - imported by numpy._core (top-level), numpy.lib._shape_base_impl (top-level), numpy (conditional)
|
||||
missing module named numpy._core.void - imported by numpy._core (conditional), numpy (conditional)
|
||||
@@ -84,7 +85,7 @@ missing module named numpy._core.sinh - imported by numpy._core (conditional), n
|
||||
missing module named numpy._core.single - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.signedinteger - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.signbit - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||
missing module named numpy._core.sign - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||
missing module named numpy._core.sign - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.short - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.rint - imported by numpy._core (conditional), numpy (conditional)
|
||||
missing module named numpy._core.right_shift - imported by numpy._core (conditional), numpy (conditional)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
BIN
devkit/dist/je-skin-devkit-server.exe
vendored
BIN
devkit/dist/je-skin-devkit-server.exe
vendored
Binary file not shown.
Binary file not shown.
@@ -5,8 +5,8 @@ a = Analysis(
|
||||
['sensor_server.py'],
|
||||
pathex=[],
|
||||
binaries=[],
|
||||
datas=[],
|
||||
hiddenimports=[],
|
||||
datas=[('sensor_stream_pb2*.py', '.')],
|
||||
hiddenimports=['grpc', 'openpyxl'],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -24,7 +24,7 @@ _sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x13sensor_stream.proto\x12\rsensor_stream\"\x85\x01\n\x0bSensorFrame\x12\x0b\n\x03seq\x18\x01 \x01(\x04\x12\x14\n\x0ctimestamp_ms\x18\x02 \x01(\x04\x12\x0c\n\x04rows\x18\x03 \x01(\r\x12\x0c\n\x04\x63ols\x18\x04 \x01(\r\x12\x0e\n\x06matrix\x18\x05 \x03(\r\x12\x17\n\x0fresultant_force\x18\x06 \x01(\x01\x12\x0e\n\x06\x64ts_ms\x18\x07 \x01(\r\"\xd1\x01\n\x10PztAngleResponse\x12\x0b\n\x03seq\x18\x01 \x01(\x04\x12\x14\n\x0ctimestamp_ms\x18\x02 \x01(\x04\x12\r\n\x05\x61ngle\x18\x03 \x01(\x02\x12\x0e\n\x06\x64ts_ms\x18\x04 \x01(\r\x12\n\n\x02ok\x18\x05 \x01(\x08\x12\x0f\n\x07message\x18\x06 \x01(\t\x12\x11\n\tmagnitude\x18\x07 \x01(\x02\x12\r\n\x05state\x18\x08 \x01(\r\x12\r\n\x05\x63op_x\x18\t \x01(\x02\x12\r\n\x05\x63op_y\x18\n \x01(\x02\x12\x0e\n\x06\x62\x61se_x\x18\x0b \x01(\x02\x12\x0e\n\x06\x62\x61se_y\x18\x0c \x01(\x02\"8\n\x0eProcessRequest\x12\x10\n\x08\x63sv_path\x18\x01 \x01(\t\x12\x14\n\x0csave_as_xlsx\x18\x02 \x01(\x08\"\xa6\x01\n\x0fProcessResponse\x12\n\n\x02ok\x18\x01 \x01(\x08\x12\x13\n\x0boutput_path\x18\x02 \x01(\t\x12\x13\n\x0bgroups_used\x18\x03 \x01(\r\x12\x12\n\nmean_value\x18\x04 \x01(\x01\x12\x11\n\tthreshold\x18\x05 \x01(\x01\x12\x12\n\nrows_total\x18\x06 \x01(\r\x12\x11\n\trows_kept\x18\x07 \x01(\r\x12\x0f\n\x07message\x18\x08 \x01(\t2W\n\nSensorPush\x12I\n\x06Upload\x12\x1a.sensor_stream.SensorFrame\x1a\x1f.sensor_stream.PztAngleResponse(\x01\x30\x01\x32_\n\x0f\x45xportProcessor\x12L\n\x0bProcessFile\x12\x1d.sensor_stream.ProcessRequest\x1a\x1e.sensor_stream.ProcessResponseb\x06proto3')
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x13sensor_stream.proto\x12\rsensor_stream\"\x85\x01\n\x0bSensorFrame\x12\x0b\n\x03seq\x18\x01 \x01(\x04\x12\x14\n\x0ctimestamp_ms\x18\x02 \x01(\x04\x12\x0c\n\x04rows\x18\x03 \x01(\r\x12\x0c\n\x04\x63ols\x18\x04 \x01(\r\x12\x0e\n\x06matrix\x18\x05 \x03(\r\x12\x17\n\x0fresultant_force\x18\x06 \x01(\x01\x12\x0e\n\x06\x64ts_ms\x18\x07 \x01(\r\"\xf9\x01\n\x10PztAngleResponse\x12\x0b\n\x03seq\x18\x01 \x01(\x04\x12\x14\n\x0ctimestamp_ms\x18\x02 \x01(\x04\x12\r\n\x05\x61ngle\x18\x03 \x01(\x02\x12\x0e\n\x06\x64ts_ms\x18\x04 \x01(\r\x12\n\n\x02ok\x18\x05 \x01(\x08\x12\x0f\n\x07message\x18\x06 \x01(\t\x12\x11\n\tmagnitude\x18\x07 \x01(\x02\x12\r\n\x05state\x18\x08 \x01(\x05\x12\r\n\x05\x63op_x\x18\t \x01(\x02\x12\r\n\x05\x63op_y\x18\n \x01(\x02\x12\x0e\n\x06\x62\x61se_x\x18\x0b \x01(\x02\x12\x0e\n\x06\x62\x61se_y\x18\x0c \x01(\x02\x12\x13\n\x0btotal_press\x18\r \x01(\x02\x12\x11\n\tthreshold\x18\x0e \x01(\x02\"8\n\x0eProcessRequest\x12\x10\n\x08\x63sv_path\x18\x01 \x01(\t\x12\x14\n\x0csave_as_xlsx\x18\x02 \x01(\x08\"\xa6\x01\n\x0fProcessResponse\x12\n\n\x02ok\x18\x01 \x01(\x08\x12\x13\n\x0boutput_path\x18\x02 \x01(\t\x12\x13\n\x0bgroups_used\x18\x03 \x01(\r\x12\x12\n\nmean_value\x18\x04 \x01(\x01\x12\x11\n\tthreshold\x18\x05 \x01(\x01\x12\x12\n\nrows_total\x18\x06 \x01(\r\x12\x11\n\trows_kept\x18\x07 \x01(\r\x12\x0f\n\x07message\x18\x08 \x01(\t2W\n\nSensorPush\x12I\n\x06Upload\x12\x1a.sensor_stream.SensorFrame\x1a\x1f.sensor_stream.PztAngleResponse(\x01\x30\x01\x32_\n\x0f\x45xportProcessor\x12L\n\x0bProcessFile\x12\x1d.sensor_stream.ProcessRequest\x1a\x1e.sensor_stream.ProcessResponseb\x06proto3')
|
||||
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
@@ -34,13 +34,13 @@ if not _descriptor._USE_C_DESCRIPTORS:
|
||||
_globals['_SENSORFRAME']._serialized_start=39
|
||||
_globals['_SENSORFRAME']._serialized_end=172
|
||||
_globals['_PZTANGLERESPONSE']._serialized_start=175
|
||||
_globals['_PZTANGLERESPONSE']._serialized_end=384
|
||||
_globals['_PROCESSREQUEST']._serialized_start=386
|
||||
_globals['_PROCESSREQUEST']._serialized_end=442
|
||||
_globals['_PROCESSRESPONSE']._serialized_start=445
|
||||
_globals['_PROCESSRESPONSE']._serialized_end=611
|
||||
_globals['_SENSORPUSH']._serialized_start=613
|
||||
_globals['_SENSORPUSH']._serialized_end=700
|
||||
_globals['_EXPORTPROCESSOR']._serialized_start=702
|
||||
_globals['_EXPORTPROCESSOR']._serialized_end=797
|
||||
_globals['_PZTANGLERESPONSE']._serialized_end=424
|
||||
_globals['_PROCESSREQUEST']._serialized_start=426
|
||||
_globals['_PROCESSREQUEST']._serialized_end=482
|
||||
_globals['_PROCESSRESPONSE']._serialized_start=485
|
||||
_globals['_PROCESSRESPONSE']._serialized_end=651
|
||||
_globals['_SENSORPUSH']._serialized_start=653
|
||||
_globals['_SENSORPUSH']._serialized_end=740
|
||||
_globals['_EXPORTPROCESSOR']._serialized_start=742
|
||||
_globals['_EXPORTPROCESSOR']._serialized_end=837
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
|
||||
0
devkit/server-start.err.log
Normal file
0
devkit/server-start.err.log
Normal file
33231
devkit/server-start.out.log
Normal file
33231
devkit/server-start.out.log
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,127 +0,0 @@
|
||||
"""
|
||||
独立测试脚本:读取84个原始ADC数据,传入CoP算法计算角度,终端打印结果。
|
||||
|
||||
用法:
|
||||
python test_pzt.py # 从 stdin 逐行读取(每行84个逗号分隔数值)
|
||||
python test_pzt.py data.csv # 从 CSV 文件逐行读取
|
||||
python test_pzt.py --random # 生成随机测试数据(调试用)
|
||||
"""
|
||||
|
||||
import sys
|
||||
import csv
|
||||
import numpy as np
|
||||
|
||||
# ── 从 sensor_server.py 导入算法 ──
|
||||
sys.path.insert(0, ".")
|
||||
from sensor_server import (
|
||||
get_pzt_angle,
|
||||
reset_baseline,
|
||||
subtract_baseline,
|
||||
compute_pressure_direction,
|
||||
compute_PZT_angle,
|
||||
)
|
||||
|
||||
|
||||
def print_result(data_label: str, pzt_angle: float, magnitude: float, state: int, cop_x: float, cop_y: float, base_x: float, base_y: float):
|
||||
dx = cop_x - base_x
|
||||
dy = base_y - cop_y
|
||||
print(
|
||||
f"devkit: angle={pzt_angle:.2f}, magnitude={magnitude:.4f}, state={state}, "
|
||||
f"cop_x={cop_x:.4f}, cop_y={cop_y:.4f}, dx={dx:.4f}, dy={dy:.4f}"
|
||||
)
|
||||
|
||||
|
||||
def process_values(values: list[int | float]):
|
||||
"""处理一帧84个值并打印结果"""
|
||||
if len(values) != 84:
|
||||
print(f"[ERROR] 期望84个值,实际收到 {len(values)} 个", file=sys.stderr)
|
||||
return
|
||||
|
||||
try:
|
||||
pzt_angle, magnitude, state, cop_x, cop_y, base_x, base_y = get_pzt_angle(values)
|
||||
print_result("", pzt_angle, magnitude, state, cop_x, cop_y, base_x, base_y)
|
||||
except Exception as e:
|
||||
print(f"[ERROR] 计算失败: {e}", file=sys.stderr)
|
||||
|
||||
|
||||
def run_random_test():
|
||||
"""生成随机数据测试算法"""
|
||||
reset_baseline()
|
||||
print("[TEST] 使用随机数据测试 CoP 算法")
|
||||
print("[TEST] 先用全零帧建立基线...")
|
||||
process_values([0] * 84)
|
||||
print("[TEST] 模拟右侧偏移按压...")
|
||||
# 模拟:row 5-7, col 4-6 区域有压力
|
||||
data = [0.0] * 84
|
||||
for r in range(5, 8):
|
||||
for c in range(4, 7):
|
||||
idx = r * 7 + c
|
||||
data[idx] = 100.0 + (c - 4) * 50 # 右侧更强
|
||||
process_values(data)
|
||||
print("[TEST] 模拟下方偏移按压...")
|
||||
data2 = [0.0] * 84
|
||||
for r in range(8, 11):
|
||||
for c in range(2, 5):
|
||||
idx = r * 7 + c
|
||||
data2[idx] = 150.0 + (r - 8) * 30
|
||||
process_values(data2)
|
||||
print("[TEST] 完成")
|
||||
|
||||
|
||||
def run_csv_mode(filepath: str):
|
||||
"""从 CSV 文件逐行读取并处理"""
|
||||
reset_baseline()
|
||||
print(f"[CSV] 读取文件: {filepath}")
|
||||
with open(filepath, "r", encoding="utf-8-sig", newline="") as f:
|
||||
reader = csv.reader(f)
|
||||
for i, row in enumerate(reader):
|
||||
if not row:
|
||||
continue
|
||||
# 跳过 header
|
||||
if row[0].strip() in ("seq", "timestamp_ms"):
|
||||
print(f"[CSV] 跳过 header: {row[:5]}...")
|
||||
continue
|
||||
try:
|
||||
values = [float(v) for v in row]
|
||||
if len(values) == 84:
|
||||
process_values(values)
|
||||
elif len(values) > 84:
|
||||
process_values(values[:84])
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
|
||||
def run_stdin_mode():
|
||||
"""从 stdin 逐行读取"""
|
||||
reset_baseline()
|
||||
print("[STDIN] 等待输入(每行84个逗号分隔数值,Ctrl+C 退出)...")
|
||||
try:
|
||||
for line in sys.stdin:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
try:
|
||||
values = [float(v) for v in line.split(",")]
|
||||
if len(values) >= 84:
|
||||
process_values(values[:84])
|
||||
except ValueError:
|
||||
continue
|
||||
except KeyboardInterrupt:
|
||||
print("\n[STDIN] 已退出")
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) > 1:
|
||||
arg = sys.argv[1]
|
||||
if arg == "--random":
|
||||
run_random_test()
|
||||
elif arg == "--help" or arg == "-h":
|
||||
print(__doc__)
|
||||
else:
|
||||
run_csv_mode(arg)
|
||||
else:
|
||||
run_stdin_mode()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
32
docs/CHANGELOG.md
Normal file
32
docs/CHANGELOG.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# 更新日志
|
||||
|
||||
## 2026-06-09 - 送样分支
|
||||
|
||||
分支:`sample-delivery`
|
||||
|
||||
提交:`160ff54 Prepare sample delivery UI`
|
||||
|
||||
### 显示与交互
|
||||
|
||||
- 合力曲线改为 Canvas 渲染,保留原有 HUD 风格。
|
||||
- 合力曲线 panel 宽度调整为与三维力 panel 一致。
|
||||
- 卸力后合力曲线继续接收并渲染后端 0 值数据,panel 延迟 5 秒消失。
|
||||
- 5 秒内重新施力会取消合力曲线的消失计时。
|
||||
- 三维力 panel 改为卸力后延迟 5 秒消失。
|
||||
- 三维力箭头仍然实时跟随后端数据,卸力后箭头立即消失,不冻结最后方向。
|
||||
|
||||
### 后端数据
|
||||
|
||||
|
||||
- 合力低于显示阈值时,后端不再清空 summary 数组,而是持续写入 `0.0`。
|
||||
- 压力矩阵在低于显示阈值时仍然清零。
|
||||
- 前端可以通过 summary 数组是否存在和最新值大小来判断释放状态。
|
||||
|
||||
### 显示范围
|
||||
|
||||
- 合力与压力数值显示增加最大显示值处理:超过 `25.6` 时显示为 `25.6+`。
|
||||
|
||||
### 验证
|
||||
|
||||
- `npm.cmd run check` 通过,0 errors,保留 13 个既有 warnings。
|
||||
- `cargo check` 通过。
|
||||
104
package-lock.json
generated
104
package-lock.json
generated
@@ -9,7 +9,7 @@
|
||||
"version": "0.4.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^2",
|
||||
"@tauri-apps/api": "^2.11.0",
|
||||
"@tauri-apps/plugin-opener": "^2",
|
||||
"@tauri-apps/plugin-process": "^2.3.1",
|
||||
"@tauri-apps/plugin-updater": "^2.10.1",
|
||||
@@ -19,7 +19,7 @@
|
||||
"@sveltejs/adapter-static": "^3.0.6",
|
||||
"@sveltejs/kit": "^2.9.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^5.0.0",
|
||||
"@tauri-apps/cli": "^2",
|
||||
"@tauri-apps/cli": "^2.11.2",
|
||||
"@types/three": "^0.183.1",
|
||||
"svelte": "^5.0.0",
|
||||
"svelte-check": "^4.0.0",
|
||||
@@ -1032,9 +1032,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/api": {
|
||||
"version": "2.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.10.1.tgz",
|
||||
"integrity": "sha512-hKL/jWf293UDSUN09rR69hrToyIXBb8CjGaWC7gfinvnQrBVvnLr08FeFi38gxtugAVyVcTa5/FD/Xnkb1siBw==",
|
||||
"version": "2.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.11.0.tgz",
|
||||
"integrity": "sha512-7CinYODhky9lmO23xHnUFv0Xt43fbtWMyxZcLcRBlFkcgXKuEirBvHpmtJ89YMhyeGcq20Wuc47Fa4XjyniywA==",
|
||||
"license": "Apache-2.0 OR MIT",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
@@ -1042,9 +1042,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli": {
|
||||
"version": "2.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.10.1.tgz",
|
||||
"integrity": "sha512-jQNGF/5quwORdZSSLtTluyKQ+o6SMa/AUICfhf4egCGFdMHqWssApVgYSbg+jmrZoc8e1DscNvjTnXtlHLS11g==",
|
||||
"version": "2.11.2",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.11.2.tgz",
|
||||
"integrity": "sha512-bk3HemqvGRoy+5D/dVMUQHKMYLglD0jVnMm/0iGMH6ufZ+p8r14m6BpIixwij3PBvZdvORUp1YifTD8QxVZ1Nw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0 OR MIT",
|
||||
"bin": {
|
||||
@@ -1058,23 +1058,23 @@
|
||||
"url": "https://opencollective.com/tauri"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@tauri-apps/cli-darwin-arm64": "2.10.1",
|
||||
"@tauri-apps/cli-darwin-x64": "2.10.1",
|
||||
"@tauri-apps/cli-linux-arm-gnueabihf": "2.10.1",
|
||||
"@tauri-apps/cli-linux-arm64-gnu": "2.10.1",
|
||||
"@tauri-apps/cli-linux-arm64-musl": "2.10.1",
|
||||
"@tauri-apps/cli-linux-riscv64-gnu": "2.10.1",
|
||||
"@tauri-apps/cli-linux-x64-gnu": "2.10.1",
|
||||
"@tauri-apps/cli-linux-x64-musl": "2.10.1",
|
||||
"@tauri-apps/cli-win32-arm64-msvc": "2.10.1",
|
||||
"@tauri-apps/cli-win32-ia32-msvc": "2.10.1",
|
||||
"@tauri-apps/cli-win32-x64-msvc": "2.10.1"
|
||||
"@tauri-apps/cli-darwin-arm64": "2.11.2",
|
||||
"@tauri-apps/cli-darwin-x64": "2.11.2",
|
||||
"@tauri-apps/cli-linux-arm-gnueabihf": "2.11.2",
|
||||
"@tauri-apps/cli-linux-arm64-gnu": "2.11.2",
|
||||
"@tauri-apps/cli-linux-arm64-musl": "2.11.2",
|
||||
"@tauri-apps/cli-linux-riscv64-gnu": "2.11.2",
|
||||
"@tauri-apps/cli-linux-x64-gnu": "2.11.2",
|
||||
"@tauri-apps/cli-linux-x64-musl": "2.11.2",
|
||||
"@tauri-apps/cli-win32-arm64-msvc": "2.11.2",
|
||||
"@tauri-apps/cli-win32-ia32-msvc": "2.11.2",
|
||||
"@tauri-apps/cli-win32-x64-msvc": "2.11.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-darwin-arm64": {
|
||||
"version": "2.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.10.1.tgz",
|
||||
"integrity": "sha512-Z2OjCXiZ+fbYZy7PmP3WRnOpM9+Fy+oonKDEmUE6MwN4IGaYqgceTjwHucc/kEEYZos5GICve35f7ZiizgqEnQ==",
|
||||
"version": "2.11.2",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.11.2.tgz",
|
||||
"integrity": "sha512-+4UZzLt+eOAEQCwgd+TqKgyUJMrvx+BgdXLLaqJYmPqzP+nE6YZr/hY6CWLYGQb8jFn99jEkmC6uA3tNvamA1w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1089,9 +1089,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-darwin-x64": {
|
||||
"version": "2.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.10.1.tgz",
|
||||
"integrity": "sha512-V/irQVvjPMGOTQqNj55PnQPVuH4VJP8vZCN7ajnj+ZS8Kom1tEM2hR3qbbIRoS3dBKs5mbG8yg1WC+97dq17Pw==",
|
||||
"version": "2.11.2",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.11.2.tgz",
|
||||
"integrity": "sha512-VjYYtZUPqDMLutSfJEyxFE3Bz+DPi7c8wC3imckgvciLDZLq4qwKJxBicg0BXGhXjJsl8vKWgWRFNMPELQ+Xyg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1106,9 +1106,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-linux-arm-gnueabihf": {
|
||||
"version": "2.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.10.1.tgz",
|
||||
"integrity": "sha512-Hyzwsb4VnCWKGfTw+wSt15Z2pLw2f0JdFBfq2vHBOBhvg7oi6uhKiF87hmbXOBXUZaGkyRDkCHsdzJcIfoJC2w==",
|
||||
"version": "2.11.2",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.11.2.tgz",
|
||||
"integrity": "sha512-yMemD6f4i95AQriS8EazyOFzbE34yjnP16i3IOzpHGQvBoy2DjypFMFBq0NtPuITURv/cOGguRtHR5d79/9CSA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -1123,9 +1123,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-linux-arm64-gnu": {
|
||||
"version": "2.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.10.1.tgz",
|
||||
"integrity": "sha512-OyOYs2t5GkBIvyWjA1+h4CZxTcdz1OZPCWAPz5DYEfB0cnWHERTnQ/SLayQzncrT0kwRoSfSz9KxenkyJoTelA==",
|
||||
"version": "2.11.2",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.11.2.tgz",
|
||||
"integrity": "sha512-cgI91D2wL8GSgoWwZXDqt+DwnuZCP2/bz03QAE4TrhgAKIsrB4hX26W/H1EONPUUNkqrsgeCD0wU6pcNjV/5kw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1143,9 +1143,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-linux-arm64-musl": {
|
||||
"version": "2.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.10.1.tgz",
|
||||
"integrity": "sha512-MIj78PDDGjkg3NqGptDOGgfXks7SYJwhiMh8SBoZS+vfdz7yP5jN18bNaLnDhsVIPARcAhE1TlsZe/8Yxo2zqg==",
|
||||
"version": "2.11.2",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.11.2.tgz",
|
||||
"integrity": "sha512-X1rm0BERqAAggtYTESSgXrS3sz4Sb/OiPiz54UqISlXW+GkR3vNIGnsy/lejNmoXGVqri3Q53BCfQiclOIyRPw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1163,9 +1163,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-linux-riscv64-gnu": {
|
||||
"version": "2.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.10.1.tgz",
|
||||
"integrity": "sha512-X0lvOVUg8PCVaoEtEAnpxmnkwlE1gcMDTqfhbefICKDnOTJ5Est3qL0SrWxizDackIOKBcvtpejrSiVpuJI1kw==",
|
||||
"version": "2.11.2",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.11.2.tgz",
|
||||
"integrity": "sha512-usbMLJbT3KtkOrBMDVeGYNM35aTHXx38SJSzTMSqqjeUIOQ+iVPjb2yAGNAE+KqmBbAx4FOFIyMeKXx2M/JKGQ==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@@ -1183,9 +1183,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-linux-x64-gnu": {
|
||||
"version": "2.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.10.1.tgz",
|
||||
"integrity": "sha512-2/12bEzsJS9fAKybxgicCDFxYD1WEI9kO+tlDwX5znWG2GwMBaiWcmhGlZ8fi+DMe9CXlcVarMTYc0L3REIRxw==",
|
||||
"version": "2.11.2",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.11.2.tgz",
|
||||
"integrity": "sha512-Ru4gwJKPG0ctVGchRGpRup4Y4lW2SSfFnrbQcyHhCliKy4g8Qz97TrUgCur4CbWyAgKxvGh3SjrkA0LDYzDGiw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1203,9 +1203,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-linux-x64-musl": {
|
||||
"version": "2.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.10.1.tgz",
|
||||
"integrity": "sha512-Y8J0ZzswPz50UcGOFuXGEMrxbjwKSPgXftx5qnkuMs2rmwQB5ssvLb6tn54wDSYxe7S6vlLob9vt0VKuNOaCIQ==",
|
||||
"version": "2.11.2",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.11.2.tgz",
|
||||
"integrity": "sha512-eUm7T6clN1MMmNSRQ9gaWsQdyehQx2Gmn5hht/QUlqZQI/qcP2OJK5dnaxqwFzCr2HdsEo9ydxaqcS1oJzMvUw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1223,9 +1223,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-win32-arm64-msvc": {
|
||||
"version": "2.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.10.1.tgz",
|
||||
"integrity": "sha512-iSt5B86jHYAPJa/IlYw++SXtFPGnWtFJriHn7X0NFBVunF6zu9+/zOn8OgqIWSl8RgzhLGXQEEtGBdR4wzpVgg==",
|
||||
"version": "2.11.2",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.11.2.tgz",
|
||||
"integrity": "sha512-HeeZW80jU+gVTOEX4X/hC6NVSAdDVXajwP5fxIZ/3z9WvUC7qrudX2GMTilYq6Dg0e0sk0XgsAJD1hZ5wPBXUA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1240,9 +1240,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-win32-ia32-msvc": {
|
||||
"version": "2.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.10.1.tgz",
|
||||
"integrity": "sha512-gXyxgEzsFegmnWywYU5pEBURkcFN/Oo45EAwvZrHMh+zUSEAvO5E8TXsgPADYm31d1u7OQU3O3HsYfVBf2moHw==",
|
||||
"version": "2.11.2",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.11.2.tgz",
|
||||
"integrity": "sha512-YhjQNZcXfbkCLyazSv1nPnJ9iRFE1wm6kc51FDbU10/Dk09io+6PAGMLjkxnX2GdM0qMnDmTjstY8mTDVvtKeA==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@@ -1257,9 +1257,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli-win32-x64-msvc": {
|
||||
"version": "2.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.10.1.tgz",
|
||||
"integrity": "sha512-6Cn7YpPFwzChy0ERz6djKEmUehWrYlM+xTaNzGPgZocw3BD7OfwfWHKVWxXzdjEW2KfKkHddfdxK1XXTYqBRLg==",
|
||||
"version": "2.11.2",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.11.2.tgz",
|
||||
"integrity": "sha512-d2JchlFIpZevZVReyqhQOekJmb1UH3rhZ5VX6sH3ty9ETE0TKQavpihvoScUXfKKpW6HZC0MrFGRU0ZtD+w3gA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^2",
|
||||
"@tauri-apps/api": "^2.11.0",
|
||||
"@tauri-apps/plugin-opener": "^2",
|
||||
"@tauri-apps/plugin-process": "^2.3.1",
|
||||
"@tauri-apps/plugin-updater": "^2.10.1",
|
||||
@@ -25,7 +25,7 @@
|
||||
"@sveltejs/adapter-static": "^3.0.6",
|
||||
"@sveltejs/kit": "^2.9.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^5.0.0",
|
||||
"@tauri-apps/cli": "^2",
|
||||
"@tauri-apps/cli": "^2.11.2",
|
||||
"@types/three": "^0.183.1",
|
||||
"svelte": "^5.0.0",
|
||||
"svelte-check": "^4.0.0",
|
||||
|
||||
1312
src-tauri/Cargo.lock
generated
1312
src-tauri/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -16,6 +16,7 @@ crate-type = ["staticlib", "cdylib", "rlib"]
|
||||
|
||||
[features]
|
||||
default = ["multi-dim"]
|
||||
debug = []
|
||||
devkit = ["dep:tonic", "dep:prost", "dep:prost-types", "dep:async-stream", "dep:dirs"]
|
||||
multi-dim = ["dep:ndarray"]
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ message PztAngleResponse {
|
||||
bool ok = 5;
|
||||
string message = 6;
|
||||
float magnitude = 7;
|
||||
uint32 state = 8;
|
||||
int32 state = 8;
|
||||
float cop_x = 9;
|
||||
float cop_y = 10;
|
||||
float base_x = 11;
|
||||
|
||||
Binary file not shown.
@@ -1,162 +0,0 @@
|
||||
/// AD值反解x计算器
|
||||
/// AD = -5.732*x^3 - 131.5*x^2 + 31980*x + 13490 (x <= 6.57)
|
||||
/// AD = -377.8*x^2 + 26040*x + 51120 (x > 6.57)
|
||||
|
||||
const X_BOUNDARY: f64 = 6.57;
|
||||
|
||||
/// 二次方程在边界处的AD值
|
||||
/// 当 x = 6.57 时,AD = -377.8*6.57^2 + 26040*6.57 + 51120
|
||||
const AD_BOUNDARY: f64 = 205895.10;
|
||||
|
||||
/// 二次方程求解器
|
||||
/// -377.8*x^2 + 26040*x + 51120 = ad
|
||||
/// 返回 x > 6.57 的那个解
|
||||
fn solve_quadratic(ad: f64) -> Option<f64> {
|
||||
let a = -377.8;
|
||||
let b = 26040.0;
|
||||
let c = 51120.0 - ad;
|
||||
|
||||
let discriminant = b * b - 4.0 * a * c;
|
||||
if discriminant < 0.0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let sqrt_d = discriminant.sqrt();
|
||||
let x1 = (-b + sqrt_d) / (2.0 * a);
|
||||
let x2 = (-b - sqrt_d) / (2.0 * a);
|
||||
|
||||
// 选择 x > 6.57 的解(只可能有一个解满足这个条件)
|
||||
if x1 > X_BOUNDARY && x1 > 0.0 {
|
||||
Some(x1)
|
||||
} else if x2 > X_BOUNDARY && x2 > 0.0 {
|
||||
Some(x2)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// 计算三次多项式的值
|
||||
/// f(x) = -5.732*x^3 - 131.5*x^2 + 31980*x + 13490
|
||||
fn cubic_value(x: f64) -> f64 {
|
||||
-5.732 * x.powi(3) - 131.5 * x.powi(2) + 31980.0 * x + 13490.0
|
||||
}
|
||||
|
||||
/// 使用二分法求解三次方程 (x <= 6.57)
|
||||
/// 三次方程在 [0, 6.57] 范围内是单调递增的
|
||||
fn solve_cubic_bisection(ad: f64) -> Option<f64> {
|
||||
let mut low = 0.0;
|
||||
let mut high = X_BOUNDARY;
|
||||
|
||||
let target = ad;
|
||||
|
||||
// 检查目标是否在范围内
|
||||
let low_ad = cubic_value(low);
|
||||
let high_ad = cubic_value(high);
|
||||
|
||||
if target < low_ad.min(high_ad) || target > low_ad.max(high_ad) {
|
||||
return None;
|
||||
}
|
||||
|
||||
for _i in 0..100 {
|
||||
let mid = (low + high) / 2.0;
|
||||
let mid_ad = cubic_value(mid);
|
||||
|
||||
if (high - low).abs() < 1e-10 {
|
||||
return Some((low + high) / 2.0);
|
||||
}
|
||||
|
||||
if mid_ad > target {
|
||||
high = mid;
|
||||
} else {
|
||||
low = mid;
|
||||
}
|
||||
}
|
||||
|
||||
Some((low + high) / 2.0)
|
||||
}
|
||||
|
||||
/// 主求解函数:根据AD值反解x
|
||||
pub fn solve_for_x(ad: f64) -> Option<f64> {
|
||||
// 如果 AD <= 边界值,使用三次方程 (x <= 6.57)
|
||||
// 如果 AD > 边界值,使用二次方程 (x > 6.57)
|
||||
if ad <= AD_BOUNDARY {
|
||||
return solve_cubic_bisection(ad);
|
||||
}
|
||||
|
||||
// AD > 边界值,使用二次方程
|
||||
solve_quadratic(ad)
|
||||
}
|
||||
|
||||
/// 批量求解,用于验证所有解
|
||||
pub fn solve_for_x_all(ad: f64) -> Vec<f64> {
|
||||
let mut results = Vec::new();
|
||||
|
||||
// 三次方程解
|
||||
if let Some(x) = solve_cubic_bisection(ad) {
|
||||
results.push(x);
|
||||
}
|
||||
|
||||
// 二次方程解
|
||||
if let Some(x) = solve_quadratic(ad) {
|
||||
results.push(x);
|
||||
}
|
||||
|
||||
results
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_cubic_forward() {
|
||||
// 测试 x <= 6.57 的正向计算
|
||||
let x = 5.0;
|
||||
let ad = cubic_value(x);
|
||||
println!("x={}, ad={}", x, ad);
|
||||
let solved = solve_for_x(ad).unwrap();
|
||||
println!("solved={}", solved);
|
||||
assert!((solved - x).abs() < 0.01, "x={}, solved={}", x, solved);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_quadratic_forward() {
|
||||
// 测试 x > 6.57 的正向计算
|
||||
let x = 10.0;
|
||||
let ad = -377.8 * x * x + 26040.0 * x + 51120.0;
|
||||
let solved = solve_for_x(ad).unwrap();
|
||||
assert!((solved - x).abs() < 0.01, "x={}, solved={}", x, solved);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_boundary() {
|
||||
// 测试边界值
|
||||
let x = 6.57;
|
||||
let ad_cubic = cubic_value(x);
|
||||
let ad_quad = -377.8 * x * x + 26040.0 * x + 51120.0;
|
||||
|
||||
println!("x=6.57 时三次方程 AD = {:.2}", ad_cubic);
|
||||
println!("x=6.57 时二次方程 AD = {:.2}", ad_quad);
|
||||
println!("边界值 AD_BOUNDARY = {:.2}", AD_BOUNDARY);
|
||||
|
||||
// 边界处两个公式应该有显著差异
|
||||
assert!((ad_cubic - ad_quad).abs() > 100.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_known_values() {
|
||||
// 测试一些已知值
|
||||
let test_cases = [
|
||||
(0.0, cubic_value(0.0)),
|
||||
(3.0, cubic_value(3.0)),
|
||||
(6.0, cubic_value(6.0)),
|
||||
(8.0, -377.8 * 8.0 * 8.0 + 26040.0 * 8.0 + 51120.0),
|
||||
(15.0, -377.8 * 15.0 * 15.0 + 26040.0 * 15.0 + 51120.0),
|
||||
];
|
||||
|
||||
for (x, ad) in test_cases {
|
||||
let solved = solve_for_x(ad).unwrap();
|
||||
assert!((solved - x).abs() < 0.01, "x={}, ad={}, solved={}", x, ad, solved);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,26 @@
|
||||
//!
|
||||
//! 仅在 `devkit` feature 启用时编译。
|
||||
|
||||
use serde::Serialize;
|
||||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use tauri::State;
|
||||
#[cfg(feature = "devkit")]
|
||||
use tauri::AppHandle;
|
||||
|
||||
use crate::devkit::{DevKitConfig, DevKitState, DevKitStatusSnapshot, ExportProcessResult};
|
||||
use crate::devkit::{
|
||||
proto::SensorFrame, DevKitConfig, DevKitState, DevKitStatusSnapshot, ExportProcessResult,
|
||||
};
|
||||
|
||||
static REPLAY_SEQ_COUNTER: AtomicU64 = AtomicU64::new(0);
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DevKitReplayFramePushResult {
|
||||
pub seq: u64,
|
||||
pub timestamp_ms: u64,
|
||||
pub dts_ms: u32,
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn devkit_status(state: State<'_, DevKitState>) -> DevKitStatusSnapshot {
|
||||
@@ -51,3 +66,55 @@ pub async fn devkit_process_export(
|
||||
let use_xlsx = save_as_xlsx.unwrap_or(config.save_as_xlsx);
|
||||
state.process_export(&csv_path, use_xlsx).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn devkit_push_replay_frame(
|
||||
state: State<'_, DevKitState>,
|
||||
values: Vec<i32>,
|
||||
dts_ms: u32,
|
||||
seq: Option<u64>,
|
||||
) -> Result<DevKitReplayFramePushResult, String> {
|
||||
if values.len() != 84 {
|
||||
return Err(format!("InvalidReplayMatrixLength: {}", values.len()));
|
||||
}
|
||||
|
||||
if !state.running.load(Ordering::Relaxed) {
|
||||
return Err("NotRunning".to_string());
|
||||
}
|
||||
|
||||
let timestamp_ms = now_millis();
|
||||
let seq = seq.unwrap_or_else(|| build_replay_seq(timestamp_ms));
|
||||
let resultant_force = values.iter().copied().sum::<i32>().max(0) as f64;
|
||||
let matrix = values
|
||||
.into_iter()
|
||||
.map(|value| value.max(0) as u32)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
state.push_frame(SensorFrame {
|
||||
seq,
|
||||
timestamp_ms,
|
||||
rows: 12,
|
||||
cols: 7,
|
||||
matrix,
|
||||
resultant_force,
|
||||
dts_ms,
|
||||
});
|
||||
|
||||
Ok(DevKitReplayFramePushResult {
|
||||
seq,
|
||||
timestamp_ms,
|
||||
dts_ms,
|
||||
})
|
||||
}
|
||||
|
||||
fn now_millis() -> u64 {
|
||||
SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.map(|duration| duration.as_millis() as u64)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn build_replay_seq(timestamp_ms: u64) -> u64 {
|
||||
let counter = REPLAY_SEQ_COUNTER.fetch_add(1, Ordering::Relaxed) % 1000;
|
||||
timestamp_ms.saturating_mul(1000).saturating_add(counter)
|
||||
}
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
use crate::serial_core::codecs::hand_gateway::HandGatewayCodec;
|
||||
use crate::serial_core::codecs::tactile_a::{
|
||||
export_recording_csv, TactileACodec, TactileACsvImporter, TactileAHandler,
|
||||
export_recording_csv, TactileACodec, TactileACsvImporter, TactileADataPacket, TactileAHandler,
|
||||
};
|
||||
use crate::serial_core::error::SerialError;
|
||||
use crate::serial_core::model::HudSpatialForce;
|
||||
#[cfg(feature = "multi-dim")]
|
||||
use crate::serial_core::multi_dim_force::PztProcessor;
|
||||
use crate::serial_core::record::CsvImporter;
|
||||
use crate::serial_core::serial::{PollMode, TactileAPollRequester};
|
||||
use crate::serial_core::{serial, TactileARecording};
|
||||
use log::info;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::Serialize;
|
||||
use std::fs::File;
|
||||
use std::io::Cursor;
|
||||
use std::path::{Path, PathBuf};
|
||||
@@ -22,10 +24,6 @@ const DEFAULT_TACTILE_ROWS: usize = 12;
|
||||
const DEFAULT_TACTILE_POLL_INTERVAL_MS: u64 = 10;
|
||||
const DEFAULT_TACTILE_REPLY_TIMEOUT_MS: u64 = 140;
|
||||
|
||||
// MCU currently uses a fixed node layout. Update this list to match the firmware:
|
||||
// one entry per Config bit, containing that node's number of u16 samples.
|
||||
const DEFAULT_HAND_GATEWAY_NODE_SAMPLE_COUNTS: &[u16] = &[84];
|
||||
|
||||
type SharedTactileRecording = Arc<Mutex<TactileARecording>>;
|
||||
|
||||
#[derive(Serialize)]
|
||||
@@ -36,13 +34,6 @@ pub struct SerialConnectResponse {
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum SerialProtocol {
|
||||
TactileA,
|
||||
HandGateway,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SerialExportResponse {
|
||||
@@ -56,6 +47,7 @@ pub struct SerialExportResponse {
|
||||
pub struct SerialImportFrame {
|
||||
pub data: Vec<i32>,
|
||||
pub dts_ms: u64,
|
||||
pub spatial_force: Option<HudSpatialForce>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
@@ -79,7 +71,7 @@ struct SerialSession {
|
||||
port: String,
|
||||
cancel: CancellationToken,
|
||||
task: JoinHandle<()>,
|
||||
current_record: Option<SharedTactileRecording>,
|
||||
current_record: SharedTactileRecording,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
@@ -90,7 +82,7 @@ pub struct SerialConnectionState {
|
||||
|
||||
pub async fn shutdown_active_session(
|
||||
state: &SerialConnectionState,
|
||||
) -> Result<Option<(String, Option<SharedTactileRecording>)>, SerialError> {
|
||||
) -> Result<Option<(String, SharedTactileRecording)>, SerialError> {
|
||||
let session = {
|
||||
let mut guard = state.session.lock().map_err(|_| SerialError::StateError)?;
|
||||
guard.take()
|
||||
@@ -110,15 +102,13 @@ pub async fn shutdown_active_session(
|
||||
let _ = task.await;
|
||||
|
||||
let frame_count = current_record
|
||||
.as_ref()
|
||||
.and_then(|record| record.lock().ok().map(|record| record.frames.len()))
|
||||
.lock()
|
||||
.map(|record| record.frames.len())
|
||||
.unwrap_or(0);
|
||||
|
||||
info!("last_record has {} frames", frame_count);
|
||||
|
||||
if let (Some(current_record), Ok(mut last_record)) =
|
||||
(current_record.as_ref(), state.last_record.lock())
|
||||
{
|
||||
if let Ok(mut last_record) = state.last_record.lock() {
|
||||
*last_record = Some(current_record.clone());
|
||||
}
|
||||
|
||||
@@ -132,8 +122,7 @@ pub fn serial_enum() -> Result<Vec<String>, SerialError> {
|
||||
.into_iter()
|
||||
.filter_map(|p| {
|
||||
let name = p.port_name;
|
||||
#[cfg(unix)]
|
||||
if !name.contains("USB") {
|
||||
if !should_include_serial_port(&name) {
|
||||
return None;
|
||||
}
|
||||
Some(name)
|
||||
@@ -143,11 +132,25 @@ pub fn serial_enum() -> Result<Vec<String>, SerialError> {
|
||||
Ok(ports)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn should_include_serial_port(name: &str) -> bool {
|
||||
name.to_ascii_lowercase().contains("usb")
|
||||
}
|
||||
|
||||
#[cfg(all(unix, not(target_os = "macos")))]
|
||||
fn should_include_serial_port(name: &str) -> bool {
|
||||
name.contains("USB")
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
fn should_include_serial_port(_name: &str) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn serial_connect(
|
||||
app: AppHandle,
|
||||
port: String,
|
||||
protocol: SerialProtocol,
|
||||
state: State<'_, SerialConnectionState>,
|
||||
) -> Result<SerialConnectResponse, SerialError> {
|
||||
let port_name = port.trim().to_string();
|
||||
@@ -163,10 +166,7 @@ pub async fn serial_connect(
|
||||
}
|
||||
|
||||
let cancel = CancellationToken::new();
|
||||
let current_record = match protocol {
|
||||
SerialProtocol::TactileA => Some(Arc::new(Mutex::new(TactileARecording::new()))),
|
||||
SerialProtocol::HandGateway => None,
|
||||
};
|
||||
let current_record = Arc::new(Mutex::new(TactileARecording::new()));
|
||||
let task_record = current_record.clone();
|
||||
let task_cancel = cancel.clone();
|
||||
let task_app = app.clone();
|
||||
@@ -178,51 +178,32 @@ pub async fn serial_connect(
|
||||
let session_started_at = Instant::now();
|
||||
|
||||
let task = tauri::async_runtime::spawn(async move {
|
||||
let run_result = match protocol {
|
||||
SerialProtocol::TactileA => {
|
||||
let codec = TactileACodec::new(DEFAULT_TACTILE_COLS, DEFAULT_TACTILE_ROWS);
|
||||
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),
|
||||
)));
|
||||
let codec = TactileACodec::new(DEFAULT_TACTILE_COLS, DEFAULT_TACTILE_ROWS);
|
||||
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),
|
||||
)));
|
||||
|
||||
serial::run_serial_with_poll(
|
||||
task_app.clone(),
|
||||
port,
|
||||
codec,
|
||||
handler,
|
||||
session_started_at,
|
||||
task_record
|
||||
.clone()
|
||||
.expect("tactile protocol must have a recording"),
|
||||
task_cancel,
|
||||
poll_mode,
|
||||
)
|
||||
.await
|
||||
}
|
||||
SerialProtocol::HandGateway => {
|
||||
let codec = HandGatewayCodec::new(DEFAULT_HAND_GATEWAY_NODE_SAMPLE_COUNTS);
|
||||
serial::run_hand_gateway_serial(
|
||||
task_app.clone(),
|
||||
port,
|
||||
codec,
|
||||
session_started_at,
|
||||
task_cancel,
|
||||
)
|
||||
.await
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(error) = run_result {
|
||||
eprintln!("serial task exited with error: {error}");
|
||||
if let Err(error) = serial::run_serial_with_poll(
|
||||
task_app.clone(),
|
||||
port,
|
||||
codec,
|
||||
handler,
|
||||
session_started_at,
|
||||
task_record.clone(),
|
||||
task_cancel,
|
||||
poll_mode,
|
||||
)
|
||||
.await
|
||||
{
|
||||
log::error!("serial task exited with error: {error}");
|
||||
}
|
||||
|
||||
let manager = task_app.state::<SerialConnectionState>();
|
||||
if let (Some(task_record), Ok(mut last_record)) = (task_record, manager.last_record.lock())
|
||||
{
|
||||
if let Ok(mut last_record) = manager.last_record.lock() {
|
||||
*last_record = Some(task_record);
|
||||
}
|
||||
|
||||
@@ -359,13 +340,7 @@ pub fn serial_import_csv(
|
||||
|
||||
let channel_count = packets.first().map(|item| item.data.len()).unwrap_or(0);
|
||||
let frame_count = packets.len();
|
||||
let frames = packets
|
||||
.into_iter()
|
||||
.map(|packet| SerialImportFrame {
|
||||
data: packet.data,
|
||||
dts_ms: packet.dts_ms,
|
||||
})
|
||||
.collect();
|
||||
let frames = build_import_frames(packets);
|
||||
|
||||
Ok(SerialImportResponse {
|
||||
file_name,
|
||||
@@ -390,6 +365,44 @@ pub fn serial_import_csv_from_path(file_path: String) -> Result<SerialImportResp
|
||||
serial_import_csv(file_name, csv_content)
|
||||
}
|
||||
|
||||
fn build_import_frames(packets: Vec<TactileADataPacket>) -> Vec<SerialImportFrame> {
|
||||
#[cfg(feature = "multi-dim")]
|
||||
let mut pzt_processor = PztProcessor::new();
|
||||
|
||||
packets
|
||||
.into_iter()
|
||||
.map(|packet| {
|
||||
#[cfg(feature = "multi-dim")]
|
||||
let spatial_force = replay_spatial_force(&mut pzt_processor, &packet.data);
|
||||
|
||||
#[cfg(not(feature = "multi-dim"))]
|
||||
let spatial_force = None;
|
||||
|
||||
SerialImportFrame {
|
||||
data: packet.data,
|
||||
dts_ms: packet.dts_ms,
|
||||
spatial_force,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[cfg(feature = "multi-dim")]
|
||||
fn replay_spatial_force(processor: &mut PztProcessor, values: &[i32]) -> Option<HudSpatialForce> {
|
||||
let pzt_values = values.iter().map(|value| *value as f32).collect::<Vec<f32>>();
|
||||
let analysis = processor.get_pzt_analysis(&pzt_values).ok()?;
|
||||
|
||||
if !PztProcessor::should_report(&analysis) {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(HudSpatialForce {
|
||||
angle_deg: analysis.angle_deg,
|
||||
magnitude: analysis.magnitude,
|
||||
confidence: analysis.confidence,
|
||||
})
|
||||
}
|
||||
|
||||
fn resolve_record_for_export(
|
||||
state: &State<'_, SerialConnectionState>,
|
||||
) -> Result<SharedTactileRecording, SerialError> {
|
||||
@@ -397,7 +410,7 @@ fn resolve_record_for_export(
|
||||
let session = state.session.lock().map_err(|_| SerialError::StateError)?;
|
||||
session
|
||||
.as_ref()
|
||||
.and_then(|current_session| current_session.current_record.clone())
|
||||
.map(|current_session| current_session.current_record.clone())
|
||||
};
|
||||
|
||||
if let Some(recording) = current_record {
|
||||
@@ -418,7 +431,7 @@ fn snapshot_record_frame_count(
|
||||
let session = state.session.lock().map_err(|_| SerialError::StateError)?;
|
||||
session
|
||||
.as_ref()
|
||||
.and_then(|current_session| current_session.current_record.clone())
|
||||
.map(|current_session| current_session.current_record.clone())
|
||||
};
|
||||
|
||||
if let Some(record) = current_record {
|
||||
|
||||
@@ -35,6 +35,6 @@ pub async fn win_close(
|
||||
.await
|
||||
.map_err(|error| error.to_string())?;
|
||||
|
||||
app.exit(0);
|
||||
Ok(())
|
||||
main_window(&app)?.close().map_err(|error| error.to_string())
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,14 @@ struct DevKitPztAngleEvent {
|
||||
timestamp_ms: u64,
|
||||
dts_ms: u32,
|
||||
angle: f32,
|
||||
magnitude: f32,
|
||||
state: i32,
|
||||
cop_x: f32,
|
||||
cop_y: f32,
|
||||
base_x: f32,
|
||||
base_y: f32,
|
||||
total_press: f32,
|
||||
threshold: f32,
|
||||
}
|
||||
|
||||
// ── DevKit 配置 ────────────────────────────────────────────────────
|
||||
@@ -276,9 +284,19 @@ async fn run_grpc_upload(
|
||||
timestamp_ms: message.timestamp_ms,
|
||||
dts_ms: message.dts_ms,
|
||||
angle: message.angle,
|
||||
magnitude: message.magnitude,
|
||||
state: message.state,
|
||||
cop_x: message.cop_x,
|
||||
cop_y: message.cop_y,
|
||||
base_x: message.base_x,
|
||||
base_y: message.base_y,
|
||||
total_press: message.total_press,
|
||||
threshold: message.threshold,
|
||||
};
|
||||
::log::debug!(
|
||||
"devkit: angle={:.2}, magnitude={:.4}, state={}, cop_x={:.4}, cop_y={:.4}, base_x={:.4}, base_y={:.4}, total_press={:.2}, thresh={:.2}",
|
||||
"python pzt angle: seq={} dts_ms={} angle={:.2} magnitude={:.2} state={} cop=({:.2},{:.2}) base=({:.2},{:.2}) total_press={:.2} threshold={:.2}",
|
||||
message.seq,
|
||||
message.dts_ms,
|
||||
message.angle,
|
||||
message.magnitude,
|
||||
message.state,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
pub mod ad_solver;
|
||||
mod commands;
|
||||
mod lan_game;
|
||||
pub mod log;
|
||||
@@ -155,7 +154,8 @@ pub fn run() {
|
||||
commands::devkit::devkit_stop,
|
||||
commands::devkit::devkit_get_config,
|
||||
commands::devkit::devkit_set_config,
|
||||
commands::devkit::devkit_process_export
|
||||
commands::devkit::devkit_process_export,
|
||||
commands::devkit::devkit_push_replay_frame
|
||||
]);
|
||||
|
||||
#[cfg(not(feature = "devkit"))]
|
||||
|
||||
@@ -3,7 +3,7 @@ use fern::{
|
||||
Dispatch,
|
||||
};
|
||||
use log::debug;
|
||||
use std::{path::{Path, PathBuf}, time::SystemTime};
|
||||
use std::{path::PathBuf, time::SystemTime};
|
||||
|
||||
fn log_directory() -> PathBuf {
|
||||
let base_dir = std::env::var_os("LOCALAPPDATA")
|
||||
@@ -67,6 +67,7 @@ pub fn setup_logger() {
|
||||
|
||||
Dispatch::new()
|
||||
.level(log::LevelFilter::Debug)
|
||||
.level_for("h2", log::LevelFilter::Info)
|
||||
.chain(console_config)
|
||||
.chain(file_config)
|
||||
.apply()
|
||||
|
||||
@@ -1,390 +0,0 @@
|
||||
use crate::serial_core::codec::Codec;
|
||||
use crate::serial_core::error::CodecError;
|
||||
use crate::serial_core::frame::{
|
||||
HandGatewayDataRepFrame, HandGatewayFrame, HandGatewayFrameMetaData, HandGatewayFrameNode,
|
||||
};
|
||||
use crate::serial_core::utils::{calc_crc8_itu, elapsed_millis};
|
||||
use log::debug;
|
||||
use std::time::Instant;
|
||||
|
||||
const FRAME_HEADER: [u8; 2] = [0x55, 0xAA];
|
||||
const RESPONSE_DATA_CMD: u8 = 0x81;
|
||||
const RESPONSE_DATA_FIXED_LENGTH: usize = 16;
|
||||
const RESPONSE_DATA_PREFIX_LENGTH: usize = 19;
|
||||
const MIN_FRAME_LENGTH: usize = 7;
|
||||
const DEFAULT_MAX_FRAME_LENGTH: usize = 64 * 1024;
|
||||
|
||||
/// Describes one fixed MCU data block.
|
||||
///
|
||||
/// `config_mask` identifies the bit associated with this block in the protocol's
|
||||
/// Config/ValidConfig fields. `sample_count` is the number of little-endian u16
|
||||
/// samples in the block.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct HandGatewayNodeConfig {
|
||||
pub config_mask: u32,
|
||||
pub sample_count: usize,
|
||||
}
|
||||
|
||||
impl HandGatewayNodeConfig {
|
||||
pub const fn new(config_mask: u32, sample_count: usize) -> Self {
|
||||
Self {
|
||||
config_mask,
|
||||
sample_count,
|
||||
}
|
||||
}
|
||||
|
||||
fn payload_len(&self, bytes_per_sample: usize) -> Option<usize> {
|
||||
self.sample_count.checked_mul(bytes_per_sample)
|
||||
}
|
||||
}
|
||||
|
||||
/// Host-side description of the configuration currently hard-coded in the MCU.
|
||||
///
|
||||
/// Keep the node order identical to the MCU Config bit order. When the MCU gains
|
||||
/// GET_CONFIG support, construct this value from that response instead of changing
|
||||
/// the decoder.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct HandGatewayConfig {
|
||||
pub protocol_version: u8,
|
||||
pub bytes_per_sample: usize,
|
||||
pub max_frame_length: usize,
|
||||
pub nodes: Vec<HandGatewayNodeConfig>,
|
||||
}
|
||||
|
||||
impl HandGatewayConfig {
|
||||
pub fn new(nodes: Vec<HandGatewayNodeConfig>) -> Self {
|
||||
Self {
|
||||
protocol_version: 0x01,
|
||||
bytes_per_sample: 2,
|
||||
max_frame_length: DEFAULT_MAX_FRAME_LENGTH,
|
||||
nodes,
|
||||
}
|
||||
}
|
||||
|
||||
fn validate(&self) -> Result<(), CodecError> {
|
||||
if self.bytes_per_sample == 0 || self.max_frame_length < MIN_FRAME_LENGTH {
|
||||
return Err(CodecError::InvalidLength);
|
||||
}
|
||||
|
||||
let mut used_masks = 0u32;
|
||||
for node in &self.nodes {
|
||||
if node.config_mask == 0
|
||||
|| node.config_mask.count_ones() != 1
|
||||
|| used_masks & node.config_mask != 0
|
||||
|| node.payload_len(self.bytes_per_sample).is_none()
|
||||
{
|
||||
return Err(CodecError::InvalidLength);
|
||||
}
|
||||
used_masks |= node.config_mask;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct HandGatewayCodec {
|
||||
buffer: Vec<u8>,
|
||||
config: HandGatewayConfig,
|
||||
}
|
||||
|
||||
impl HandGatewayCodec {
|
||||
/// Convenience constructor for sequential Config bits (bit 0, bit 1, ...).
|
||||
/// Each entry is the u16 sample count of one MCU node.
|
||||
pub fn new(node_sample_counts: &[u16]) -> Self {
|
||||
let nodes = node_sample_counts
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, &sample_count)| {
|
||||
let config_mask = 1u32.checked_shl(index as u32).unwrap_or(0);
|
||||
HandGatewayNodeConfig::new(config_mask, usize::from(sample_count))
|
||||
})
|
||||
.collect();
|
||||
|
||||
Self {
|
||||
buffer: Vec::new(),
|
||||
config: HandGatewayConfig::new(nodes),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_config(config: HandGatewayConfig) -> Result<Self, CodecError> {
|
||||
config.validate()?;
|
||||
Ok(Self {
|
||||
buffer: Vec::new(),
|
||||
config,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn config(&self) -> &HandGatewayConfig {
|
||||
&self.config
|
||||
}
|
||||
|
||||
pub fn parse_node_payload(data: &[u8]) -> Result<Vec<u16>, CodecError> {
|
||||
if data.len() % 2 != 0 {
|
||||
return Err(CodecError::InvalidLength);
|
||||
}
|
||||
|
||||
Ok(data
|
||||
.chunks_exact(2)
|
||||
.map(|chunk| u16::from_le_bytes([chunk[0], chunk[1]]))
|
||||
.collect())
|
||||
}
|
||||
|
||||
fn retain_possible_header_prefix(&mut self) {
|
||||
if self.buffer.last() == Some(&FRAME_HEADER[0]) {
|
||||
self.buffer.drain(..self.buffer.len() - 1);
|
||||
} else {
|
||||
self.buffer.clear();
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_data_response(
|
||||
&self,
|
||||
frame: &[u8],
|
||||
length: u16,
|
||||
session_started_at: Instant,
|
||||
) -> Result<HandGatewayFrame, CodecError> {
|
||||
let payload_len = usize::from(length)
|
||||
.checked_sub(RESPONSE_DATA_FIXED_LENGTH)
|
||||
.ok_or(CodecError::InvalidLength)?;
|
||||
let payload_end = RESPONSE_DATA_PREFIX_LENGTH
|
||||
.checked_add(payload_len)
|
||||
.ok_or(CodecError::PayloadTooLarge)?;
|
||||
|
||||
if payload_end + 1 != frame.len() {
|
||||
return Err(CodecError::InvalidLength);
|
||||
}
|
||||
|
||||
let version = frame[5];
|
||||
if version != self.config.protocol_version {
|
||||
return Err(CodecError::InvalidFrameType);
|
||||
}
|
||||
|
||||
let timestamp = u32::from_le_bytes(frame[6..10].try_into().unwrap());
|
||||
let config = u32::from_le_bytes(frame[10..14].try_into().unwrap());
|
||||
let valid_config = u32::from_le_bytes(frame[14..18].try_into().unwrap());
|
||||
let block_count = frame[18];
|
||||
|
||||
let active_nodes: Vec<&HandGatewayNodeConfig> = self
|
||||
.config
|
||||
.nodes
|
||||
.iter()
|
||||
.filter(|node| config & node.config_mask != 0)
|
||||
.collect();
|
||||
|
||||
if active_nodes.len() != usize::from(block_count) {
|
||||
return Err(CodecError::InvalidLength);
|
||||
}
|
||||
|
||||
let expected_payload_len = active_nodes.iter().try_fold(0usize, |total, node| {
|
||||
let node_len = node
|
||||
.payload_len(self.config.bytes_per_sample)
|
||||
.ok_or(CodecError::PayloadTooLarge)?;
|
||||
total
|
||||
.checked_add(node_len)
|
||||
.ok_or(CodecError::PayloadTooLarge)
|
||||
})?;
|
||||
|
||||
if expected_payload_len != payload_len {
|
||||
return Err(CodecError::InvalidLength);
|
||||
}
|
||||
|
||||
let mut cursor = RESPONSE_DATA_PREFIX_LENGTH;
|
||||
let mut nodes = Vec::with_capacity(active_nodes.len());
|
||||
for node in active_nodes {
|
||||
let node_len = node
|
||||
.payload_len(self.config.bytes_per_sample)
|
||||
.ok_or(CodecError::PayloadTooLarge)?;
|
||||
let next = cursor + node_len;
|
||||
nodes.push(HandGatewayFrameNode {
|
||||
config_mask: node.config_mask,
|
||||
valid: valid_config & node.config_mask != 0,
|
||||
payload: frame[cursor..next].to_vec(),
|
||||
});
|
||||
cursor = next;
|
||||
}
|
||||
|
||||
Ok(HandGatewayFrame::DataRep(HandGatewayDataRepFrame {
|
||||
meta: HandGatewayFrameMetaData {
|
||||
header: FRAME_HEADER,
|
||||
length,
|
||||
cmd: RESPONSE_DATA_CMD,
|
||||
version,
|
||||
checksum: frame[frame.len() - 1],
|
||||
},
|
||||
timestamp,
|
||||
config,
|
||||
valid_config,
|
||||
block_count,
|
||||
nodes,
|
||||
dts_ms: elapsed_millis(session_started_at),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl Codec<HandGatewayFrame> for HandGatewayCodec {
|
||||
fn decode(
|
||||
&mut self,
|
||||
input: &[u8],
|
||||
session_started_at: Instant,
|
||||
) -> Result<Vec<HandGatewayFrame>, CodecError> {
|
||||
self.config.validate()?;
|
||||
self.buffer.extend_from_slice(input);
|
||||
let mut frames = Vec::new();
|
||||
|
||||
loop {
|
||||
let Some(header_pos) = self
|
||||
.buffer
|
||||
.windows(FRAME_HEADER.len())
|
||||
.position(|window| window == FRAME_HEADER)
|
||||
else {
|
||||
self.retain_possible_header_prefix();
|
||||
break;
|
||||
};
|
||||
|
||||
if header_pos > 0 {
|
||||
self.buffer.drain(..header_pos);
|
||||
}
|
||||
|
||||
if self.buffer.len() < 4 {
|
||||
break;
|
||||
}
|
||||
|
||||
let length = u16::from_le_bytes([self.buffer[2], self.buffer[3]]);
|
||||
let frame_len = usize::from(length)
|
||||
.checked_add(4)
|
||||
.ok_or(CodecError::PayloadTooLarge)?;
|
||||
|
||||
if frame_len < MIN_FRAME_LENGTH || frame_len > self.config.max_frame_length {
|
||||
debug!("invalid hand gateway frame length: {frame_len}");
|
||||
self.buffer.drain(..1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if self.buffer.len() < frame_len {
|
||||
break;
|
||||
}
|
||||
|
||||
let expected_checksum = calc_crc8_itu(&self.buffer[..frame_len - 1]);
|
||||
let received_checksum = self.buffer[frame_len - 1];
|
||||
if expected_checksum != received_checksum {
|
||||
debug!(
|
||||
"hand gateway checksum mismatch: expected {expected_checksum:02X}, got {received_checksum:02X}"
|
||||
);
|
||||
self.buffer.drain(..1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if self.buffer[4] == RESPONSE_DATA_CMD {
|
||||
match self.parse_data_response(
|
||||
&self.buffer[..frame_len],
|
||||
length,
|
||||
session_started_at,
|
||||
) {
|
||||
Ok(frame) => frames.push(frame),
|
||||
Err(error) => debug!("invalid hand gateway data response: {error}"),
|
||||
}
|
||||
}
|
||||
|
||||
self.buffer.drain(..frame_len);
|
||||
}
|
||||
|
||||
Ok(frames)
|
||||
}
|
||||
|
||||
fn encode(&self, _frame: &HandGatewayFrame) -> Result<Vec<u8>, CodecError> {
|
||||
Err(CodecError::InvalidFrameType)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn test_codec() -> HandGatewayCodec {
|
||||
HandGatewayCodec::with_config(HandGatewayConfig::new(vec![
|
||||
HandGatewayNodeConfig::new(1 << 0, 2),
|
||||
HandGatewayNodeConfig::new(1 << 1, 1),
|
||||
]))
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn data_response(config: u32, valid_config: u32, payload: &[u8]) -> Vec<u8> {
|
||||
let block_count = config.count_ones() as u8;
|
||||
let length = (RESPONSE_DATA_FIXED_LENGTH + payload.len()) as u16;
|
||||
let mut frame = Vec::new();
|
||||
frame.extend_from_slice(&FRAME_HEADER);
|
||||
frame.extend_from_slice(&length.to_le_bytes());
|
||||
frame.push(RESPONSE_DATA_CMD);
|
||||
frame.push(0x01);
|
||||
frame.extend_from_slice(&123_456u32.to_le_bytes());
|
||||
frame.extend_from_slice(&config.to_le_bytes());
|
||||
frame.extend_from_slice(&valid_config.to_le_bytes());
|
||||
frame.push(block_count);
|
||||
frame.extend_from_slice(payload);
|
||||
frame.push(calc_crc8_itu(&frame));
|
||||
frame
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decodes_configured_nodes() {
|
||||
let mut codec = test_codec();
|
||||
let bytes = data_response(0b11, 0b01, &[1, 0, 2, 0, 3, 0]);
|
||||
let frames = codec.decode(&bytes, Instant::now()).unwrap();
|
||||
|
||||
let HandGatewayFrame::DataRep(frame) = &frames[0];
|
||||
assert_eq!(frame.timestamp, 123_456);
|
||||
assert_eq!(frame.block_count, 2);
|
||||
assert_eq!(frame.nodes.len(), 2);
|
||||
assert_eq!(frame.nodes[0].config_mask, 1);
|
||||
assert!(frame.nodes[0].valid);
|
||||
assert_eq!(
|
||||
HandGatewayCodec::parse_node_payload(&frame.nodes[0].payload).unwrap(),
|
||||
[1, 2]
|
||||
);
|
||||
assert!(!frame.nodes[1].valid);
|
||||
assert_eq!(
|
||||
HandGatewayCodec::parse_node_payload(&frame.nodes[1].payload).unwrap(),
|
||||
[3]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn supports_split_and_sticky_packets() {
|
||||
let mut codec = test_codec();
|
||||
let frame = data_response(0b01, 0b01, &[1, 0, 2, 0]);
|
||||
let split = frame.len() / 2;
|
||||
|
||||
assert!(codec
|
||||
.decode(&frame[..split], Instant::now())
|
||||
.unwrap()
|
||||
.is_empty());
|
||||
|
||||
let mut remainder_and_next = frame[split..].to_vec();
|
||||
remainder_and_next.extend_from_slice(&frame);
|
||||
let frames = codec.decode(&remainder_and_next, Instant::now()).unwrap();
|
||||
assert_eq!(frames.len(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resynchronizes_after_noise_and_bad_crc() {
|
||||
let mut codec = test_codec();
|
||||
let valid = data_response(0b10, 0b10, &[9, 0]);
|
||||
let mut bad = valid.clone();
|
||||
let last = bad.len() - 1;
|
||||
bad[last] ^= 0xFF;
|
||||
|
||||
let mut bytes = vec![0x13, 0x55, 0x12];
|
||||
bytes.extend_from_slice(&bad);
|
||||
bytes.extend_from_slice(&valid);
|
||||
|
||||
let frames = codec.decode(&bytes, Instant::now()).unwrap();
|
||||
assert_eq!(frames.len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rejects_payload_that_does_not_match_fixed_config() {
|
||||
let mut codec = test_codec();
|
||||
let bytes = data_response(0b01, 0b01, &[1, 0]);
|
||||
assert!(codec.decode(&bytes, Instant::now()).unwrap().is_empty());
|
||||
}
|
||||
}
|
||||
@@ -2,5 +2,4 @@ use crate::serial_core::{frame::TestFrame, record::Recording};
|
||||
|
||||
pub mod test;
|
||||
pub mod tactile_a;
|
||||
pub mod hand_gateway;
|
||||
pub type TestRecording = Recording<TestFrame>;
|
||||
@@ -14,7 +14,7 @@ use anyhow::anyhow;
|
||||
use std::io::Read;
|
||||
use log::debug;
|
||||
|
||||
const FINGER_FRAME_BUFFER_MIN_LENGTH: usize = 15;
|
||||
const FRAME_BUFFER_MIN_LENGTH: usize = 15;
|
||||
|
||||
pub struct TactileACodec {
|
||||
buffer: Vec<u8>,
|
||||
@@ -77,12 +77,11 @@ impl TactileACodec {
|
||||
.chunks_exact(2)
|
||||
.map(|chunk| {
|
||||
let raw = u16::from_le_bytes([chunk[0], chunk[1]]) as i32;
|
||||
raw
|
||||
// if raw < 15 {
|
||||
// 0
|
||||
// } else {
|
||||
// raw
|
||||
// }
|
||||
if raw < 15 {
|
||||
0
|
||||
} else {
|
||||
raw
|
||||
}
|
||||
})
|
||||
.collect::<Vec<i32>>();
|
||||
|
||||
@@ -123,7 +122,7 @@ impl Codec<TactileAFrame> for TactileACodec {
|
||||
let mut frames: Vec<TactileAFrame> = Vec::new();
|
||||
|
||||
loop {
|
||||
if self.buffer.len() < FINGER_FRAME_BUFFER_MIN_LENGTH {
|
||||
if self.buffer.len() < FRAME_BUFFER_MIN_LENGTH {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -137,7 +136,7 @@ impl Codec<TactileAFrame> for TactileACodec {
|
||||
self.buffer.drain(0..pos);
|
||||
}
|
||||
|
||||
if self.buffer.len() < FINGER_FRAME_BUFFER_MIN_LENGTH {
|
||||
if self.buffer.len() < FRAME_BUFFER_MIN_LENGTH {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -165,7 +164,7 @@ impl Codec<TactileAFrame> for TactileACodec {
|
||||
continue;
|
||||
}
|
||||
|
||||
let frame_length = except_data_len + FINGER_FRAME_BUFFER_MIN_LENGTH;
|
||||
let frame_length = except_data_len + FRAME_BUFFER_MIN_LENGTH;
|
||||
if self.buffer.len() < frame_length {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -62,7 +62,6 @@ impl Codec<TestFrame> for TestCodec {
|
||||
continue;
|
||||
}
|
||||
let dts = elapsed_millis(session_started_at);
|
||||
println!("dts_ms: {dts}");
|
||||
frames.push(TestFrame {
|
||||
header: [0xAA, 0x55],
|
||||
cmd: cmd,
|
||||
@@ -244,11 +243,10 @@ mod tests {
|
||||
fn test_read_csv_basic() -> anyhow::Result<()> {
|
||||
let mut rdr = Reader::from_path("recording_20260329_125238.csv")?;
|
||||
let headers = rdr.headers()?;
|
||||
println!("headers: {:?}", headers);
|
||||
|
||||
for result in rdr.records() {
|
||||
let record = result?;
|
||||
println!("record: {:?}", record);
|
||||
let _ = record;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -7,7 +7,7 @@ pub struct TestFrame {
|
||||
pub length: usize,
|
||||
pub payload: Vec<u8>,
|
||||
pub checksum: u8,
|
||||
pub dts_ms: u64,
|
||||
pub dts_ms: u64
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
@@ -35,54 +35,23 @@ pub struct TactileARepFrame {
|
||||
pub meta: TactileAFrameMetaData,
|
||||
pub status: TactileAFrameStatusCode,
|
||||
pub payload: Vec<u8>,
|
||||
pub dts_ms: u64,
|
||||
pub dts_ms: u64
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum TactileAFrameStatusCode {
|
||||
Success,
|
||||
Failure,
|
||||
Failure
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum TactileAFrame {
|
||||
Req(TactileAReqFrame),
|
||||
Rep(TactileARepFrame),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct HandGatewayFrameMetaData {
|
||||
pub header: [u8; 2],
|
||||
pub length: u16,
|
||||
pub cmd: u8,
|
||||
pub version: u8,
|
||||
pub checksum: u8,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct HandGatewayFrameNode {
|
||||
pub config_mask: u32,
|
||||
pub valid: bool,
|
||||
pub payload: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct HandGatewayDataRepFrame {
|
||||
pub meta: HandGatewayFrameMetaData,
|
||||
pub timestamp: u32,
|
||||
pub config: u32,
|
||||
pub valid_config: u32,
|
||||
pub block_count: u8,
|
||||
pub nodes: Vec<HandGatewayFrameNode>,
|
||||
pub dts_ms: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum HandGatewayFrame {
|
||||
DataRep(HandGatewayDataRepFrame),
|
||||
Rep(TactileARepFrame)
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait FrameHandler<F, T>: Send {
|
||||
async fn on_frame(&mut self, frame: &F) -> Result<Option<Vec<T>>>;
|
||||
}
|
||||
|
||||
|
||||
@@ -118,6 +118,10 @@ impl HudChartState {
|
||||
push_summary_point(&mut self.summary_points, value);
|
||||
}
|
||||
|
||||
pub fn clear_summary(&mut self) {
|
||||
self.summary_points.clear();
|
||||
}
|
||||
|
||||
pub fn record_pressure_matrix(&mut self, values: &[i32]) {
|
||||
if values.is_empty() {
|
||||
return;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,6 @@
|
||||
use crate::ad_solver::solve_for_x;
|
||||
#[cfg(feature = "devkit")]
|
||||
use crate::devkit::{proto::SensorFrame, DevKitState};
|
||||
use crate::serial_core::codec::Codec;
|
||||
use crate::serial_core::codecs::hand_gateway::HandGatewayCodec;
|
||||
use crate::serial_core::codecs::tactile_a::TactileACodec;
|
||||
use crate::serial_core::frame::{FrameHandler, TactileAFrame, TestFrame};
|
||||
use crate::serial_core::model::{HudChartState, HudPacket, HudSpatialForce};
|
||||
@@ -11,8 +9,6 @@ use crate::serial_core::multi_dim_force::PztProcessor;
|
||||
use crate::serial_core::record::Recording;
|
||||
use crate::serial_core::record::{FrameTiming, RecordedFrame};
|
||||
use anyhow::Result;
|
||||
use log::debug;
|
||||
use log::info;
|
||||
use std::future::pending;
|
||||
#[cfg(feature = "devkit")]
|
||||
use std::sync::atomic::Ordering;
|
||||
@@ -25,6 +21,7 @@ use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use tokio::time::{self, Duration, MissedTickBehavior};
|
||||
use tokio_serial::SerialStream;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
|
||||
const AUTO_SUB_INTERVAL: Duration = Duration::from_nanos(16_666_667);
|
||||
|
||||
pub enum PollMode<F> {
|
||||
@@ -202,61 +199,6 @@ where
|
||||
.await
|
||||
}
|
||||
|
||||
/// Runs the hand gateway in passive mode. The MCU continuously uploads data, so
|
||||
/// this loop never writes request frames to the serial port.
|
||||
pub async fn run_hand_gateway_serial(
|
||||
app: AppHandle,
|
||||
mut port: SerialStream,
|
||||
mut codec: HandGatewayCodec,
|
||||
session_started_at: Instant,
|
||||
cancel: CancellationToken,
|
||||
) -> Result<()> {
|
||||
let mut buffer = [0u8; 4096];
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
_ = cancel.cancelled() => break,
|
||||
read_result = port.read(&mut buffer) => {
|
||||
let n = read_result?;
|
||||
if n == 0 {
|
||||
tokio::task::yield_now().await;
|
||||
continue;
|
||||
}
|
||||
|
||||
let raw = &buffer[..n];
|
||||
app.emit("hand_gateway_raw", raw.to_vec())?;
|
||||
let raw_hex = raw
|
||||
.iter()
|
||||
.map(|byte| format!("{byte:02X}"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ");
|
||||
info!("[hand_gateway][raw] {raw_hex}");
|
||||
|
||||
for frame in codec.decode(raw, session_started_at)? {
|
||||
let crate::serial_core::frame::HandGatewayFrame::DataRep(frame) = frame;
|
||||
info!(
|
||||
"[hand_gateway][frame] timestamp_us={} config=0x{:08X} valid_config=0x{:08X} block_count={}",
|
||||
frame.timestamp,
|
||||
frame.config,
|
||||
frame.valid_config,
|
||||
frame.block_count,
|
||||
);
|
||||
for node in frame.nodes {
|
||||
info!(
|
||||
"[hand_gateway][node] mask=0x{:08X} valid={} payload={:02X?}",
|
||||
node.config_mask,
|
||||
node.valid,
|
||||
node.payload,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn run_serial_with_poll<C, H, T, F>(
|
||||
app: AppHandle,
|
||||
mut port: SerialStream,
|
||||
@@ -368,15 +310,14 @@ where
|
||||
drop(record);
|
||||
|
||||
if let Some(vals) = decode_res {
|
||||
#[cfg(feature = "multi-dim")]
|
||||
let mut spatial_force = None;
|
||||
#[cfg(not(feature = "multi-dim"))]
|
||||
let spatial_force = None;
|
||||
#[cfg(feature = "multi-dim")]
|
||||
{
|
||||
let pzt_values = vals.iter().map(|value| *value as f32).collect::<Vec<f32>>();
|
||||
if let Ok(analysis) = pzt_processor.get_pzt_analysis(&pzt_values) {
|
||||
// debug!(
|
||||
// "spatial force: angle={:.2}°, magnitude={:.2}, dx={:.2}, dy={:.2}",
|
||||
// analysis.angle_deg, analysis.magnitude, analysis.planar_x, analysis.planar_y
|
||||
// );
|
||||
if let Ok(analysis) = pzt_processor.get_pzt_analysis_at(&pzt_values, frame.dts_ms() as f32) {
|
||||
if PztProcessor::should_report(&analysis) {
|
||||
spatial_force = Some(HudSpatialForce {
|
||||
angle_deg: analysis.angle_deg,
|
||||
@@ -386,13 +327,15 @@ where
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "devkit")]
|
||||
{
|
||||
let summary = vals.iter().copied().sum::<i32>();
|
||||
let force = raw_to_g1(summary as u32);
|
||||
|
||||
push_devkit_frame(&app, vals.as_slice(), frame.dts_ms(), force);
|
||||
}
|
||||
// #[cfg(feature = "devkit")]
|
||||
// {
|
||||
// let summary = vals.iter().copied().sum::<i32>();
|
||||
// #[cfg(feature = "debug")]
|
||||
// let force = raw_to_g1(summary as u32);
|
||||
// #[cfg(not(feature = "debug"))]
|
||||
// let force = summary as f64;
|
||||
// push_devkit_frame(&app, vals.as_slice(), frame.dts_ms(), force);
|
||||
// }
|
||||
|
||||
pending_sub_frame = Some(PendingSubFrame {
|
||||
frame: frame.clone(),
|
||||
@@ -415,15 +358,24 @@ fn build_display_values(
|
||||
spatial_force: Option<HudSpatialForce>,
|
||||
) -> Option<Vec<i32>> {
|
||||
let summary = values.iter().copied().sum::<i32>();
|
||||
let force = raw_to_g1(summary as u32);
|
||||
// let force_solve = solve_for_x(summary as f64)?;
|
||||
// println!("force_solve: {force_solve}");
|
||||
chart_state.record_summary(force as f32);
|
||||
chart_state.record_pressure_matrix(values);
|
||||
chart_state.record_spatial_force(spatial_force);
|
||||
Some(vec![summary])
|
||||
|
||||
let x = raw_to_g1(summary as u32).min(MAX_DISPLAY_FORCE);
|
||||
if x <= MIN_DISPLAY_FORCE {
|
||||
let zero_values = vec![0; values.len()];
|
||||
chart_state.record_summary(0.0);
|
||||
chart_state.record_pressure_matrix(&zero_values);
|
||||
return Some(vec![0]);
|
||||
}
|
||||
|
||||
chart_state.record_pressure_matrix(values);
|
||||
chart_state.record_summary(x as f32);
|
||||
Some(vec![x.round() as i32])
|
||||
}
|
||||
|
||||
const MIN_DISPLAY_FORCE: f64 = 0.1;
|
||||
const MAX_DISPLAY_FORCE: f64 = 25.6;
|
||||
|
||||
#[cfg(feature = "devkit")]
|
||||
fn push_devkit_frame(app: &AppHandle, values: &[i32], dts_ms: u64, resultant_force: f64) {
|
||||
let devkit_state = app.state::<DevKitState>();
|
||||
@@ -477,13 +429,12 @@ fn infer_matrix_shape(len: usize) -> (u32, u32) {
|
||||
}
|
||||
|
||||
fn raw_to_g1(raw: u32) -> f64 {
|
||||
const X: [u32; 13] = [
|
||||
0, 16811, 41350, 79241, 94615, 127446, 149559, 175900, 195056, 237852, 267810, 322472,
|
||||
378511,
|
||||
const X: [u32; 12] = [
|
||||
0, 21382, 108507, 123183, 147405, 171105, 192395, 250443, 231423, 350560, 396616, 429444
|
||||
];
|
||||
|
||||
const Y: [f64; 13] = [
|
||||
0.0, 57.0, 97.0, 197.0, 257.0, 357.0, 457.0, 557.0, 657.0, 857.0, 1057.0, 1557.0, 2057.0,
|
||||
const Y: [f64; 12] = [
|
||||
0.0, 57.0, 257.0, 357.0, 457.0, 557.0, 657.0, 857.0, 1057.0, 1557.0, 2057.0, 2557.0
|
||||
];
|
||||
|
||||
let n = X.len();
|
||||
|
||||
@@ -41,9 +41,7 @@
|
||||
"template": "nsis/installer.nsi"
|
||||
}
|
||||
},
|
||||
"resources": [
|
||||
"resources/je-skin-devkit-server.exe"
|
||||
]
|
||||
"resources": []
|
||||
},
|
||||
"plugins": {
|
||||
"updater": {
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
export let summary: HudSummary;
|
||||
export let pressureMatrix: number[] | null = null;
|
||||
export let spatialForce: HudSpatialForce | null = null;
|
||||
export let devkitSpatialForce: HudSpatialForce | null = null;
|
||||
export let showConfigPanel = false;
|
||||
export let configPanelTitle = "";
|
||||
export let configPanelHint = "";
|
||||
@@ -48,7 +47,7 @@
|
||||
export let colorMapPreset: PressureColorMapPreset = "emerald";
|
||||
export let matrixDisplayMode: MatrixDisplayMode = "dots";
|
||||
export let stageViewMode: StageViewMode = "webgl";
|
||||
export let modelUrl = "/models/je-skin-model.gltf";
|
||||
export let modelUrl = "/models/je-skin-model.glb";
|
||||
export let replaySectionLabel = "";
|
||||
export let replayPlayLabel = "";
|
||||
export let replayPauseLabel = "";
|
||||
@@ -61,8 +60,9 @@
|
||||
export let replayProgress = 0;
|
||||
export let replayFileName = "";
|
||||
export let replayFrameInfo = "";
|
||||
export let showPrecisionTestPanel = false;
|
||||
export let sessionStartedAt: number = Date.now();
|
||||
export let summaryReleasePending = false;
|
||||
export let spatialForcePanelVisible = false;
|
||||
|
||||
let stagePlaneEl: HTMLDivElement | undefined;
|
||||
let panelZoneEl: HTMLDivElement | undefined;
|
||||
@@ -89,9 +89,9 @@
|
||||
$: replaySide = summarySide === "left" ? "right" : "left";
|
||||
$: replayToggleButtonText = replayIsPlaying ? replayPauseLabel : replayPlayLabel;
|
||||
$: 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";
|
||||
$: summaryCurveVisible =
|
||||
summary.points.length > 0 &&
|
||||
(summaryReleasePending || summary.points.some((value) => Number.isFinite(value) && Math.abs(value) >= 0.0001));
|
||||
$: isModelStage = stageViewMode === "model3d";
|
||||
|
||||
function toPxNumber(rawValue: string): number {
|
||||
@@ -117,7 +117,7 @@
|
||||
return;
|
||||
}
|
||||
|
||||
panelZoneTopPx = showPrecisionTestPanel ? 24 : 16;
|
||||
panelZoneTopPx = 16;
|
||||
|
||||
const panelZoneBottomPx = panelZoneEl ? toPxNumber(getComputedStyle(panelZoneEl).bottom) : 0;
|
||||
const zoneHeight = Math.max(0, stagePlaneEl.clientHeight - panelZoneTopPx - panelZoneBottomPx);
|
||||
@@ -191,43 +191,6 @@
|
||||
<ModelStage {locale} {modelUrl} />
|
||||
{/key}
|
||||
</div>
|
||||
{:else if showPrecisionTestPanel}
|
||||
<div class="split-game-wrap">
|
||||
<section class="split-panel split-matrix-panel">
|
||||
<header class="split-panel-head">
|
||||
<p>{splitMatrixTitle}</p>
|
||||
<span>{splitMatrixHint}</span>
|
||||
</header>
|
||||
<div class="split-panel-body">
|
||||
{#key `${matrixRows}x${matrixCols}:${colorMapPreset}:split`}
|
||||
<PressureMatrixViewer
|
||||
{summary}
|
||||
{pressureMatrix}
|
||||
{matrixRows}
|
||||
{matrixCols}
|
||||
{rangeMin}
|
||||
{rangeMax}
|
||||
{colorMapPreset}
|
||||
{matrixDisplayMode}
|
||||
{locale}
|
||||
showStatsPanel={true}
|
||||
/>
|
||||
{/key}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="split-panel split-breakout-panel">
|
||||
<NeonBreakoutArena
|
||||
{locale}
|
||||
{pressureMatrix}
|
||||
{matrixRows}
|
||||
{matrixCols}
|
||||
{rangeMin}
|
||||
{rangeMax}
|
||||
{colorMapPreset}
|
||||
/>
|
||||
</section>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="canvas-wrap">
|
||||
{#key `${matrixRows}x${matrixCols}:${colorMapPreset}`}
|
||||
@@ -247,7 +210,7 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if showConfigPanel && !showPrecisionTestPanel && !isModelStage}
|
||||
{#if showConfigPanel && !isModelStage}
|
||||
<div class="config-panel-wrap">
|
||||
<ConfigPanel
|
||||
bind:matrixRows
|
||||
@@ -269,7 +232,7 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if !showPrecisionTestPanel && !isModelStage}
|
||||
{#if !isModelStage}
|
||||
<div class="panel-zone" bind:this={panelZoneEl}>
|
||||
<aside class="side-rail left-rail">
|
||||
<div class="rail-stack" bind:this={leftStackEl}>
|
||||
@@ -317,42 +280,24 @@
|
||||
<SignalChart {panel} panelIndex={index} {locale} />
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
<div
|
||||
class="panel-motion-shell"
|
||||
in:fly={{ x: 180, duration: 340, opacity: 0.08, easing: cubicOut }}
|
||||
out:fly={{ x: 180, duration: 280, opacity: 0.06, easing: cubicIn }}
|
||||
>
|
||||
<SpatialForcePanel
|
||||
{spatialForce}
|
||||
{locale}
|
||||
side="right"
|
||||
panelIndex={rightPanels.length}
|
||||
panelCode="ALG"
|
||||
panelTitle={locale === "zh-CN" ? "本地切向力" : "Local Tangential"}
|
||||
badgeLabel={locale === "zh-CN" ? "算法" : "ALGO"}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="panel-motion-shell"
|
||||
in:fly={{ x: 180, duration: 340, opacity: 0.08, easing: cubicOut }}
|
||||
out:fly={{ x: 180, duration: 280, opacity: 0.06, easing: cubicIn }}
|
||||
>
|
||||
<SpatialForcePanel
|
||||
spatialForce={devkitSpatialForce}
|
||||
{locale}
|
||||
side="right"
|
||||
panelIndex={rightPanels.length + 1}
|
||||
panelCode="DKT"
|
||||
panelTitle={locale === "zh-CN" ? "DevKit 切向力" : "DevKit Tangential"}
|
||||
badgeLabel="DEVKIT"
|
||||
badgeTone="lime"
|
||||
showMetrics={false}
|
||||
requireMagnitude={false}
|
||||
compactMetaText={locale === "zh-CN" ? "等待 DevKit 角度流" : "Waiting for DevKit angle"}
|
||||
/>
|
||||
</div>
|
||||
{#if spatialForcePanelVisible}
|
||||
<div
|
||||
class="panel-motion-shell"
|
||||
in:fly={{ x: 180, duration: 340, opacity: 0.08, easing: cubicOut }}
|
||||
out:fly={{ x: 180, duration: 280, opacity: 0.06, easing: cubicIn }}
|
||||
>
|
||||
<SpatialForcePanel
|
||||
{spatialForce}
|
||||
{locale}
|
||||
side="right"
|
||||
panelIndex={rightPanels.length}
|
||||
panelCode="3D"
|
||||
panelTitle={locale === "zh-CN" ? "三维力" : "3D Force"}
|
||||
badgeLabel=""
|
||||
badgeTone="lime"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if summaryCurveVisible && summarySide === "right"}
|
||||
<div
|
||||
@@ -368,7 +313,7 @@
|
||||
{sessionStartedAt}
|
||||
isRealtime={!replayHasData}
|
||||
side="right"
|
||||
panelIndex={rightPanels.length}
|
||||
panelIndex={rightPanels.length + (spatialForcePanelVisible ? 1 : 0)}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -377,7 +322,7 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if replayHasData && !showPrecisionTestPanel && !isModelStage}
|
||||
{#if replayHasData && !isModelStage}
|
||||
<aside class="replay-floating-panel" class:is-left={replaySide === "left"} class:is-right={replaySide === "right"}>
|
||||
<div class="replay-panel-head">
|
||||
<div class="replay-panel-title-group">
|
||||
@@ -415,7 +360,7 @@
|
||||
</aside>
|
||||
{/if}
|
||||
|
||||
{#if !showPrecisionTestPanel && !isModelStage}
|
||||
{#if !isModelStage}
|
||||
<div class="stage-bottom-overlay">
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
@@ -2,10 +2,8 @@
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import type {
|
||||
ConnectionState,
|
||||
HudConfigLink,
|
||||
HudNoticeTone,
|
||||
LocaleCode,
|
||||
MatrixDisplayMode,
|
||||
StageViewMode,
|
||||
WindowControlAction
|
||||
} from "$lib/types/hud";
|
||||
@@ -29,15 +27,8 @@
|
||||
export let serialPortValue = "";
|
||||
export let serialPortOptions: string[] = [];
|
||||
export let refreshPortsLabel = "";
|
||||
export let configLinksLabel = "";
|
||||
export let configLinks: HudConfigLink[] = [];
|
||||
export let matrixViewLabel = "";
|
||||
export let matrixViewNumericLabel = "";
|
||||
export let matrixViewDotsLabel = "";
|
||||
export let matrixDisplayMode: MatrixDisplayMode = "dots";
|
||||
export let stageModeLabel = "";
|
||||
export let stageModeWebglLabel = "";
|
||||
export let stageModeModelLabel = "";
|
||||
export let stageViewMode: StageViewMode = "webgl";
|
||||
export let connectActionLabel = "";
|
||||
export let disconnectActionLabel = "";
|
||||
@@ -59,7 +50,6 @@
|
||||
const dispatch = createEventDispatcher<{
|
||||
windowcontrol: WindowControlAction;
|
||||
localechange: LocaleCode;
|
||||
configlink: string;
|
||||
matrixdisplaytoggle: boolean;
|
||||
stagemodechange: StageViewMode;
|
||||
portchange: string;
|
||||
@@ -103,14 +93,6 @@
|
||||
dispatch("localechange", nextLocale);
|
||||
}
|
||||
|
||||
function emitConfigLink(linkId: string): void {
|
||||
dispatch("configlink", linkId);
|
||||
}
|
||||
|
||||
function emitMatrixDisplayToggle(): void {
|
||||
dispatch("matrixdisplaytoggle", matrixDisplayMode !== "dots");
|
||||
}
|
||||
|
||||
function emitStageModeChange(nextMode: StageViewMode): void {
|
||||
dispatch("stagemodechange", nextMode);
|
||||
}
|
||||
@@ -195,60 +177,6 @@
|
||||
|
||||
<div class="control-bar">
|
||||
<div class="control-main-row">
|
||||
<section class="config-links" aria-label={configLinksLabel}>
|
||||
{#each configLinks as link (link.id)}
|
||||
<button
|
||||
type="button"
|
||||
class="config-link tone-{link.tone ?? 'neutral'}"
|
||||
class:is-active={Boolean(link.active)}
|
||||
on:click={() => emitConfigLink(link.id)}
|
||||
>
|
||||
<span class="config-indicator" aria-hidden="true"></span>
|
||||
<span class="config-label">{link.label}</span>
|
||||
</button>
|
||||
{/each}
|
||||
</section>
|
||||
|
||||
<section class="matrix-switch-wrap" aria-label={matrixViewLabel}>
|
||||
<span class="matrix-switch-label">{matrixViewLabel}</span>
|
||||
<button
|
||||
type="button"
|
||||
class="matrix-switch-btn"
|
||||
class:is-active={matrixDisplayMode === "dots"}
|
||||
role="switch"
|
||||
aria-checked={matrixDisplayMode === "dots"}
|
||||
aria-label={matrixViewDotsLabel}
|
||||
on:click={emitMatrixDisplayToggle}
|
||||
>
|
||||
<span class="matrix-switch-track" aria-hidden="true">
|
||||
<span class="matrix-switch-thumb"></span>
|
||||
</span>
|
||||
<span class="matrix-switch-copy">{matrixDisplayMode === "dots" ? matrixViewDotsLabel : matrixViewNumericLabel}</span>
|
||||
</button>
|
||||
</section>
|
||||
|
||||
<section class="stage-mode-switch" aria-label={stageModeLabel}>
|
||||
<span class="stage-mode-label">{stageModeLabel}</span>
|
||||
<div class="stage-mode-options" role="group" aria-label={stageModeLabel}>
|
||||
<button
|
||||
type="button"
|
||||
class="stage-mode-btn"
|
||||
class:is-active={stageViewMode === "webgl"}
|
||||
on:click={() => emitStageModeChange("webgl")}
|
||||
>
|
||||
{stageModeWebglLabel}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="stage-mode-btn"
|
||||
class:is-active={stageViewMode === "model3d"}
|
||||
on:click={() => emitStageModeChange("model3d")}
|
||||
>
|
||||
{stageModeModelLabel}
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="state-card" aria-label={connectionLabel}>
|
||||
<span class="state-dot" class:ok={connectionTone === "ok"} class:warn={connectionTone === "warn"}></span>
|
||||
<span class="state-label">{connectionLabel}</span>
|
||||
@@ -517,149 +445,6 @@
|
||||
background: var(--panel-surface);
|
||||
}
|
||||
|
||||
.matrix-switch-wrap,
|
||||
.stage-mode-switch {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
min-block-size: 2rem;
|
||||
border: 1px solid var(--panel-line);
|
||||
border-radius: 999px;
|
||||
padding: 0.16rem 0.22rem 0.16rem 0.56rem;
|
||||
background: var(--panel-surface);
|
||||
}
|
||||
|
||||
.matrix-switch-label,
|
||||
.stage-mode-label {
|
||||
color: var(--panel-text-dim);
|
||||
font-size: 0.66rem;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.matrix-switch-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.42rem;
|
||||
min-block-size: 1.62rem;
|
||||
border: 1px solid rgb(var(--hud-border-rgb) / 0.26);
|
||||
border-radius: 999px;
|
||||
padding: 0.18rem 0.28rem 0.18rem 0.22rem;
|
||||
background: rgb(var(--hud-surface-deep-rgb) / 0.84);
|
||||
color: rgb(var(--hud-text-main-rgb) / 0.92);
|
||||
cursor: pointer;
|
||||
transition:
|
||||
border-color 180ms ease,
|
||||
box-shadow 180ms ease,
|
||||
background-color 180ms ease,
|
||||
color 180ms ease;
|
||||
}
|
||||
|
||||
.matrix-switch-btn:hover {
|
||||
border-color: rgb(var(--hud-cyan-rgb) / 0.4);
|
||||
}
|
||||
|
||||
.matrix-switch-btn.is-active {
|
||||
border-color: rgb(var(--hud-cyan-rgb) / 0.5);
|
||||
background:
|
||||
linear-gradient(180deg, rgb(var(--hud-surface-alt-rgb) / 0.94), rgb(var(--hud-surface-rgb) / 0.9)),
|
||||
radial-gradient(circle at 50% 0, rgb(var(--hud-cyan-rgb) / 0.12), transparent 60%);
|
||||
box-shadow:
|
||||
inset 0 0 0 1px rgb(var(--hud-text-main-rgb) / 0.05),
|
||||
0 0 12px rgb(var(--hud-cyan-rgb) / 0.12);
|
||||
}
|
||||
|
||||
.matrix-switch-track {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
inline-size: 2.2rem;
|
||||
block-size: 1.2rem;
|
||||
border-radius: 999px;
|
||||
padding: 0.14rem;
|
||||
background: rgb(var(--hud-surface-rgb) / 0.9);
|
||||
box-shadow: inset 0 0 0 1px rgb(var(--hud-border-rgb) / 0.24);
|
||||
transition:
|
||||
background-color 180ms ease,
|
||||
box-shadow 180ms ease;
|
||||
}
|
||||
|
||||
.matrix-switch-btn.is-active .matrix-switch-track {
|
||||
background: rgb(var(--hud-cyan-rgb) / 0.18);
|
||||
box-shadow: inset 0 0 0 1px rgb(var(--hud-cyan-rgb) / 0.18);
|
||||
}
|
||||
|
||||
.matrix-switch-thumb {
|
||||
inline-size: 0.92rem;
|
||||
block-size: 0.92rem;
|
||||
border-radius: 50%;
|
||||
background: rgb(var(--hud-text-main-rgb) / 0.96);
|
||||
box-shadow:
|
||||
0 1px 4px rgb(0 0 0 / 0.26),
|
||||
0 0 10px rgb(var(--hud-text-main-rgb) / 0.12);
|
||||
transform: translateX(0);
|
||||
transition:
|
||||
transform 180ms ease,
|
||||
background-color 180ms ease,
|
||||
box-shadow 180ms ease;
|
||||
}
|
||||
|
||||
.matrix-switch-btn.is-active .matrix-switch-thumb {
|
||||
transform: translateX(0.96rem);
|
||||
background: rgb(var(--hud-cyan-rgb) / 0.96);
|
||||
box-shadow:
|
||||
0 1px 4px rgb(0 0 0 / 0.26),
|
||||
0 0 12px rgb(var(--hud-cyan-rgb) / 0.22);
|
||||
}
|
||||
|
||||
.matrix-switch-copy {
|
||||
font-size: 0.74rem;
|
||||
letter-spacing: 0.04em;
|
||||
white-space: nowrap;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.stage-mode-options {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.18rem;
|
||||
padding: 0.16rem;
|
||||
border: 1px solid rgb(var(--hud-border-rgb) / 0.24);
|
||||
border-radius: 999px;
|
||||
background: rgb(var(--hud-surface-deep-rgb) / 0.8);
|
||||
}
|
||||
|
||||
.stage-mode-btn {
|
||||
min-block-size: 1.38rem;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 999px;
|
||||
padding: 0.18rem 0.54rem;
|
||||
background: transparent;
|
||||
color: rgb(var(--hud-text-dim-rgb) / 0.88);
|
||||
font: inherit;
|
||||
font-size: 0.7rem;
|
||||
letter-spacing: 0.04em;
|
||||
cursor: pointer;
|
||||
transition:
|
||||
border-color 180ms ease,
|
||||
background-color 180ms ease,
|
||||
color 180ms ease,
|
||||
box-shadow 180ms ease;
|
||||
}
|
||||
|
||||
.stage-mode-btn:hover {
|
||||
color: rgb(var(--hud-text-main-rgb) / 0.96);
|
||||
}
|
||||
|
||||
.stage-mode-btn.is-active {
|
||||
border-color: rgb(var(--hud-cyan-rgb) / 0.42);
|
||||
background: rgb(var(--hud-cyan-rgb) / 0.14);
|
||||
color: rgb(var(--hud-text-main-rgb) / 0.98);
|
||||
box-shadow: 0 0 12px rgb(var(--hud-cyan-rgb) / 0.1);
|
||||
}
|
||||
|
||||
.state-dot {
|
||||
inline-size: 0.55rem;
|
||||
block-size: 0.55rem;
|
||||
@@ -1123,93 +908,6 @@
|
||||
background: rgb(10 16 20 / 0.7);
|
||||
}
|
||||
|
||||
.config-links {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.2rem;
|
||||
min-block-size: 2rem;
|
||||
border: 1px solid rgb(95 132 158 / 0.36);
|
||||
border-radius: 999px;
|
||||
padding: 0.17rem 0.2rem;
|
||||
background: linear-gradient(180deg, rgb(9 15 19 / 0.9), rgb(4 8 12 / 0.86));
|
||||
box-shadow: inset 0 0 0 1px rgb(140 184 210 / 0.06);
|
||||
}
|
||||
|
||||
.config-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.34rem;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 999px;
|
||||
padding: 0.26rem 0.64rem;
|
||||
background: transparent;
|
||||
color: rgb(164 188 208 / 0.9);
|
||||
font-size: 0.81rem;
|
||||
letter-spacing: 0.05em;
|
||||
cursor: pointer;
|
||||
transition:
|
||||
color 180ms ease,
|
||||
border-color 180ms ease,
|
||||
background-color 180ms ease,
|
||||
box-shadow 220ms ease;
|
||||
}
|
||||
|
||||
.config-indicator {
|
||||
inline-size: 0.34rem;
|
||||
block-size: 0.34rem;
|
||||
border-radius: 999px;
|
||||
background: rgb(136 157 174 / 0.88);
|
||||
box-shadow: 0 0 0 2px rgb(136 157 174 / 0.16);
|
||||
transition:
|
||||
background-color 180ms ease,
|
||||
box-shadow 200ms ease;
|
||||
}
|
||||
|
||||
.config-label {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.config-link:hover {
|
||||
color: #d7edfb;
|
||||
border-color: rgb(62 232 255 / 0.26);
|
||||
}
|
||||
|
||||
.config-link.is-active {
|
||||
color: #f1fdff;
|
||||
border-color: rgb(106 150 180 / 0.56);
|
||||
background: rgb(18 27 35 / 0.9);
|
||||
box-shadow:
|
||||
inset 0 0 0 1px rgb(167 218 252 / 0.08),
|
||||
0 0 10px rgb(62 232 255 / 0.12);
|
||||
}
|
||||
|
||||
.config-link.tone-cyan.is-active {
|
||||
border-color: rgb(62 232 255 / 0.48);
|
||||
}
|
||||
|
||||
.config-link.tone-lime.is-active {
|
||||
border-color: rgb(133 255 68 / 0.52);
|
||||
}
|
||||
|
||||
.config-link.tone-orange.is-active {
|
||||
border-color: rgb(255 91 63 / 0.52);
|
||||
}
|
||||
|
||||
.config-link.tone-cyan.is-active .config-indicator {
|
||||
background: var(--hud-cyan);
|
||||
box-shadow: 0 0 0 2px rgb(62 232 255 / 0.17);
|
||||
}
|
||||
|
||||
.config-link.tone-lime.is-active .config-indicator {
|
||||
background: var(--hud-lime);
|
||||
box-shadow: 0 0 0 2px rgb(133 255 68 / 0.17);
|
||||
}
|
||||
|
||||
.config-link.tone-orange.is-active .config-indicator {
|
||||
background: var(--hud-orange);
|
||||
box-shadow: 0 0 0 2px rgb(255 91 63 / 0.18);
|
||||
}
|
||||
|
||||
.locale-btn {
|
||||
border: 1px solid transparent;
|
||||
border-radius: 999px;
|
||||
@@ -1236,21 +934,11 @@
|
||||
background: rgb(24 31 25 / 0.9);
|
||||
}
|
||||
|
||||
@media (max-width: 1080px) {
|
||||
.config-links {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 820px) {
|
||||
.control-main-row {
|
||||
gap: 0.44rem;
|
||||
}
|
||||
|
||||
.config-links {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.serial-select {
|
||||
padding-inline-start: 0.45rem;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
type ModelLoadState = "loading" | "ready" | "missing" | "error";
|
||||
|
||||
export let locale: LocaleCode = "zh-CN";
|
||||
export let modelUrl = "/models/je-skin-model.glb";
|
||||
export let modelUrl = "/models/je-skin-model.gltf";
|
||||
|
||||
let rootEl: HTMLDivElement | undefined;
|
||||
let canvasEl: HTMLCanvasElement | undefined;
|
||||
@@ -19,15 +19,43 @@
|
||||
|
||||
const FLOOR_Y = -1.15;
|
||||
const MODEL_FLOOR_CLEARANCE = 0.035;
|
||||
const MODEL_TARGET_HEIGHT = 6.55;
|
||||
const MODEL_TARGET_HEIGHT = 8.4;
|
||||
const MODEL_MIN_SCALE = 0.02;
|
||||
const MODEL_MAX_SCALE = 80;
|
||||
const FIXED_CAMERA_POSITION = new THREE.Vector3(-0.113, -0.149, 10.911);
|
||||
const FIXED_CAMERA_TARGET = new THREE.Vector3(0, 2.35, 0);
|
||||
const MODEL_FRONT_ROTATION_Y = -Math.PI / 2;
|
||||
const MODEL_UPRIGHT_ROTATION_Z = Math.PI * 1.5 - THREE.MathUtils.degToRad(2.2);
|
||||
const CAMERA_DISTANCE_FACTOR = 1.35;
|
||||
const CAMERA_DISTANCE_MIN = 7.5;
|
||||
const CAMERA_DISTANCE_MAX = 24;
|
||||
|
||||
$: canvasLabel = locale === "zh-CN" ? "3D 模型" : "3D Model";
|
||||
$: copy =
|
||||
locale === "zh-CN"
|
||||
? {
|
||||
title: "3D 模型舱",
|
||||
subtitle: "Dark Grid / Future Lab",
|
||||
loading: "正在加载模型",
|
||||
ready: "模型已载入",
|
||||
missing: "等待模型文件",
|
||||
error: "模型加载失败",
|
||||
modelPath: "模型路径",
|
||||
hint: "请使用 glTF 2.0 的 .glb/.gltf;旧版 glTF 1.0 需要先转换"
|
||||
}
|
||||
: {
|
||||
title: "3D Model Bay",
|
||||
subtitle: "Dark Grid / Future Lab",
|
||||
loading: "Loading model",
|
||||
ready: "Model loaded",
|
||||
missing: "Waiting for model file",
|
||||
error: "Model load failed",
|
||||
modelPath: "Model path",
|
||||
hint: "Use glTF 2.0 .glb/.gltf assets; older glTF 1.0 files need conversion first"
|
||||
};
|
||||
$: statusText =
|
||||
loadState === "ready"
|
||||
? copy.ready
|
||||
: loadState === "missing"
|
||||
? copy.missing
|
||||
: loadState === "error"
|
||||
? copy.error
|
||||
: `${copy.loading} ${Math.round(loadProgress)}%`;
|
||||
|
||||
function disposeObject3D(object: THREE.Object3D): void {
|
||||
object.traverse((child) => {
|
||||
@@ -100,41 +128,7 @@
|
||||
return Math.min(max, Math.max(min, value));
|
||||
}
|
||||
|
||||
function materialToUnlit(material: THREE.Material): THREE.Material {
|
||||
const source = material as THREE.MeshStandardMaterial & THREE.MeshPhysicalMaterial;
|
||||
const unlit = new THREE.MeshBasicMaterial({
|
||||
color: source.color?.clone() ?? new THREE.Color(0xffffff),
|
||||
map: source.map ?? null,
|
||||
transparent: source.transparent,
|
||||
opacity: source.opacity,
|
||||
alphaMap: source.alphaMap ?? null,
|
||||
side: source.side,
|
||||
depthWrite: source.depthWrite,
|
||||
depthTest: source.depthTest,
|
||||
vertexColors: source.vertexColors,
|
||||
toneMapped: false
|
||||
});
|
||||
|
||||
return unlit;
|
||||
}
|
||||
|
||||
function applyUnlitMaterials(object: THREE.Object3D): void {
|
||||
object.traverse((child) => {
|
||||
const mesh = child as THREE.Mesh;
|
||||
if (!mesh.isMesh || !mesh.material) {
|
||||
return;
|
||||
}
|
||||
|
||||
mesh.castShadow = false;
|
||||
mesh.receiveShadow = false;
|
||||
mesh.material = Array.isArray(mesh.material)
|
||||
? mesh.material.map(materialToUnlit)
|
||||
: materialToUnlit(mesh.material);
|
||||
});
|
||||
}
|
||||
|
||||
function normalizeObjectToStage(object: THREE.Object3D): THREE.Box3 {
|
||||
object.rotation.set(0, MODEL_FRONT_ROTATION_Y, MODEL_UPRIGHT_ROTATION_Z);
|
||||
object.updateMatrixWorld(true);
|
||||
let bounds = new THREE.Box3().setFromObject(object);
|
||||
const size = bounds.getSize(new THREE.Vector3());
|
||||
@@ -155,14 +149,19 @@
|
||||
}
|
||||
|
||||
function frameObject(object: THREE.Object3D, camera: THREE.PerspectiveCamera, controls: OrbitControls): void {
|
||||
normalizeObjectToStage(object);
|
||||
camera.position.copy(FIXED_CAMERA_POSITION);
|
||||
camera.near = 0.05;
|
||||
camera.far = 600;
|
||||
const bounds = normalizeObjectToStage(object);
|
||||
const size = bounds.getSize(new THREE.Vector3());
|
||||
const maxAxis = Math.max(size.x, size.y, size.z, 1);
|
||||
const distance = clamp(maxAxis * CAMERA_DISTANCE_FACTOR, CAMERA_DISTANCE_MIN, CAMERA_DISTANCE_MAX);
|
||||
const targetY = FLOOR_Y + Math.max(size.y * 0.46, 1.4);
|
||||
|
||||
camera.position.set(distance * 0.48, targetY + distance * 0.24, distance * 0.68);
|
||||
camera.near = Math.max(distance / 80, 0.01);
|
||||
camera.far = distance * 24;
|
||||
camera.updateProjectionMatrix();
|
||||
controls.target.copy(FIXED_CAMERA_TARGET);
|
||||
controls.minDistance = 2.4;
|
||||
controls.maxDistance = 32;
|
||||
controls.target.set(0, targetY, 0);
|
||||
controls.minDistance = Math.max(distance * 0.32, 2);
|
||||
controls.maxDistance = Math.max(distance * 2.5, 12);
|
||||
controls.update();
|
||||
}
|
||||
|
||||
@@ -187,15 +186,14 @@
|
||||
scene.fog = new THREE.FogExp2(0x03070d, 0.028);
|
||||
|
||||
const camera = new THREE.PerspectiveCamera(38, 1, 0.05, 600);
|
||||
camera.position.copy(FIXED_CAMERA_POSITION);
|
||||
camera.lookAt(FIXED_CAMERA_TARGET);
|
||||
camera.position.set(8, 6, 9);
|
||||
|
||||
const controls = new OrbitControls(camera, canvasEl);
|
||||
controls.enableDamping = true;
|
||||
controls.dampingFactor = 0.08;
|
||||
controls.minDistance = 2.4;
|
||||
controls.maxDistance = 32;
|
||||
controls.target.copy(FIXED_CAMERA_TARGET);
|
||||
controls.target.set(0, FLOOR_Y + 3.2, 0);
|
||||
|
||||
const labGroup = new THREE.Group();
|
||||
scene.add(labGroup);
|
||||
@@ -243,8 +241,16 @@
|
||||
floor.position.y = FLOOR_Y - 0.018;
|
||||
labGroup.add(floor);
|
||||
|
||||
const ambient = new THREE.AmbientLight(0x9fb8d0, 0.22);
|
||||
const keyLight = new THREE.DirectionalLight(0x7be7ff, 1.5);
|
||||
keyLight.position.set(8, 12, 8);
|
||||
const rimLight = new THREE.PointLight(0xa6ff7a, 26, 24, 2.1);
|
||||
rimLight.position.set(-4.5, 4.8, -3.6);
|
||||
const sideLight = new THREE.PointLight(0x5c8cff, 15, 28, 1.7);
|
||||
sideLight.position.set(5.8, 3.2, -5.4);
|
||||
scene.add(ambient, keyLight, rimLight, sideLight);
|
||||
|
||||
let activeModel: THREE.Object3D = buildPlaceholderModel();
|
||||
applyUnlitMaterials(activeModel);
|
||||
scene.add(activeModel);
|
||||
frameObject(activeModel, camera, controls);
|
||||
|
||||
@@ -255,7 +261,13 @@
|
||||
scene.remove(activeModel);
|
||||
disposeObject3D(activeModel);
|
||||
activeModel = gltf.scene;
|
||||
applyUnlitMaterials(activeModel);
|
||||
activeModel.traverse((child) => {
|
||||
const mesh = child as THREE.Mesh;
|
||||
if (mesh.isMesh) {
|
||||
mesh.castShadow = true;
|
||||
mesh.receiveShadow = true;
|
||||
}
|
||||
});
|
||||
scene.add(activeModel);
|
||||
frameObject(activeModel, camera, controls);
|
||||
loadState = "ready";
|
||||
@@ -318,9 +330,20 @@
|
||||
</script>
|
||||
|
||||
<div class="model-stage" bind:this={rootEl}>
|
||||
<canvas class="model-canvas" bind:this={canvasEl} aria-label={canvasLabel}></canvas>
|
||||
<canvas class="model-canvas" bind:this={canvasEl} aria-label={copy.title}></canvas>
|
||||
<div class="model-vignette" aria-hidden="true"></div>
|
||||
<div class="model-scanlines" aria-hidden="true"></div>
|
||||
|
||||
<section class="model-hud" aria-label={copy.title}>
|
||||
<p class="model-kicker">{copy.subtitle}</p>
|
||||
<h2>{copy.title}</h2>
|
||||
<div class="model-status-row">
|
||||
<span class="status-light" class:is-ready={loadState === "ready"}></span>
|
||||
<span>{statusText}</span>
|
||||
</div>
|
||||
<p class="model-path">{copy.modelPath}: {modelUrl}</p>
|
||||
<p class="model-hint">{loadError || copy.hint}</p>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
@@ -365,4 +388,82 @@
|
||||
mix-blend-mode: screen;
|
||||
}
|
||||
|
||||
.model-hud {
|
||||
position: absolute;
|
||||
top: clamp(1.2rem, 2.8vw, 2.2rem);
|
||||
left: clamp(1.2rem, 2.8vw, 2.4rem);
|
||||
z-index: 2;
|
||||
display: grid;
|
||||
gap: 0.42rem;
|
||||
max-inline-size: min(22rem, 42vw);
|
||||
padding: 0.9rem 1rem 1rem;
|
||||
border: 1px solid rgb(94 231 255 / 0.24);
|
||||
border-radius: 0.7rem;
|
||||
background:
|
||||
linear-gradient(180deg, rgb(8 18 28 / 0.82), rgb(3 9 15 / 0.72)),
|
||||
radial-gradient(circle at 0 0, rgb(94 231 255 / 0.1), transparent 44%);
|
||||
box-shadow:
|
||||
inset 0 1px 0 rgb(255 255 255 / 0.06),
|
||||
0 0 28px rgb(94 231 255 / 0.08);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.model-kicker,
|
||||
.model-path,
|
||||
.model-hint {
|
||||
margin: 0;
|
||||
color: rgb(198 226 239 / 0.72);
|
||||
font-size: 0.6rem;
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
color: rgb(241 251 255 / 0.96);
|
||||
font-size: clamp(1.15rem, 1.1vw + 0.88rem, 1.72rem);
|
||||
line-height: 1.05;
|
||||
font-weight: 650;
|
||||
}
|
||||
|
||||
.model-status-row {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.44rem;
|
||||
color: rgb(229 249 255 / 0.94);
|
||||
font-size: 0.78rem;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
.status-light {
|
||||
inline-size: 0.58rem;
|
||||
block-size: 0.58rem;
|
||||
border-radius: 50%;
|
||||
background: rgb(255 188 92 / 0.95);
|
||||
box-shadow: 0 0 0 2px rgb(255 188 92 / 0.16), 0 0 12px rgb(255 188 92 / 0.18);
|
||||
}
|
||||
|
||||
.status-light.is-ready {
|
||||
background: rgb(166 255 122 / 0.95);
|
||||
box-shadow: 0 0 0 2px rgb(166 255 122 / 0.16), 0 0 14px rgb(166 255 122 / 0.22);
|
||||
}
|
||||
|
||||
.model-path {
|
||||
color: rgb(94 231 255 / 0.78);
|
||||
text-transform: none;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.model-hint {
|
||||
color: rgb(198 226 239 / 0.66);
|
||||
text-transform: none;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
@media (max-width: 960px) {
|
||||
.model-hud {
|
||||
max-inline-size: min(20rem, calc(100% - 2.4rem));
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -67,6 +67,7 @@
|
||||
const CAMERA_TARGET_Z = MATRIX_OFFSET_Z - 0.4;
|
||||
const MATRIX_ROTATION_Y = 0;
|
||||
const rangeStopPositions = [0, 0.25, 0.5, 0.75, 0.875, 1] as const;
|
||||
const maxDisplayForce = 25.6;
|
||||
|
||||
const labelVector = new THREE.Vector3();
|
||||
$: resolvedColorPalette = pressureColorPalettes[colorMapPreset] ?? pressureColorPalettes.emerald;
|
||||
@@ -145,6 +146,10 @@
|
||||
return "--";
|
||||
}
|
||||
|
||||
if (value >= maxDisplayForce) {
|
||||
return `${maxDisplayForce.toFixed(1)}+`;
|
||||
}
|
||||
|
||||
return value.toFixed(1);
|
||||
}
|
||||
|
||||
@@ -672,14 +677,6 @@
|
||||
<span class="stats-key">{viewerI18n.current}</span>
|
||||
<strong class="stats-value">{formatForceStat(stats.current)}</strong>
|
||||
</article>
|
||||
<article class="stats-card">
|
||||
<span class="stats-key">{viewerI18n.max}</span>
|
||||
<strong class="stats-value">{formatForceStat(stats.max)}</strong>
|
||||
</article>
|
||||
<article class="stats-card">
|
||||
<span class="stats-key">{viewerI18n.min}</span>
|
||||
<strong class="stats-value">{formatForceStat(stats.min)}</strong>
|
||||
</article>
|
||||
</div>
|
||||
<p class="stats-note">{statsNote}</p>
|
||||
</section>
|
||||
@@ -768,7 +765,7 @@
|
||||
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
gap: 0.46rem;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
const viewportWidth = 100;
|
||||
const viewportHeight = 36;
|
||||
const maxDisplayForce = 25.6;
|
||||
|
||||
const toneColorMap: Record<SignalTone, string> = {
|
||||
cyan: "62 232 255",
|
||||
@@ -32,7 +33,15 @@
|
||||
}
|
||||
|
||||
function formatMetric(value: number | null): string {
|
||||
return value === null ? "--" : value.toFixed(1);
|
||||
if (value === null) {
|
||||
return "--";
|
||||
}
|
||||
|
||||
if (value >= maxDisplayForce) {
|
||||
return `${maxDisplayForce.toFixed(1)}+`;
|
||||
}
|
||||
|
||||
return value.toFixed(1);
|
||||
}
|
||||
|
||||
function resolveBounds(seriesCollection: HudSignalPanel["series"]): { min: number; max: number } {
|
||||
|
||||
@@ -9,17 +9,7 @@
|
||||
export let panelTitle = "";
|
||||
export let badgeLabel = "";
|
||||
export let badgeTone: "cyan" | "lime" | "orange" = "cyan";
|
||||
export let showMetrics = true;
|
||||
export let requireMagnitude = true;
|
||||
export let compactMetaText = "";
|
||||
|
||||
function formatValue(value: number | null, digits = 1): string {
|
||||
if (value === null || !Number.isFinite(value)) {
|
||||
return "--";
|
||||
}
|
||||
|
||||
return value.toFixed(digits);
|
||||
}
|
||||
|
||||
function normalizeAngle(value: number): number {
|
||||
return ((value % 360) + 360) % 360;
|
||||
@@ -30,6 +20,7 @@
|
||||
return delta === -180 ? 180 : delta;
|
||||
}
|
||||
|
||||
const displayAngleOffsetDeg = 90;
|
||||
const jumpAngleThresholdDeg = 72;
|
||||
|
||||
let visualAngleDeg = 0;
|
||||
@@ -83,7 +74,7 @@
|
||||
$: i18n =
|
||||
locale === "zh-CN"
|
||||
? {
|
||||
title: "切向力方向",
|
||||
title: "三维力",
|
||||
waiting: "等待数据",
|
||||
angle: "ANGLE",
|
||||
heading: "方向角",
|
||||
@@ -91,7 +82,7 @@
|
||||
confidence: "置信度"
|
||||
}
|
||||
: {
|
||||
title: "Tangential Direction",
|
||||
title: "3D Force",
|
||||
waiting: "Waiting",
|
||||
angle: "ANGLE",
|
||||
heading: "Heading",
|
||||
@@ -100,23 +91,19 @@
|
||||
};
|
||||
$: resolvedTitle = panelTitle || i18n.title;
|
||||
$: resolvedBadgeLabel = badgeLabel || i18n.angle;
|
||||
$: resolvedCompactMetaText =
|
||||
compactMetaText || (locale === "zh-CN" ? "仅使用角度流" : "Angle stream only");
|
||||
|
||||
$: hasData =
|
||||
spatialForce !== null &&
|
||||
Number.isFinite(spatialForce.angleDeg) &&
|
||||
(!requireMagnitude || Number.isFinite(spatialForce.magnitude));
|
||||
$: angleDeg = hasData ? normalizeAngle(spatialForce?.angleDeg ?? 0) : 0;
|
||||
(!requireMagnitude || (Number.isFinite(spatialForce.magnitude) && Math.abs(spatialForce.magnitude) >= 0.0001));
|
||||
$: angleDeg = hasData ? normalizeAngle((spatialForce?.angleDeg ?? 0) + displayAngleOffsetDeg) : 0;
|
||||
$: updateVisualAngle(angleDeg, hasData);
|
||||
$: magnitude = hasData ? spatialForce?.magnitude ?? 0 : null;
|
||||
$: confidence = hasData ? (spatialForce?.confidence ?? 0) * 100 : null;
|
||||
</script>
|
||||
|
||||
<article
|
||||
class="signal-panel spatial-panel side-{side}"
|
||||
class:is-empty={!hasData}
|
||||
aria-hidden={false}
|
||||
aria-label={resolvedTitle}
|
||||
style="--panel-index: {panelIndex};"
|
||||
>
|
||||
<header class="panel-head">
|
||||
@@ -125,9 +112,11 @@
|
||||
<p class="panel-title">{resolvedTitle}</p>
|
||||
</div>
|
||||
|
||||
<div class="icon-layer" aria-hidden="true">
|
||||
<span class={`icon-chip tone-${badgeTone}`}>{resolvedBadgeLabel}</span>
|
||||
</div>
|
||||
{#if resolvedBadgeLabel}
|
||||
<div class="icon-layer" aria-hidden="true">
|
||||
<span class={`icon-chip tone-${badgeTone}`}>{resolvedBadgeLabel}</span>
|
||||
</div>
|
||||
{/if}
|
||||
</header>
|
||||
|
||||
<div class="panel-body">
|
||||
@@ -148,42 +137,28 @@
|
||||
</div>
|
||||
{/if}
|
||||
<div class="compass-center"></div>
|
||||
<span class="compass-label label-top">90</span>
|
||||
<span class="compass-label label-right">0</span>
|
||||
<span class="compass-label label-bottom">270</span>
|
||||
<span class="compass-label label-left">180</span>
|
||||
<span class="compass-label label-top">0</span>
|
||||
<span class="compass-label label-right">270</span>
|
||||
<span class="compass-label label-bottom">180</span>
|
||||
<span class="compass-label label-left">90</span>
|
||||
</div>
|
||||
|
||||
{#if !hasData}
|
||||
<div class="empty-state">
|
||||
<span>{i18n.waiting}</span>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="angle-stage">
|
||||
<p class="angle-label">{i18n.heading}</p>
|
||||
{#if showMetrics}
|
||||
<p class="angle-meta">{i18n.strength}: {formatValue(magnitude, 2)}</p>
|
||||
<p class="angle-meta">{i18n.confidence}: {hasData ? `${formatValue(confidence, 0)}%` : "--"}</p>
|
||||
{:else}
|
||||
<p class="angle-meta">{resolvedCompactMetaText}</p>
|
||||
<p class="angle-meta">{hasData ? (locale === "zh-CN" ? "实时对比中" : "Live comparison") : "--"}</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<style>
|
||||
.signal-panel {
|
||||
--offset-x: 12%;
|
||||
--enter-ms: 1800ms;
|
||||
--fade-ms: 1000ms;
|
||||
overflow: hidden;
|
||||
inline-size: min(100%, clamp(34rem, 44vw, 44rem));
|
||||
inline-size: var(--rail-width, min(100%, clamp(34rem, 44vw, 44rem)));
|
||||
max-inline-size: 100%;
|
||||
box-sizing: border-box;
|
||||
flex: 0 0 var(--rail-width, auto);
|
||||
justify-self: start;
|
||||
display: grid;
|
||||
grid-template-rows: auto 1fr;
|
||||
grid-template-rows: auto 1fr auto;
|
||||
gap: 0.68rem;
|
||||
padding: 0.88rem 0.96rem 1rem;
|
||||
border: 1px solid rgb(var(--hud-border-strong-rgb) / 0.42);
|
||||
@@ -218,6 +193,16 @@
|
||||
opacity: 0.82;
|
||||
}
|
||||
|
||||
.spatial-panel::after {
|
||||
content: "";
|
||||
display: block;
|
||||
block-size: 1rem;
|
||||
}
|
||||
|
||||
.spatial-panel {
|
||||
margin-block-end: clamp(0.8rem, 1.8vh, 1.4rem);
|
||||
}
|
||||
|
||||
.panel-head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@@ -277,16 +262,18 @@
|
||||
|
||||
.panel-body {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1.1fr) minmax(10rem, 0.9fr);
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
gap: 0.72rem;
|
||||
block-size: clamp(12rem, 15.5vw, 15rem);
|
||||
min-block-size: clamp(12rem, 15.5vw, 15rem);
|
||||
block-size: clamp(14rem, 17vw, 16.5rem);
|
||||
min-block-size: 5rem;
|
||||
}
|
||||
|
||||
.compass-stage {
|
||||
position: relative;
|
||||
min-block-size: 0;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
padding: 1.35rem 1.7rem;
|
||||
border: 1px solid rgb(var(--hud-border-strong-rgb) / 0.32);
|
||||
border-radius: 0.62rem;
|
||||
background:
|
||||
@@ -298,7 +285,8 @@
|
||||
|
||||
.compass-core {
|
||||
position: relative;
|
||||
inline-size: min(72%, 13rem);
|
||||
inline-size: min(72%, 12.2rem, calc(100% - 3.4rem));
|
||||
min-inline-size: 6.2rem;
|
||||
aspect-ratio: 1;
|
||||
}
|
||||
|
||||
@@ -397,26 +385,26 @@
|
||||
}
|
||||
|
||||
.label-top {
|
||||
top: -0.9rem;
|
||||
top: 0.35rem;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.label-right {
|
||||
top: 50%;
|
||||
right: -1rem;
|
||||
right: 0.42rem;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.label-bottom {
|
||||
bottom: -0.9rem;
|
||||
bottom: 0.35rem;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.label-left {
|
||||
top: 50%;
|
||||
left: -1.35rem;
|
||||
left: 0.42rem;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
@@ -433,76 +421,79 @@
|
||||
background: linear-gradient(180deg, rgb(var(--hud-surface-deep-rgb) / 0.06), rgb(var(--hud-surface-deep-rgb) / 0.18));
|
||||
}
|
||||
|
||||
.angle-stage {
|
||||
border: 1px solid rgb(var(--hud-border-rgb) / 0.26);
|
||||
border-radius: 0.62rem;
|
||||
padding: 0.9rem 0.85rem;
|
||||
block-size: 100%;
|
||||
min-block-size: 0;
|
||||
overflow: hidden;
|
||||
background:
|
||||
linear-gradient(180deg, rgb(var(--hud-surface-rgb) / 0.72), rgb(var(--hud-surface-deep-rgb) / 0.84)),
|
||||
radial-gradient(circle at 50% 0, rgb(var(--hud-glow-rgb) / 0.05), transparent 58%);
|
||||
display: grid;
|
||||
grid-template-rows: auto auto auto;
|
||||
align-content: center;
|
||||
justify-items: start;
|
||||
gap: 0.36rem;
|
||||
}
|
||||
|
||||
.angle-label {
|
||||
margin: 0;
|
||||
color: rgb(var(--hud-text-dim-rgb) / 0.82);
|
||||
font-size: 0.68rem;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.angle-meta {
|
||||
margin: 0;
|
||||
inline-size: 10rem;
|
||||
min-block-size: 1rem;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
color: rgb(var(--hud-text-dim-rgb) / 0.84);
|
||||
font-size: 0.68rem;
|
||||
font-variant-numeric: tabular-nums;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
@media (max-width: 1180px) {
|
||||
.signal-panel {
|
||||
inline-size: min(100%, clamp(28rem, 40vw, 38rem));
|
||||
inline-size: var(--rail-width, min(100%, clamp(28rem, 40vw, 38rem)));
|
||||
}
|
||||
|
||||
.panel-body {
|
||||
block-size: clamp(12rem, 14.5vw, 14rem);
|
||||
}
|
||||
|
||||
.compass-core {
|
||||
inline-size: min(64%, 10.4rem, calc(100% - 3.4rem));
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-height: 900px) {
|
||||
.signal-panel {
|
||||
inline-size: min(100%, clamp(28rem, 38vw, 36rem));
|
||||
inline-size: var(--rail-width, min(100%, clamp(28rem, 38vw, 36rem)));
|
||||
padding: 0.7rem 0.76rem 0.8rem;
|
||||
}
|
||||
|
||||
.panel-body {
|
||||
block-size: clamp(11.2rem, 13.5vw, 13.2rem);
|
||||
}
|
||||
|
||||
.compass-stage {
|
||||
padding-block: 1.2rem;
|
||||
}
|
||||
|
||||
.compass-core {
|
||||
inline-size: min(62%, 10rem, calc(100% - 3.4rem));
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-height: 760px) {
|
||||
.signal-panel {
|
||||
inline-size: min(100%, clamp(24rem, 34vw, 30rem));
|
||||
inline-size: var(--rail-width, min(100%, clamp(24rem, 34vw, 30rem)));
|
||||
padding: 0.62rem 0.68rem 0.72rem;
|
||||
gap: 0.48rem;
|
||||
}
|
||||
|
||||
.panel-body {
|
||||
block-size: clamp(9rem, 10vw, 10.8rem);
|
||||
min-block-size: clamp(9rem, 10vw, 10.8rem);
|
||||
block-size: clamp(9.4rem, 11vw, 10.8rem);
|
||||
}
|
||||
|
||||
.compass-stage {
|
||||
padding: 1rem 1.45rem;
|
||||
}
|
||||
|
||||
.compass-core {
|
||||
inline-size: min(58%, 8.2rem, calc(100% - 2.9rem));
|
||||
min-inline-size: 5.6rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-height: 680px) {
|
||||
.signal-panel {
|
||||
inline-size: min(100%, clamp(20rem, 28vw, 26rem));
|
||||
inline-size: var(--rail-width, min(100%, clamp(20rem, 28vw, 26rem)));
|
||||
padding: 0.52rem 0.58rem 0.6rem;
|
||||
gap: 0.36rem;
|
||||
}
|
||||
|
||||
.panel-body {
|
||||
block-size: clamp(7.6rem, 9vw, 8.8rem);
|
||||
}
|
||||
|
||||
.compass-stage {
|
||||
padding: 0.82rem 1.25rem;
|
||||
}
|
||||
|
||||
.compass-core {
|
||||
inline-size: min(54%, 6.4rem, calc(100% - 2.5rem));
|
||||
min-inline-size: 4.8rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
|
||||
@@ -11,15 +11,26 @@
|
||||
export let sessionStartedAt: number = Date.now();
|
||||
export let isRealtime = false;
|
||||
|
||||
let canvasEl: HTMLCanvasElement | undefined;
|
||||
let currentTimeSeconds = 0;
|
||||
let timerId: ReturnType<typeof setInterval> | null = null;
|
||||
let resizeObserver: ResizeObserver | null = null;
|
||||
|
||||
onMount(() => {
|
||||
timerId = setInterval(() => {
|
||||
currentTimeSeconds = Math.round((Date.now() - sessionStartedAt) / 100) / 10;
|
||||
}, 200);
|
||||
|
||||
if (canvasEl) {
|
||||
resizeObserver = new ResizeObserver(() => {
|
||||
drawCanvas(canvasEl, plotPoints, yAxisTicks, xAxisTicks, sampleCount);
|
||||
});
|
||||
resizeObserver.observe(canvasEl);
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (timerId != null) clearInterval(timerId);
|
||||
resizeObserver?.disconnect();
|
||||
};
|
||||
});
|
||||
|
||||
@@ -33,7 +44,8 @@
|
||||
const plotInsetRight = 4;
|
||||
const plotInsetTop = 4;
|
||||
const plotInsetBottom = 9;
|
||||
const fixedYBounds = { min: 0, max: 25 };
|
||||
const maxDisplayForce = 25.6;
|
||||
const fixedYBounds = { min: 0, max: maxDisplayForce };
|
||||
|
||||
interface CurveSample {
|
||||
x: number;
|
||||
@@ -56,14 +68,6 @@
|
||||
return Math.min(max, Math.max(min, value));
|
||||
}
|
||||
|
||||
function formatValue(value: number | null): string {
|
||||
if (value === null) {
|
||||
return "--";
|
||||
}
|
||||
|
||||
return value.toFixed(1);
|
||||
}
|
||||
|
||||
function formatAxisValue(value: number, axis: "x" | "y"): string {
|
||||
if (!Number.isFinite(value)) {
|
||||
return "--";
|
||||
@@ -225,24 +229,117 @@
|
||||
}));
|
||||
}
|
||||
|
||||
function createLinePath(points: PlotPoint[]): string {
|
||||
if (points.length === 0) {
|
||||
return "";
|
||||
function drawCanvas(
|
||||
canvas: HTMLCanvasElement | undefined,
|
||||
points: PlotPoint[],
|
||||
yTicks: AxisTick[],
|
||||
xTicks: AxisTick[],
|
||||
count: number
|
||||
): void {
|
||||
if (!canvas) {
|
||||
return;
|
||||
}
|
||||
|
||||
return points.map((point, index) => `${index === 0 ? "M" : "L"} ${point.x} ${point.y}`).join(" ");
|
||||
}
|
||||
|
||||
function createAreaPath(points: PlotPoint[]): string {
|
||||
if (points.length < 2) {
|
||||
return "";
|
||||
const context = canvas.getContext("2d");
|
||||
if (!context) {
|
||||
return;
|
||||
}
|
||||
|
||||
const linePath = createLinePath(points);
|
||||
const firstPoint = points[0];
|
||||
const lastPoint = points[points.length - 1];
|
||||
const cssWidth = Math.max(1, canvas.clientWidth);
|
||||
const cssHeight = Math.max(1, canvas.clientHeight);
|
||||
const dpr = typeof window === "undefined" ? 1 : window.devicePixelRatio || 1;
|
||||
const targetWidth = Math.round(cssWidth * dpr);
|
||||
const targetHeight = Math.round(cssHeight * dpr);
|
||||
|
||||
return `${linePath} L ${lastPoint.x} ${viewportHeight - plotInsetBottom} L ${firstPoint.x} ${viewportHeight - plotInsetBottom} Z`;
|
||||
if (canvas.width !== targetWidth || canvas.height !== targetHeight) {
|
||||
canvas.width = targetWidth;
|
||||
canvas.height = targetHeight;
|
||||
}
|
||||
|
||||
context.setTransform(targetWidth / viewportWidth, 0, 0, targetHeight / viewportHeight, 0, 0);
|
||||
context.clearRect(0, 0, viewportWidth, viewportHeight);
|
||||
|
||||
context.save();
|
||||
context.lineWidth = 0.45;
|
||||
context.strokeStyle = "rgb(120 180 150 / 0.16)";
|
||||
for (const tick of yTicks) {
|
||||
context.beginPath();
|
||||
context.moveTo(plotInsetLeft, tick.plotY);
|
||||
context.lineTo(viewportWidth - plotInsetRight, tick.plotY);
|
||||
context.stroke();
|
||||
}
|
||||
context.restore();
|
||||
|
||||
if (points.length >= 2) {
|
||||
const baselineY = viewportHeight - plotInsetBottom;
|
||||
const fill = context.createLinearGradient(0, plotInsetTop, 0, baselineY);
|
||||
fill.addColorStop(0, "rgb(62 232 255 / 0.28)");
|
||||
fill.addColorStop(1, "rgb(62 232 255 / 0.02)");
|
||||
|
||||
context.save();
|
||||
context.beginPath();
|
||||
context.moveTo(points[0].x, points[0].y);
|
||||
for (let index = 1; index < points.length; index += 1) {
|
||||
context.lineTo(points[index].x, points[index].y);
|
||||
}
|
||||
context.lineTo(points[points.length - 1].x, baselineY);
|
||||
context.lineTo(points[0].x, baselineY);
|
||||
context.closePath();
|
||||
context.fillStyle = fill;
|
||||
context.fill();
|
||||
context.restore();
|
||||
}
|
||||
|
||||
if (points.length > 0) {
|
||||
context.save();
|
||||
context.beginPath();
|
||||
context.moveTo(points[0].x, points[0].y);
|
||||
for (let index = 1; index < points.length; index += 1) {
|
||||
context.lineTo(points[index].x, points[index].y);
|
||||
}
|
||||
context.lineWidth = 1.35;
|
||||
context.lineCap = "round";
|
||||
context.lineJoin = "round";
|
||||
context.strokeStyle = "rgb(130 232 255 / 0.96)";
|
||||
context.shadowColor = "rgb(62 232 255 / 0.22)";
|
||||
context.shadowBlur = 4;
|
||||
context.stroke();
|
||||
context.restore();
|
||||
|
||||
const lastPoint = points[points.length - 1];
|
||||
context.save();
|
||||
context.beginPath();
|
||||
context.arc(lastPoint.x, lastPoint.y, 1.7, 0, Math.PI * 2);
|
||||
context.fillStyle = "rgb(73 222 128 / 0.98)";
|
||||
context.shadowColor = "rgb(73 222 128 / 0.3)";
|
||||
context.shadowBlur = 6;
|
||||
context.fill();
|
||||
context.restore();
|
||||
}
|
||||
|
||||
context.save();
|
||||
context.font = "600 3.2px sans-serif";
|
||||
context.textBaseline = "middle";
|
||||
context.shadowColor = "rgb(0 0 0 / 0.3)";
|
||||
context.shadowBlur = 4;
|
||||
context.fillStyle = "rgb(145 185 165 / 0.84)";
|
||||
for (const tick of yTicks) {
|
||||
context.textAlign = "right";
|
||||
context.fillText(tick.label, tick.plotX, tick.plotY + 0.5);
|
||||
}
|
||||
|
||||
context.fillStyle = "rgb(180 220 200 / 0.9)";
|
||||
context.textBaseline = "alphabetic";
|
||||
for (let index = 0; index < xTicks.length; index += 1) {
|
||||
const tick = xTicks[index];
|
||||
context.textAlign = index === 0 ? "left" : index === xTicks.length - 1 ? "right" : "center";
|
||||
context.fillText(tick.label, tick.plotX, tick.plotY);
|
||||
}
|
||||
context.restore();
|
||||
|
||||
if (count === 0) {
|
||||
context.clearRect(0, 0, viewportWidth, viewportHeight);
|
||||
}
|
||||
}
|
||||
|
||||
$: sourceYValues = yValues && yValues.length ? yValues : summary.points;
|
||||
@@ -261,14 +358,9 @@
|
||||
$: xDataBounds = resolveDataBounds(samples.map((sample) => sample.x));
|
||||
$: yDataBounds = resolveDataBounds(samples.map((sample) => sample.y));
|
||||
$: plotPoints = convertPoints(samples, xScaleBounds, yScaleBounds);
|
||||
$: linePath = createLinePath(plotPoints);
|
||||
$: areaPath = createAreaPath(plotPoints);
|
||||
$: lastPoint = plotPoints.length > 0 ? plotPoints[plotPoints.length - 1] : null;
|
||||
$: yAxisTicks = sampleCount > 0 ? buildYAxisTicks(yScaleBounds, yDataBounds) : [];
|
||||
$: xAxisTicks = sampleCount > 0 ? buildXAxisTicks(xScaleBounds) : [];
|
||||
$: latestValue = formatValue(summary.latest);
|
||||
$: minValue = formatValue(summary.min);
|
||||
$: maxValue = formatValue(summary.max);
|
||||
$: drawCanvas(canvasEl, plotPoints, yAxisTicks, xAxisTicks, sampleCount);
|
||||
</script>
|
||||
|
||||
<article
|
||||
@@ -280,62 +372,12 @@
|
||||
<header class="panel-head">
|
||||
<div class="head-text">
|
||||
<p class="panel-code">RF</p>
|
||||
<p class="panel-title">{summary.label}</p>
|
||||
</div>
|
||||
|
||||
<div class="icon-layer" aria-hidden="true">
|
||||
<span class="icon-chip tone-cyan">NOW</span>
|
||||
<span class="icon-chip tone-lime">MIN</span>
|
||||
<span class="icon-chip tone-orange">MAX</span>
|
||||
<p class="panel-title">{locale === "zh-CN" ? "合力" : "Resultant Force"}</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="chart-stage">
|
||||
<svg viewBox="0 0 {viewportWidth} {viewportHeight}" preserveAspectRatio="none" role="img" aria-label={summary.label}>
|
||||
<defs>
|
||||
<linearGradient id="summary-fill" x1="0%" y1="0%" x2="0%" y2="100%">
|
||||
<stop offset="0%" stop-color="rgb(62 232 255 / 0.28)" />
|
||||
<stop offset="100%" stop-color="rgb(62 232 255 / 0.02)" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
|
||||
<g class="grid-lines" aria-hidden="true">
|
||||
{#each yAxisTicks as tick (`grid-${tick.value}`)}
|
||||
<line x1={plotInsetLeft} y1={tick.plotY} x2={viewportWidth - plotInsetRight} y2={tick.plotY}></line>
|
||||
{/each}
|
||||
</g>
|
||||
|
||||
{#if areaPath}
|
||||
<path d={areaPath} class="summary-area"></path>
|
||||
{/if}
|
||||
|
||||
{#if linePath}
|
||||
<path d={linePath} class="summary-line"></path>
|
||||
{/if}
|
||||
|
||||
{#if lastPoint}
|
||||
<circle cx={lastPoint.x} cy={lastPoint.y} r="1.7" class="summary-dot"></circle>
|
||||
{/if}
|
||||
|
||||
<g class="axis-labels" aria-hidden="true">
|
||||
{#each yAxisTicks as tick, index (`y-${index}`)}
|
||||
<text class="axis-label y-axis-label" x={tick.plotX} y={tick.plotY + 1.1} text-anchor="end">
|
||||
{tick.label}
|
||||
</text>
|
||||
{/each}
|
||||
|
||||
{#each xAxisTicks as tick, index (`x-${index}`)}
|
||||
<text
|
||||
class="axis-label x-axis-label"
|
||||
x={tick.plotX}
|
||||
y={tick.plotY}
|
||||
text-anchor={index === 0 ? "start" : index === xAxisTicks.length - 1 ? "end" : "middle"}
|
||||
>
|
||||
{tick.label}
|
||||
</text>
|
||||
{/each}
|
||||
</g>
|
||||
</svg>
|
||||
<canvas bind:this={canvasEl} aria-label={summary.label}></canvas>
|
||||
|
||||
{#if sampleCount === 0}
|
||||
<div class="empty-state">
|
||||
@@ -343,24 +385,6 @@
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<footer class="panel-foot">
|
||||
<p class="foot-item">
|
||||
<span class="dot tone-cyan"></span>
|
||||
<span class="metric-text">{i18n.now}</span>
|
||||
<span class="value">{latestValue}</span>
|
||||
</p>
|
||||
<p class="foot-item">
|
||||
<span class="dot tone-lime"></span>
|
||||
<span class="metric-text">{i18n.min}</span>
|
||||
<span class="value">{minValue}</span>
|
||||
</p>
|
||||
<p class="foot-item">
|
||||
<span class="dot tone-orange"></span>
|
||||
<span class="metric-text">{i18n.max}</span>
|
||||
<span class="value">{maxValue}</span>
|
||||
</p>
|
||||
</footer>
|
||||
</article>
|
||||
|
||||
<style>
|
||||
@@ -369,10 +393,13 @@
|
||||
--enter-ms: 1800ms;
|
||||
--fade-ms: 1000ms;
|
||||
overflow: hidden;
|
||||
inline-size: min(100%, clamp(34rem, 44vw, 44rem));
|
||||
inline-size: var(--rail-width, min(100%, clamp(34rem, 44vw, 44rem)));
|
||||
max-inline-size: 100%;
|
||||
box-sizing: border-box;
|
||||
flex: 0 0 var(--rail-width, auto);
|
||||
justify-self: start;
|
||||
display: grid;
|
||||
grid-template-rows: auto 1fr auto;
|
||||
grid-template-rows: auto 1fr;
|
||||
gap: 0.68rem;
|
||||
padding: 0.88rem 0.96rem 1rem;
|
||||
border: 1px solid rgb(var(--hud-border-strong-rgb) / 0.42);
|
||||
@@ -438,36 +465,6 @@
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.icon-layer {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 0.26rem;
|
||||
}
|
||||
|
||||
.icon-chip {
|
||||
border: 1px solid rgb(var(--hud-border-strong-rgb) / 0.44);
|
||||
border-radius: 999px;
|
||||
padding: 0.08rem 0.36rem;
|
||||
font-size: 0.58rem;
|
||||
letter-spacing: 0.08em;
|
||||
color: rgb(var(--hud-text-main-rgb) / 0.94);
|
||||
background: rgb(var(--hud-surface-rgb) / 0.66);
|
||||
}
|
||||
|
||||
.icon-chip.tone-cyan {
|
||||
border-color: rgb(var(--hud-cyan-rgb) / 0.54);
|
||||
}
|
||||
|
||||
.icon-chip.tone-lime {
|
||||
border-color: rgb(var(--hud-lime-rgb) / 0.56);
|
||||
}
|
||||
|
||||
.icon-chip.tone-orange {
|
||||
border-color: rgb(var(--hud-orange-rgb) / 0.58);
|
||||
}
|
||||
|
||||
.chart-stage {
|
||||
position: relative;
|
||||
block-size: clamp(12rem, 15.5vw, 15rem);
|
||||
@@ -480,53 +477,12 @@
|
||||
radial-gradient(circle at 50% 0, rgb(var(--hud-glow-rgb) / 0.09), transparent 45%);
|
||||
}
|
||||
|
||||
svg {
|
||||
canvas {
|
||||
display: block;
|
||||
inline-size: 100%;
|
||||
block-size: 100%;
|
||||
}
|
||||
|
||||
.grid-lines line {
|
||||
stroke: rgb(var(--hud-border-strong-rgb) / 0.16);
|
||||
stroke-width: 0.45;
|
||||
}
|
||||
|
||||
.summary-area {
|
||||
fill: url(#summary-fill);
|
||||
}
|
||||
|
||||
.summary-line {
|
||||
fill: none;
|
||||
stroke: rgb(var(--hud-cyan-rgb) / 0.96);
|
||||
stroke-width: 1.35;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
filter: drop-shadow(0 0 4px rgb(var(--hud-cyan-rgb) / 0.22));
|
||||
}
|
||||
|
||||
.summary-dot {
|
||||
fill: rgb(var(--hud-lime-rgb) / 0.98);
|
||||
filter: drop-shadow(0 0 6px rgb(var(--hud-lime-rgb) / 0.3));
|
||||
}
|
||||
|
||||
.axis-label {
|
||||
fill: rgb(var(--hud-text-main-rgb) / 0.88);
|
||||
font-size: 3.2px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.02em;
|
||||
text-shadow:
|
||||
0 1px 0 rgb(0 0 0 / 0.46),
|
||||
0 0 4px rgb(0 0 0 / 0.3);
|
||||
}
|
||||
|
||||
.y-axis-label {
|
||||
fill: rgb(var(--hud-text-dim-rgb) / 0.84);
|
||||
}
|
||||
|
||||
.x-axis-label {
|
||||
fill: rgb(var(--hud-text-dim-rgb) / 0.9);
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
@@ -540,58 +496,9 @@
|
||||
background: linear-gradient(180deg, rgb(var(--hud-surface-deep-rgb) / 0.06), rgb(var(--hud-surface-deep-rgb) / 0.18));
|
||||
}
|
||||
|
||||
.panel-foot {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
gap: 0.8rem;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.foot-item {
|
||||
margin: 0;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.22rem;
|
||||
color: rgb(var(--hud-text-main-rgb) / 0.9);
|
||||
font-size: 0.68rem;
|
||||
letter-spacing: 0.03em;
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.metric-text {
|
||||
color: rgb(var(--hud-text-dim-rgb) / 0.82);
|
||||
text-transform: uppercase;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
inline-size: 0.34rem;
|
||||
block-size: 0.34rem;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.dot.tone-cyan {
|
||||
background: rgb(var(--hud-cyan-rgb));
|
||||
}
|
||||
|
||||
.dot.tone-lime {
|
||||
background: rgb(var(--hud-lime-rgb));
|
||||
}
|
||||
|
||||
.dot.tone-orange {
|
||||
background: rgb(var(--hud-orange-rgb));
|
||||
}
|
||||
|
||||
.value {
|
||||
min-inline-size: 2.6rem;
|
||||
}
|
||||
|
||||
@media (max-width: 1180px) {
|
||||
.signal-panel {
|
||||
inline-size: min(100%, clamp(28rem, 40vw, 38rem));
|
||||
inline-size: var(--rail-width, min(100%, clamp(28rem, 40vw, 38rem)));
|
||||
}
|
||||
|
||||
.chart-stage {
|
||||
@@ -601,7 +508,7 @@
|
||||
|
||||
@media (max-height: 900px) {
|
||||
.signal-panel {
|
||||
inline-size: min(100%, clamp(28rem, 38vw, 36rem));
|
||||
inline-size: var(--rail-width, min(100%, clamp(28rem, 38vw, 36rem)));
|
||||
padding: 0.7rem 0.76rem 0.8rem;
|
||||
}
|
||||
|
||||
@@ -612,7 +519,7 @@
|
||||
|
||||
@media (max-height: 760px) {
|
||||
.signal-panel {
|
||||
inline-size: min(100%, clamp(24rem, 34vw, 30rem));
|
||||
inline-size: var(--rail-width, min(100%, clamp(24rem, 34vw, 30rem)));
|
||||
padding: 0.62rem 0.68rem 0.72rem;
|
||||
gap: 0.48rem;
|
||||
}
|
||||
@@ -624,7 +531,7 @@
|
||||
|
||||
@media (max-height: 680px) {
|
||||
.signal-panel {
|
||||
inline-size: min(100%, clamp(20rem, 28vw, 26rem));
|
||||
inline-size: var(--rail-width, min(100%, clamp(20rem, 28vw, 26rem)));
|
||||
padding: 0.52rem 0.58rem 0.6rem;
|
||||
gap: 0.36rem;
|
||||
}
|
||||
|
||||
@@ -14,8 +14,6 @@ export type MatrixDisplayMode = "numeric" | "dots";
|
||||
|
||||
export type SignalPanelSide = "left" | "right";
|
||||
|
||||
export type HudConfigTone = "neutral" | "cyan" | "lime" | "orange";
|
||||
|
||||
export interface HudSignalSeries {
|
||||
id: string;
|
||||
tone: SignalTone;
|
||||
@@ -64,13 +62,6 @@ export interface HudSummary {
|
||||
max: number | null;
|
||||
}
|
||||
|
||||
export interface HudConfigLink {
|
||||
id: string;
|
||||
label: string;
|
||||
tone?: HudConfigTone;
|
||||
active?: boolean;
|
||||
}
|
||||
|
||||
export interface HudColorMapOption {
|
||||
id: PressureColorMapPreset;
|
||||
label: string;
|
||||
@@ -107,7 +98,6 @@ export interface HudCopy {
|
||||
deviceLabel: string;
|
||||
sampleRateLabel: string;
|
||||
channelsLabel: string;
|
||||
configLinksLabel: string;
|
||||
refreshPortsLabel: string;
|
||||
connectActionLabel: string;
|
||||
disconnectActionLabel: string;
|
||||
@@ -169,6 +159,7 @@ export interface SerialRecordStateResult {
|
||||
export interface SerialImportFrameResult {
|
||||
data: number[];
|
||||
dtsMs: number;
|
||||
spatialForce: HudSpatialForce | null;
|
||||
}
|
||||
|
||||
export interface SerialImportResult {
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
FileExplorerRoot,
|
||||
HudColorMapOption,
|
||||
HudCopy,
|
||||
HudConfigLink,
|
||||
HudNoticeTone,
|
||||
HudPacket,
|
||||
HudSpatialForce,
|
||||
@@ -28,7 +27,6 @@
|
||||
HudSignalSeries,
|
||||
HudSummary,
|
||||
LocaleCode,
|
||||
MatrixDisplayMode,
|
||||
SerialConnectResult,
|
||||
SerialExportResult,
|
||||
SerialRecordStateResult,
|
||||
@@ -44,6 +42,7 @@
|
||||
interface ReplayFrame {
|
||||
values: number[];
|
||||
dtsMs: number;
|
||||
spatialForce?: HudSpatialForce | null;
|
||||
}
|
||||
|
||||
interface DevKitPztAngleEvent {
|
||||
@@ -51,6 +50,20 @@
|
||||
timestampMs: number;
|
||||
dtsMs: number;
|
||||
angle: number;
|
||||
magnitude: number;
|
||||
state: number;
|
||||
copX: number;
|
||||
copY: number;
|
||||
baseX: number;
|
||||
baseY: number;
|
||||
totalPress: number;
|
||||
threshold: number;
|
||||
}
|
||||
|
||||
interface DevKitReplayFramePushResult {
|
||||
seq: number;
|
||||
timestampMs: number;
|
||||
dtsMs: number;
|
||||
}
|
||||
|
||||
const copyByLocale: Record<LocaleCode, HudCopy> = {
|
||||
@@ -69,7 +82,7 @@
|
||||
rangeMaxLabel: "最大值",
|
||||
colorMapLabel: "映射颜色",
|
||||
matrixViewLabel: "矩阵模式",
|
||||
matrixViewNumericLabel: "数字矩阵",
|
||||
matrixViewNumericLabel: "数字模式",
|
||||
matrixViewDotsLabel: "点矩阵",
|
||||
stageModeLabel: "渲染模式",
|
||||
stageModeWebglLabel: "WebGL",
|
||||
@@ -84,7 +97,6 @@
|
||||
deviceLabel: "设备",
|
||||
sampleRateLabel: "采样率",
|
||||
channelsLabel: "通道",
|
||||
configLinksLabel: "配置链接",
|
||||
refreshPortsLabel: "刷新",
|
||||
connectActionLabel: "连接",
|
||||
disconnectActionLabel: "断开",
|
||||
@@ -146,7 +158,6 @@
|
||||
deviceLabel: "Device",
|
||||
sampleRateLabel: "Sample Rate",
|
||||
channelsLabel: "Channels",
|
||||
configLinksLabel: "Config Links",
|
||||
refreshPortsLabel: "Refresh",
|
||||
connectActionLabel: "Connect",
|
||||
disconnectActionLabel: "Disconnect",
|
||||
@@ -183,6 +194,9 @@
|
||||
const pointsPerSeries = 28;
|
||||
const summaryPointsPerSeries = 42;
|
||||
const signalRenderTickMs = 1200;
|
||||
const summaryReleaseForceEpsilon = 0.1;
|
||||
const releaseClearDelayMs = 5000;
|
||||
const spatialForceMagnitudeEpsilon = 0.0001;
|
||||
const replayDefaultFrameMs = 40;
|
||||
const showSignalPanels = false;
|
||||
const mockToneCycle: SignalTone[] = ["cyan", "lime", "orange", "violet", "gold", "rose"];
|
||||
@@ -229,9 +243,6 @@
|
||||
let sampleRateValue = "100Hz";
|
||||
let channelsValue = "84";
|
||||
let isWindowMaximized = false;
|
||||
let activeConfigLinkId = "stream-on";
|
||||
let isConfigPanelOpen = false;
|
||||
let isPrecisionTestOpen = false;
|
||||
let hasSignalData = false;
|
||||
let signalPanels: HudSignalPanel[] = buildInactivePanels();
|
||||
let summary: HudSummary = buildEmptySummary();
|
||||
@@ -243,7 +254,6 @@
|
||||
let rangeMin = DEFAULT_PRESSURE_RANGE_MIN;
|
||||
let rangeMax = DEFAULT_PRESSURE_RANGE_MAX;
|
||||
let colorMapPreset: PressureColorMapPreset = "emerald";
|
||||
let matrixDisplayMode: MatrixDisplayMode = "dots";
|
||||
let stageViewMode: StageViewMode = "webgl";
|
||||
let replayFrames: ReplayFrame[] = [];
|
||||
let replayCurrentIndex = 0;
|
||||
@@ -253,6 +263,8 @@
|
||||
let replayProgress = 0;
|
||||
let replayFileName = "";
|
||||
let replayTimerId: number | null = null;
|
||||
let replayPendingDevkitSeq: number | null = null;
|
||||
let replayDevkitSeqCounter = 0;
|
||||
let fileExplorerOpen = false;
|
||||
let fileExplorerMode: FileExplorerMode = "open";
|
||||
let fileExplorerBusy = false;
|
||||
@@ -279,17 +291,14 @@
|
||||
} | null = null;
|
||||
let devkitStatusTimer: number | null = null;
|
||||
let devkitSpatialForceClearTimer: number | null = null;
|
||||
let summaryClearTimer: number | null = null;
|
||||
let spatialForceClearTimer: number | null = null;
|
||||
let summaryReleaseHidden = true;
|
||||
let spatialForceReleaseHidden = false;
|
||||
let spatialForcePanelVisible = false;
|
||||
let sessionStartedAt: number = Date.now();
|
||||
|
||||
$: uiCopy = copyByLocale[locale];
|
||||
$: configLinks = buildConfigLinks(
|
||||
locale,
|
||||
activeConfigLinkId,
|
||||
isConfigPanelOpen,
|
||||
isPrecisionTestOpen,
|
||||
devkitEnabled,
|
||||
isDevKitConfigOpen
|
||||
);
|
||||
$: leftSignalPanels = signalPanels.filter((panel) => panel.side === "left");
|
||||
$: rightSignalPanels = signalPanels.filter((panel) => panel.side === "right");
|
||||
$: rangeTicks = buildRangeTicks(rangeMin, rangeMax);
|
||||
@@ -297,6 +306,7 @@
|
||||
$: rangeScaleStyle = buildRangeScaleStyle(colorMapPreset);
|
||||
$: replayHasData = replayFrames.length > 0;
|
||||
$: replayFrameInfo = replayHasData ? `${replayHasDisplayedFrame ? replayCurrentIndex + 1 : 0}/${replayFrames.length}` : "";
|
||||
$: summaryReleasePending = summaryClearTimer != null;
|
||||
$: fileExplorerTitle =
|
||||
fileExplorerMode === "open" ? uiCopy.fileExplorerImportTitle : uiCopy.fileExplorerExportTitle;
|
||||
$: fileExplorerConfirmLabel =
|
||||
@@ -306,17 +316,17 @@
|
||||
return typeof window !== "undefined" && "__TAURI_INTERNALS__" in window;
|
||||
}
|
||||
|
||||
function serialProtocolForStage(mode: StageViewMode = stageViewMode): "tactileA" | "handGateway" {
|
||||
return mode === "model3d" ? "handGateway" : "tactileA";
|
||||
}
|
||||
|
||||
function clearDevkitSpatialForce(): void {
|
||||
devkitSpatialForce = null;
|
||||
if (devkitSpatialForceClearTimer != null && typeof window !== "undefined") {
|
||||
window.clearTimeout(devkitSpatialForceClearTimer);
|
||||
devkitSpatialForceClearTimer = null;
|
||||
}
|
||||
hasSignalData = signalPanels.length > 0 || summary.points.length > 0 || spatialForce !== null;
|
||||
hasSignalData =
|
||||
signalPanels.length > 0 ||
|
||||
summary.points.length > 0 ||
|
||||
spatialForce !== null ||
|
||||
spatialForcePanelVisible;
|
||||
}
|
||||
|
||||
function scheduleDevkitSpatialForceClear(): void {
|
||||
@@ -335,6 +345,54 @@
|
||||
}, 420);
|
||||
}
|
||||
|
||||
function cancelSummaryClear(): void {
|
||||
if (summaryClearTimer != null && typeof window !== "undefined") {
|
||||
window.clearTimeout(summaryClearTimer);
|
||||
}
|
||||
summaryClearTimer = null;
|
||||
}
|
||||
|
||||
function scheduleSummaryClear(): void {
|
||||
if (typeof window === "undefined" || summary.points.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (summaryClearTimer != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
summaryClearTimer = window.setTimeout(() => {
|
||||
summary = buildEmptySummary();
|
||||
summaryClearTimer = null;
|
||||
summaryReleaseHidden = true;
|
||||
hasSignalData = signalPanels.length > 0 || spatialForce !== null || spatialForcePanelVisible;
|
||||
}, releaseClearDelayMs);
|
||||
}
|
||||
|
||||
function cancelSpatialForceClear(): void {
|
||||
if (spatialForceClearTimer != null && typeof window !== "undefined") {
|
||||
window.clearTimeout(spatialForceClearTimer);
|
||||
}
|
||||
spatialForceClearTimer = null;
|
||||
}
|
||||
|
||||
function scheduleSpatialForceClear(): void {
|
||||
if (typeof window === "undefined" || !spatialForcePanelVisible) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (spatialForceClearTimer != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
spatialForceClearTimer = window.setTimeout(() => {
|
||||
spatialForceClearTimer = null;
|
||||
spatialForceReleaseHidden = true;
|
||||
spatialForcePanelVisible = false;
|
||||
hasSignalData = signalPanels.length > 0 || summary.points.length > 0 || spatialForce !== null;
|
||||
}, releaseClearDelayMs);
|
||||
}
|
||||
|
||||
function clamp(value: number, min: number, max: number): number {
|
||||
return Math.min(max, Math.max(min, value));
|
||||
}
|
||||
@@ -687,7 +745,8 @@
|
||||
});
|
||||
frames = result.frames.map((frame) => ({
|
||||
values: frame.data,
|
||||
dtsMs: frame.dtsMs
|
||||
dtsMs: frame.dtsMs,
|
||||
spatialForce: frame.spatialForce
|
||||
}));
|
||||
importedFrameCount = result.frameCount;
|
||||
importedChannelCount = result.channelCount;
|
||||
@@ -717,7 +776,8 @@
|
||||
|
||||
const frames = result.frames.map((frame) => ({
|
||||
values: frame.data,
|
||||
dtsMs: frame.dtsMs
|
||||
dtsMs: frame.dtsMs,
|
||||
spatialForce: frame.spatialForce
|
||||
}));
|
||||
|
||||
applyImportedFrames(result.fileName, frames, result.frameCount, result.channelCount);
|
||||
@@ -738,6 +798,43 @@
|
||||
replayTimerId = null;
|
||||
}
|
||||
|
||||
function buildReplayDevkitSeq(frameIndex: number): number {
|
||||
replayDevkitSeqCounter = (replayDevkitSeqCounter + 1) % 1000;
|
||||
return Date.now() * 1000 + replayDevkitSeqCounter + frameIndex;
|
||||
}
|
||||
|
||||
function canPushReplayFrameToDevkit(frame: ReplayFrame): boolean {
|
||||
return (
|
||||
isTauriRuntime() &&
|
||||
devkitEnabled &&
|
||||
devkitRunning &&
|
||||
frame.values.length === 84
|
||||
);
|
||||
}
|
||||
|
||||
function pushReplayFrameToDevkit(frame: ReplayFrame, frameIndex: number): void {
|
||||
if (!canPushReplayFrameToDevkit(frame)) {
|
||||
replayPendingDevkitSeq = null;
|
||||
clearDevkitSpatialForce();
|
||||
return;
|
||||
}
|
||||
|
||||
const seq = buildReplayDevkitSeq(frameIndex);
|
||||
replayPendingDevkitSeq = seq;
|
||||
clearDevkitSpatialForce();
|
||||
|
||||
void invoke<DevKitReplayFramePushResult>("devkit_push_replay_frame", {
|
||||
values: frame.values.map((value) => Math.max(0, Math.round(Number(value) || 0))),
|
||||
dtsMs: clamp(Math.round(frame.dtsMs), 0, 4_294_967_295),
|
||||
seq
|
||||
}).catch((error) => {
|
||||
if (replayPendingDevkitSeq === seq) {
|
||||
replayPendingDevkitSeq = null;
|
||||
}
|
||||
console.error("Failed to push replay frame to DevKit:", error);
|
||||
});
|
||||
}
|
||||
|
||||
function frameValuesToMatrix(values: number[]): number[] {
|
||||
const totalCells = Math.max(matrixRows * matrixCols, 1);
|
||||
const matrix = new Array<number>(totalCells).fill(0);
|
||||
@@ -756,8 +853,13 @@
|
||||
}
|
||||
|
||||
function resetReplayVisualState(): void {
|
||||
cancelSummaryClear();
|
||||
cancelSpatialForceClear();
|
||||
spatialForceReleaseHidden = false;
|
||||
spatialForcePanelVisible = false;
|
||||
pressureMatrix = buildZeroMatrix();
|
||||
spatialForce = null;
|
||||
replayPendingDevkitSeq = null;
|
||||
clearDevkitSpatialForce();
|
||||
signalPanels = buildInactivePanels();
|
||||
summary = buildEmptySummary();
|
||||
@@ -793,9 +895,14 @@
|
||||
replayCurrentIndex = safeIndex;
|
||||
replayHasDisplayedFrame = true;
|
||||
replayProgress = replayFrames.length > 1 ? safeIndex / (replayFrames.length - 1) : 1;
|
||||
pressureMatrix = frameValuesToMatrix(replayFrames[safeIndex].values);
|
||||
spatialForce = null;
|
||||
clearDevkitSpatialForce();
|
||||
const frame = replayFrames[safeIndex];
|
||||
cancelSummaryClear();
|
||||
cancelSpatialForceClear();
|
||||
spatialForceReleaseHidden = false;
|
||||
pressureMatrix = frameValuesToMatrix(frame.values);
|
||||
spatialForce = frame.spatialForce ?? null;
|
||||
spatialForcePanelVisible = spatialForce !== null;
|
||||
pushReplayFrameToDevkit(frame, safeIndex);
|
||||
signalPanels = buildInactivePanels();
|
||||
summary = buildReplaySummaryAt(safeIndex);
|
||||
hasSignalData = true;
|
||||
@@ -964,13 +1071,99 @@
|
||||
}
|
||||
|
||||
function isZeroLikeValue(value: number): boolean {
|
||||
return !Number.isFinite(value) || Math.abs(value) < 0.0001;
|
||||
return !Number.isFinite(value) || Math.abs(value) <= summaryReleaseForceEpsilon;
|
||||
}
|
||||
|
||||
function shouldHideSummary(points: number[]): boolean {
|
||||
return points.length === 0 || points.every((value) => isZeroLikeValue(value));
|
||||
}
|
||||
|
||||
function latestSummaryValue(summaryValue: HudSummary): number | null {
|
||||
if (Number.isFinite(summaryValue.latest)) {
|
||||
return summaryValue.latest;
|
||||
}
|
||||
|
||||
const latestPoint = summaryValue.points[summaryValue.points.length - 1];
|
||||
return Number.isFinite(latestPoint) ? latestPoint : null;
|
||||
}
|
||||
|
||||
function hasActiveSummary(summaryValue: HudSummary): boolean {
|
||||
const latest = latestSummaryValue(summaryValue);
|
||||
return latest !== null && !isZeroLikeValue(latest);
|
||||
}
|
||||
|
||||
function hasActiveSpatialForce(spatialForceValue: HudSpatialForce | null): boolean {
|
||||
return (
|
||||
spatialForceValue !== null &&
|
||||
Number.isFinite(spatialForceValue.angleDeg) &&
|
||||
Number.isFinite(spatialForceValue.magnitude) &&
|
||||
Math.abs(spatialForceValue.magnitude) > spatialForceMagnitudeEpsilon
|
||||
);
|
||||
}
|
||||
|
||||
function buildPacketSummary(summaryValue: HudSummary): HudSummary {
|
||||
const nowSeconds = Math.round((Date.now() - sessionStartedAt) / 100) / 10;
|
||||
const pointCount = summaryValue.points.length;
|
||||
const spacing =
|
||||
pointCount > 1 ? Math.min(1.2, nowSeconds / Math.max(pointCount - 1, 1)) : 0;
|
||||
const startX = Math.max(0, nowSeconds - spacing * Math.max(pointCount - 1, 0));
|
||||
const xValues = summaryValue.points.map((_, index) => Math.round((startX + index * spacing) * 10) / 10);
|
||||
return { ...summaryValue, xValues };
|
||||
}
|
||||
|
||||
function estimateSummarySpacing(xValues: number[]): number {
|
||||
const diffs = xValues
|
||||
.slice(1)
|
||||
.map((value, index) => value - xValues[index])
|
||||
.filter((value) => Number.isFinite(value) && value > 0);
|
||||
|
||||
if (diffs.length === 0) {
|
||||
return 1.2;
|
||||
}
|
||||
|
||||
const average = diffs.reduce((sum, value) => sum + value, 0) / diffs.length;
|
||||
return Math.max(0.1, Math.min(1.2, Math.round(average * 10) / 10));
|
||||
}
|
||||
|
||||
function buildContinuousSummary(summaryValue: HudSummary): HudSummary {
|
||||
if (
|
||||
summary.points.length === 0 ||
|
||||
!summary.xValues ||
|
||||
summary.xValues.length !== summary.points.length
|
||||
) {
|
||||
return buildPacketSummary(summaryValue);
|
||||
}
|
||||
|
||||
const pointCount = summaryValue.points.length;
|
||||
const previousXValues = summary.xValues;
|
||||
const previousCount = previousXValues.length;
|
||||
|
||||
if (pointCount === 0) {
|
||||
return buildEmptySummary();
|
||||
}
|
||||
|
||||
if (pointCount < previousCount) {
|
||||
return buildPacketSummary(summaryValue);
|
||||
}
|
||||
|
||||
const spacing = estimateSummarySpacing(previousXValues);
|
||||
let xValues: number[];
|
||||
|
||||
if (pointCount > previousCount) {
|
||||
xValues = previousXValues.slice();
|
||||
while (xValues.length < pointCount) {
|
||||
const previousX = xValues[xValues.length - 1] ?? 0;
|
||||
xValues.push(Math.round((previousX + spacing) * 10) / 10);
|
||||
}
|
||||
} else {
|
||||
xValues = previousXValues.slice(1);
|
||||
const previousX = previousXValues[previousXValues.length - 1] ?? 0;
|
||||
xValues.push(Math.round((previousX + spacing) * 10) / 10);
|
||||
}
|
||||
|
||||
return { ...summaryValue, xValues };
|
||||
}
|
||||
|
||||
function normalizeSummary(summaryValue: HudSummary): HudSummary {
|
||||
return shouldHideSummary(summaryValue.points) ? buildEmptySummary() : summaryValue;
|
||||
}
|
||||
@@ -1038,27 +1231,48 @@
|
||||
return;
|
||||
}
|
||||
signalPanels = showSignalPanels ? packet.panels : buildInactivePanels();
|
||||
const packetHasActiveSummary = hasActiveSummary(packet.summary);
|
||||
if (packet.summary.points.length > 0) {
|
||||
const nowSeconds = Math.round((Date.now() - sessionStartedAt) / 100) / 10;
|
||||
const pointCount = packet.summary.points.length;
|
||||
const spacing =
|
||||
pointCount > 1 ? Math.min(1.2, nowSeconds / Math.max(pointCount - 1, 1)) : 0;
|
||||
const startX = Math.max(0, nowSeconds - spacing * Math.max(pointCount - 1, 0));
|
||||
const xValues = packet.summary.points.map((_, index) => Math.round((startX + index * spacing) * 10) / 10);
|
||||
summary = { ...packet.summary, xValues };
|
||||
} else {
|
||||
summary = packet.summary;
|
||||
if (packetHasActiveSummary) {
|
||||
summaryReleaseHidden = false;
|
||||
summary = buildContinuousSummary(packet.summary);
|
||||
cancelSummaryClear();
|
||||
} else if (summaryReleaseHidden) {
|
||||
summary = buildEmptySummary();
|
||||
} else {
|
||||
summary = buildContinuousSummary(packet.summary);
|
||||
scheduleSummaryClear();
|
||||
}
|
||||
} else if (!summaryReleaseHidden) {
|
||||
scheduleSummaryClear();
|
||||
}
|
||||
pressureMatrix = packet.pressureMatrix;
|
||||
spatialForce = packet.spatialForce ?? null;
|
||||
const nextSpatialForce = packet.spatialForce ?? null;
|
||||
if (packetHasActiveSummary && hasActiveSpatialForce(nextSpatialForce)) {
|
||||
spatialForceReleaseHidden = false;
|
||||
spatialForcePanelVisible = true;
|
||||
spatialForce = nextSpatialForce;
|
||||
cancelSpatialForceClear();
|
||||
} else {
|
||||
spatialForce = null;
|
||||
if (spatialForceReleaseHidden || !spatialForcePanelVisible) {
|
||||
spatialForcePanelVisible = false;
|
||||
}
|
||||
scheduleSpatialForceClear();
|
||||
}
|
||||
hasSignalData =
|
||||
signalPanels.length > 0 ||
|
||||
packet.summary.points.length > 0 ||
|
||||
summary.points.length > 0 ||
|
||||
spatialForce !== null ||
|
||||
devkitSpatialForce !== null;
|
||||
spatialForcePanelVisible;
|
||||
}
|
||||
|
||||
function clearHudPanels(): void {
|
||||
cancelSummaryClear();
|
||||
cancelSpatialForceClear();
|
||||
summaryReleaseHidden = true;
|
||||
spatialForceReleaseHidden = false;
|
||||
spatialForcePanelVisible = false;
|
||||
hasSignalData = false;
|
||||
signalPanels = buildInactivePanels();
|
||||
summary = buildEmptySummary();
|
||||
@@ -1089,69 +1303,6 @@
|
||||
});
|
||||
}
|
||||
|
||||
function buildConfigLinks(
|
||||
currentLocale: LocaleCode,
|
||||
activeId: string,
|
||||
isSettingsOpen: boolean,
|
||||
isPrecisionOpen: boolean,
|
||||
isDevKitEnabled: boolean,
|
||||
isDevKitOpen: boolean
|
||||
): HudConfigLink[] {
|
||||
const labels =
|
||||
currentLocale === "zh-CN"
|
||||
? {
|
||||
streamOn: "打开",
|
||||
streamOff: "关闭",
|
||||
precisionTest: "游戏",
|
||||
settings: "参数"
|
||||
}
|
||||
: {
|
||||
streamOn: "Open",
|
||||
streamOff: "Close",
|
||||
precisionTest: "Game",
|
||||
settings: "Setup"
|
||||
};
|
||||
const devkitLabel = currentLocale === "zh-CN" ? "开发工具" : "DevKit";
|
||||
|
||||
const links: HudConfigLink[] = [
|
||||
{
|
||||
id: "stream-on",
|
||||
label: labels.streamOn,
|
||||
tone: "lime",
|
||||
active: activeId === "stream-on"
|
||||
},
|
||||
{
|
||||
id: "stream-off",
|
||||
label: labels.streamOff,
|
||||
tone: "orange",
|
||||
active: activeId === "stream-off"
|
||||
},
|
||||
{
|
||||
id: "precision-test",
|
||||
label: labels.precisionTest,
|
||||
tone: "lime",
|
||||
active: isPrecisionOpen
|
||||
},
|
||||
{
|
||||
id: "settings",
|
||||
label: labels.settings,
|
||||
tone: "neutral",
|
||||
active: isSettingsOpen
|
||||
}
|
||||
];
|
||||
|
||||
if (isDevKitEnabled) {
|
||||
links.push({
|
||||
id: "devkit",
|
||||
label: devkitLabel,
|
||||
tone: "cyan",
|
||||
active: isDevKitOpen
|
||||
});
|
||||
}
|
||||
|
||||
return links;
|
||||
}
|
||||
|
||||
async function ensureDefaultWindowSize(): Promise<void> {
|
||||
if (!isTauriRuntime()) {
|
||||
return;
|
||||
@@ -1449,10 +1600,7 @@
|
||||
connectionNotice = "";
|
||||
|
||||
try {
|
||||
const result = await invoke<SerialConnectResult>("serial_connect", {
|
||||
port: event.detail,
|
||||
protocol: serialProtocolForStage()
|
||||
});
|
||||
const result = await invoke<SerialConnectResult>("serial_connect", { port: event.detail });
|
||||
connectionState = result.connected ? "online" : "offline";
|
||||
serialPortValue = result.port;
|
||||
connectionNotice = "";
|
||||
@@ -1704,37 +1852,6 @@
|
||||
resetReplayVisualState();
|
||||
}
|
||||
|
||||
function handleConfigLink(event: CustomEvent<string>): void {
|
||||
if (event.detail === "precision-test") {
|
||||
stageViewMode = "webgl";
|
||||
isPrecisionTestOpen = !isPrecisionTestOpen;
|
||||
isConfigPanelOpen = false;
|
||||
isDevKitConfigOpen = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.detail === "settings") {
|
||||
stageViewMode = "webgl";
|
||||
isPrecisionTestOpen = false;
|
||||
isConfigPanelOpen = !isConfigPanelOpen;
|
||||
isDevKitConfigOpen = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.detail === "devkit") {
|
||||
isPrecisionTestOpen = false;
|
||||
isConfigPanelOpen = false;
|
||||
isDevKitConfigOpen = !isDevKitConfigOpen;
|
||||
return;
|
||||
}
|
||||
|
||||
isPrecisionTestOpen = false;
|
||||
isConfigPanelOpen = false;
|
||||
isDevKitConfigOpen = false;
|
||||
activeConfigLinkId = event.detail;
|
||||
console.info("[hud] config link clicked:", event.detail);
|
||||
}
|
||||
|
||||
async function handleWindowControl(event: CustomEvent<WindowControlAction>): Promise<void> {
|
||||
if (!isTauriRuntime()) {
|
||||
return;
|
||||
@@ -1803,52 +1920,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
function handleMatrixDisplayToggle(event: CustomEvent<boolean>): void {
|
||||
matrixDisplayMode = event.detail ? "dots" : "numeric";
|
||||
}
|
||||
|
||||
async function handleStageModeChange(event: CustomEvent<StageViewMode>): Promise<void> {
|
||||
const previousMode = stageViewMode;
|
||||
function handleStageModeChange(event: CustomEvent<StageViewMode>): void {
|
||||
stageViewMode = event.detail;
|
||||
if (stageViewMode === "model3d") {
|
||||
isPrecisionTestOpen = false;
|
||||
isConfigPanelOpen = false;
|
||||
}
|
||||
|
||||
if (
|
||||
previousMode === stageViewMode ||
|
||||
connectionState !== "online" ||
|
||||
!serialPortValue ||
|
||||
!isTauriRuntime()
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
connectionState = "connecting";
|
||||
connectionNotice = "";
|
||||
try {
|
||||
await invoke<SerialConnectResult>("serial_disconnect");
|
||||
const result = await invoke<SerialConnectResult>("serial_connect", {
|
||||
port: serialPortValue,
|
||||
protocol: serialProtocolForStage(stageViewMode)
|
||||
});
|
||||
connectionState = result.connected ? "online" : "offline";
|
||||
serialPortValue = result.port;
|
||||
clearHudPanels();
|
||||
console.info(`[serial] switched protocol to ${serialProtocolForStage(stageViewMode)}`);
|
||||
} catch (error) {
|
||||
connectionState = "offline";
|
||||
connectionNotice = resolveSerialNotice(error, "connect");
|
||||
connectionNoticeTone = "warn";
|
||||
clearHudPanels();
|
||||
console.error("Serial protocol switch failed:", error);
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
let disposed = false;
|
||||
let unlistenHudStream: UnlistenFn | null = null;
|
||||
let unlistenHandGatewayRaw: UnlistenFn | null = null;
|
||||
let unlistenDevkitPztAngle: UnlistenFn | null = null;
|
||||
let stopMockFeed: (() => void) | null = null;
|
||||
|
||||
@@ -1873,41 +1951,28 @@
|
||||
.catch((error) => {
|
||||
console.error("Failed to listen for hud_stream:", error);
|
||||
});
|
||||
void listen<number[]>("hand_gateway_raw", (event) => {
|
||||
const rawHex = event.payload
|
||||
.map((byte) => byte.toString(16).padStart(2, "0").toUpperCase())
|
||||
.join(" ");
|
||||
console.info(`[hand_gateway][raw] ${rawHex}`);
|
||||
})
|
||||
.then((unlisten) => {
|
||||
if (disposed) {
|
||||
unlisten();
|
||||
void listen<DevKitPztAngleEvent>("devkit_pzt_angle", (event) => {
|
||||
if (replayHasData) {
|
||||
if (replayPendingDevkitSeq == null || event.payload.seq !== replayPendingDevkitSeq) {
|
||||
return;
|
||||
}
|
||||
replayPendingDevkitSeq = null;
|
||||
}
|
||||
|
||||
unlistenHandGatewayRaw = unlisten;
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Failed to listen for hand_gateway_raw:", error);
|
||||
});
|
||||
void listen<DevKitPztAngleEvent>("devkit_pzt_angle", (event) => {
|
||||
const angleDeg = Number(event.payload.angle);
|
||||
if (!Number.isFinite(angleDeg)) {
|
||||
const magnitude = Number(event.payload.magnitude);
|
||||
const isReportable = event.payload.state > 0 && Number.isFinite(magnitude) && magnitude > 0;
|
||||
if (!Number.isFinite(angleDeg) || !isReportable) {
|
||||
clearDevkitSpatialForce();
|
||||
return;
|
||||
}
|
||||
|
||||
devkitSpatialForce = {
|
||||
angleDeg,
|
||||
magnitude: 0,
|
||||
magnitude,
|
||||
confidence: 0
|
||||
};
|
||||
scheduleDevkitSpatialForceClear();
|
||||
hasSignalData =
|
||||
signalPanels.length > 0 ||
|
||||
summary.points.length > 0 ||
|
||||
spatialForce !== null ||
|
||||
devkitSpatialForce !== null;
|
||||
})
|
||||
.then((unlisten) => {
|
||||
if (disposed) {
|
||||
@@ -1927,10 +1992,11 @@
|
||||
return () => {
|
||||
disposed = true;
|
||||
pauseReplayPlayback();
|
||||
cancelSummaryClear();
|
||||
cancelSpatialForceClear();
|
||||
clearDevkitSpatialForce();
|
||||
stopMockFeed?.();
|
||||
unlistenHudStream?.();
|
||||
unlistenHandGatewayRaw?.();
|
||||
unlistenDevkitPztAngle?.();
|
||||
if (devkitStatusTimer != null) {
|
||||
window.clearInterval(devkitStatusTimer);
|
||||
@@ -1967,15 +2033,9 @@
|
||||
sampleRateValue={sampleRateValue}
|
||||
channelsLabel={uiCopy.channelsLabel}
|
||||
channelsValue={channelsValue}
|
||||
configLinksLabel={uiCopy.configLinksLabel}
|
||||
refreshPortsLabel={uiCopy.refreshPortsLabel}
|
||||
matrixViewLabel={uiCopy.matrixViewLabel}
|
||||
matrixViewNumericLabel={uiCopy.matrixViewNumericLabel}
|
||||
matrixViewDotsLabel={uiCopy.matrixViewDotsLabel}
|
||||
{matrixDisplayMode}
|
||||
stageModeLabel={uiCopy.stageModeLabel}
|
||||
stageModeWebglLabel={uiCopy.stageModeWebglLabel}
|
||||
stageModeModelLabel={uiCopy.stageModeModelLabel}
|
||||
{stageViewMode}
|
||||
connectActionLabel={uiCopy.connectActionLabel}
|
||||
disconnectActionLabel={uiCopy.disconnectActionLabel}
|
||||
@@ -1988,7 +2048,6 @@
|
||||
noticeCancelLabel={locale === "zh-CN" ? "取消" : "Cancel"}
|
||||
noticeShowActions={updateNoticeVisible}
|
||||
noticeActionBusy={updateInstallBusy}
|
||||
{configLinks}
|
||||
{isRefreshingPorts}
|
||||
{isExporting}
|
||||
isConnectDisabled={!serialPortValue || connectionState === "connecting"}
|
||||
@@ -1997,8 +2056,6 @@
|
||||
on:windowcontrol={handleWindowControl}
|
||||
on:localechange={handleLocaleChange}
|
||||
on:portchange={handlePortChange}
|
||||
on:configlink={handleConfigLink}
|
||||
on:matrixdisplaytoggle={handleMatrixDisplayToggle}
|
||||
on:stagemodechange={handleStageModeChange}
|
||||
on:serialrefresh={handleSerialRefresh}
|
||||
on:serialconnect={handleSerialConnect}
|
||||
@@ -2019,7 +2076,6 @@
|
||||
bind:rangeMin
|
||||
bind:rangeMax
|
||||
bind:colorMapPreset
|
||||
bind:matrixDisplayMode
|
||||
{stageViewMode}
|
||||
configPanelTitle={uiCopy.configPanelTitle}
|
||||
configPanelHint={uiCopy.configPanelHint}
|
||||
@@ -2042,24 +2098,23 @@
|
||||
{replayFileName}
|
||||
{replayFrameInfo}
|
||||
{sessionStartedAt}
|
||||
{summaryReleasePending}
|
||||
{spatialForcePanelVisible}
|
||||
resetConfigLabel={uiCopy.resetConfigLabel}
|
||||
applyLiveHint={uiCopy.applyLiveHint}
|
||||
leftPanels={leftSignalPanels}
|
||||
rightPanels={rightSignalPanels}
|
||||
{pressureMatrix}
|
||||
{spatialForce}
|
||||
{devkitSpatialForce}
|
||||
showConfigPanel={isConfigPanelOpen}
|
||||
showPrecisionTestPanel={isPrecisionTestOpen}
|
||||
showConfigPanel={false}
|
||||
{summary}
|
||||
on:replaytoggle={handleReplayToggle}
|
||||
on:replaystop={handleReplayStop}
|
||||
on:replayseek={handleReplaySeek}
|
||||
on:replayspeed={handleReplaySpeed}
|
||||
on:replayclose={handleReplayClose}
|
||||
on:configclose={() => (isConfigPanelOpen = false)}
|
||||
>
|
||||
{#if !isPrecisionTestOpen && stageViewMode === "webgl"}
|
||||
{#if stageViewMode === "webgl"}
|
||||
<section class="range-scale" aria-label="Signal Range">
|
||||
<p class="range-label">{locale === "zh-CN" ? "范围" : "Range"}</p>
|
||||
<div class="range-track">
|
||||
|
||||
Reference in New Issue
Block a user