| 两侧同时换到之前的修订记录
前一修订版
后一修订版
|
前一修订版
|
en:stpc-exxx-c [2026/11/13 23:31] wjj 2.2 figure sized tighter |
en:stpc-exxx-c [2026/11/14 03:52] (当前版本) wjj 3D 透视配色与透明度终值:蓝灰鬼影 + 内部零件加重 |
| /* ===== 产品图库:目录右侧展示区 ===== */ | /* ===== 产品图库:目录右侧展示区 ===== */ |
| .sml-top{display:flex;gap:18px;align-items:flex-start;margin:0 0 1.6em;} | .sml-top{display:flex;gap:18px;align-items:flex-start;margin:0 0 1.6em;} |
| .sml-left{flex:0 0 264px;min-width:0;} | .sml-left{flex:0 0 auto;min-width:0;max-width:46%;} |
| .sml-left #smltoc{margin:0;width:100%;box-sizing:border-box;} | /* 目录每项单行显示:左栏随目录内容自适应,既不折行,也不会压住右侧图库 */ |
| | #smltoc ul.toclist li{white-space:nowrap;} |
| | #smltoc{overflow-x:auto;} |
| | .sml-left #smltoc{margin:0;width:auto;max-width:100%;box-sizing:border-box;} |
| .sml-gallery{position:sticky;top:14px;flex:1 1 auto;min-width:0;border:1px solid #d7e0ea;border-radius:6px;background:linear-gradient(155deg,#fcfdff 0%,#f0f4f9 100%);box-shadow:0 8px 26px rgba(31,42,55,.07);overflow:hidden;font-family:"Microsoft YaHei","PingFang SC","Hiragino Sans GB","Helvetica Neue",Arial,sans-serif;font-variant-numeric:lining-nums tabular-nums;font-feature-settings:"lnum" 1,"tnum" 1;} | .sml-gallery{position:sticky;top:14px;flex:1 1 auto;min-width:0;border:1px solid #d7e0ea;border-radius:6px;background:linear-gradient(155deg,#fcfdff 0%,#f0f4f9 100%);box-shadow:0 8px 26px rgba(31,42,55,.07);overflow:hidden;font-family:"Microsoft YaHei","PingFang SC","Hiragino Sans GB","Helvetica Neue",Arial,sans-serif;font-variant-numeric:lining-nums tabular-nums;font-feature-settings:"lnum" 1,"tnum" 1;} |
| .sml-g-head{display:flex;justify-content:space-between;align-items:flex-end;gap:12px;padding:9px 16px 8px;border-bottom:1px solid #e2e9f1;} | .sml-g-head{display:flex;justify-content:space-between;align-items:flex-end;gap:12px;padding:9px 16px 8px;border-bottom:1px solid #e2e9f1;} |
| .sml-g-apps .t{font-weight:700;color:#1f2a37;letter-spacing:.5px;margin-right:2px;} | .sml-g-apps .t{font-weight:700;color:#1f2a37;letter-spacing:.5px;margin-right:2px;} |
| .sml-g-apps .chip{border:1px solid #d7e0ea;background:#fff;border-radius:2px;padding:2px 8px;color:#4a5765;} | .sml-g-apps .chip{border:1px solid #d7e0ea;background:#fff;border-radius:2px;padding:2px 8px;color:#4a5765;} |
| @media (max-width:1200px){.sml-left{flex-basis:220px;}} | @media (max-width:1200px){.sml-top{flex-direction:column;}.sml-left{flex:1 1 auto;width:100%;max-width:none;}.sml-gallery{order:-1;position:static;width:100%;box-sizing:border-box;}.sml-g-note{display:none;}} |
| @media (max-width:1100px){.sml-top{flex-direction:column;}.sml-left{flex:1 1 auto;width:100%;}.sml-gallery{order:-1;position:static;width:100%;box-sizing:border-box;}.sml-g-note{display:none;}} | |
| @media (max-width:900px){.sml-g-body{flex-direction:column;}.sml-g-stage{height:220px;}.sml-g-side{flex:1 1 auto;flex-direction:row;flex-wrap:nowrap;}button.sml-g-thumb{flex:1 1 0;min-width:0;flex-direction:column;text-align:center;gap:3px;padding:5px 3px 6px;}.sml-g-tn{flex:none;width:100%;height:36px;}.sml-g-tx{font-size:10px;text-align:center;}.sml-g-tx b{display:none;}.sml-g-side-hd{display:none;}.sml-g-spec{flex:1 1 50%;}} | @media (max-width:900px){.sml-g-body{flex-direction:column;}.sml-g-stage{height:220px;}.sml-g-side{flex:1 1 auto;flex-direction:row;flex-wrap:nowrap;}button.sml-g-thumb{flex:1 1 0;min-width:0;flex-direction:column;text-align:center;gap:3px;padding:5px 3px 6px;}.sml-g-tn{flex:none;width:100%;height:36px;}.sml-g-tx{font-size:10px;text-align:center;}.sml-g-tx b{display:none;}.sml-g-side-hd{display:none;}.sml-g-spec{flex:1 1 50%;}} |
| @media (max-width:520px){.sml-g-stage{height:180px;}.sml-g-cap{font-size:10px;}.sml-g-zoom{font-size:10px;}} | @media (max-width:520px){.sml-g-stage{height:180px;}.sml-g-cap{font-size:10px;}.sml-g-zoom{font-size:10px;}} |
| #bodyContent .sml-doc p.sml-note{min-width:min(100%,240px)!important;} | #bodyContent .sml-doc p.sml-note{min-width:min(100%,240px)!important;} |
| } | } |
| | .sml-3d{position:absolute;inset:0;display:none;z-index:4;background:#f3f6fa;}.sml-g-stage.on3d{height:430px;}.sml-g-stage.on3d>*:not(.sml-3d){visibility:hidden;}.sml-g-stage.on3d .sml-3d{display:block;}.sml-g-side.on3d{justify-content:flex-start;}.sml-g-side.on3d button.sml-g-thumb{flex:0 0 auto;min-height:38px;}button.sml-g-thumb[data-3d] svg{display:block;width:100%;height:100%;}@media (max-width:900px){.sml-g-stage.on3d{height:330px;}.sml-g-side{flex-wrap:wrap!important;gap:4px!important;}button.sml-g-thumb{flex:1 1 calc(33.333% - 3px)!important;min-width:0;}.sml-g-side.on3d button.sml-g-thumb{min-height:44px;}.sml-g-cap{max-width:calc(100% - 78px);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}} |
| | .sml-g-side{flex:0 0 168px;} |
| </style></html> | </style></html> |
| <html><script> | <html><script> |
| <div class="sml-gallery"> | <div class="sml-gallery"> |
| <div class="sml-g-head"><div><div class="sml-g-kicker">PRODUCT GALLERY / Product Gallery</div><div class="sml-g-title">sTPC-EXXX-C Series · Unit Appearance</div></div><div class="sml-g-note">Using the E156 model as an example · Click a view on the right to switch</div></div> | <div class="sml-g-head"><div><div class="sml-g-kicker">PRODUCT GALLERY / Product Gallery</div><div class="sml-g-title">sTPC-EXXX-C Series · Unit Appearance</div></div><div class="sml-g-note">Using the E156 model as an example · Click a view on the right to switch</div></div> |
| <div class="sml-g-body"><div class="sml-g-stage"><img id="sml-g-main" class="sml-g-main" src="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_front_v.jpg" alt="Front View · Multi-Point Capacitive Touch Screen"><div class="sml-g-badge">INDUSTRIAL PANEL PC</div><a id="sml-g-zoom" class="sml-g-zoom" href="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_front.jpg" target="_blank" rel="noopener">View Full-Resolution Image ↗</a><div class="sml-g-cap" id="sml-g-cap">Front View · Multi-Point Capacitive Touch Screen</div><div class="sml-g-count" id="sml-g-count">01 / 04</div></div><div class="sml-g-side"><div class="sml-g-side-hd">Unit Views / 04 VIEWS</div><button type="button" class="sml-g-thumb on" data-view="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_front_v.jpg" data-full="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_front.jpg" data-idx="01" data-cap="Front View · Multi-Point Capacitive Touch Screen"><span class="sml-g-tn"><img src="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_thumb_01.jpg" alt="Front View"></span><span class="sml-g-tx"><b>VIEW 01</b>Front View</span></button><button type="button" class="sml-g-thumb" data-view="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_persp_v.jpg" data-full="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_persp.jpg" data-idx="02" data-cap="Perspective View · Unit Structure and Rear Main Bay"><span class="sml-g-tn"><img src="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_thumb_02.jpg" alt="Perspective View"></span><span class="sml-g-tx"><b>VIEW 02</b>Perspective View</span></button><button type="button" class="sml-g-thumb" data-view="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_back_v.jpg" data-full="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_back.jpg" data-idx="03" data-cap="Rear View · Fully Sealed Rear Cover and VESA Holes"><span class="sml-g-tn"><img src="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_thumb_03.jpg" alt="Rear View"></span><span class="sml-g-tx"><b>VIEW 03</b>Rear View</span></button><button type="button" class="sml-g-thumb" data-view="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_io_v.jpg" data-full="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_io.jpg" data-idx="04" data-cap="Interface View · External I/O Concentrated on the Lower Rear"><span class="sml-g-tn"><img src="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_thumb_04.jpg" alt="Interface View"></span><span class="sml-g-tx"><b>VIEW 04</b>Interface View</span></button></div></div> | <div class="sml-g-body"><div class="sml-g-stage"><img id="sml-g-main" class="sml-g-main" src="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_front_v.jpg" alt="Front View · Multi-Point Capacitive Touch Screen"><div class="sml-g-badge">INDUSTRIAL PANEL PC</div><a id="sml-g-zoom" class="sml-g-zoom" href="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_front.jpg" target="_blank" rel="noopener">View Full-Resolution Image ↗</a><div class="sml-3d" id="sml-3d"></div><div class="sml-g-cap" id="sml-g-cap">Front View · Capacitive Touch Panel</div><div class="sml-g-count" id="sml-g-count">01 / 05</div></div><div class="sml-g-side"><div class="sml-g-side-hd">Unit Views / 05 VIEWS</div><button type="button" class="sml-g-thumb on" data-view="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_front_v.jpg" data-full="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_front.jpg" data-idx="01" data-cap="Front View · Capacitive Touch Panel"><span class="sml-g-tn"><img src="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_thumb_01.jpg" alt="Front View"></span><span class="sml-g-tx"><b>SLC</b>Front View</span></button><button type="button" class="sml-g-thumb" data-view="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_persp_v.jpg" data-full="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_persp.jpg" data-idx="02" data-cap="Perspective View · Main Module"><span class="sml-g-tn"><img src="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_thumb_02.jpg" alt="Perspective View"></span><span class="sml-g-tx"><b>SLC</b>Perspective View</span></button><button type="button" class="sml-g-thumb" data-view="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_back_v.jpg" data-full="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_back.jpg" data-idx="03" data-cap="Rear View · Mounting Back Plate"><span class="sml-g-tn"><img src="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_thumb_03.jpg" alt="Rear View"></span><span class="sml-g-tx"><b>SLC</b>Rear View</span></button><button type="button" class="sml-g-thumb" data-view="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_io_v.jpg" data-full="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_io.jpg" data-idx="04" data-cap="Interface View · Power and Network"><span class="sml-g-tn"><img src="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_thumb_04.jpg" alt="Interface View"></span><span class="sml-g-tx"><b>SLC</b>Interface View</span></button> |
| | <button type="button" class="sml-g-thumb" data-3d="1" data-idx="05" data-zip="/dokuwiki/lib/exe/fetch.php?media=wiki:stpc_e156c_3d.zip" data-lang="en" data-size="about 3.4 MB" data-rear="0" data-parts="[["后壳","Rear Shell","#eef2f5",1.25,-1],["前框","Front Bezel","#e6ebef",1.55,1],["显示模组","Display Module","#0b1015",1.0,1],["角部盖板","Corner Plate","#e2e8ed",1.7,1],["触摸屏","Touch Panel","#151d26",1.8,1],["前视窗玻璃","Front Glass","#0a0d11",1.95,1],["主板组件","Main Board","#2f6f59",0.7,-1],["连接器","Connector","#a45a52",0.35,-1],["接口座","I/O Socket","#a45a52",0.4,-1],["接口板","I/O Board","#2f6f59",0.5,-1],["屏蔽板","Shield Plate","#dfe5ea",0.5,-1],["按键座","Button Seat","#a45a52",0.35,-1],["导光件","Light Guide","#c9a227",0.3,-1],["紧固件","Fastener","#9aa4b0",0.2,-1],["显示面板","Display Panel","#0a0e12",2.0,1]]" data-cap="3D Teardown · Part Structure"><span class="sml-g-tn"><svg viewBox="0 0 44 30" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><g fill="none" stroke="#0b5394" stroke-width="1.3" stroke-linejoin="round"><path d="M12 8 L22 3 L32 8 L22 13 Z"/><path d="M12 8 L12 20 L22 25 L22 13"/><path d="M32 8 L32 20 L22 25"/><path d="M17 5.5 L27 10.5" stroke="#8fb2d6" stroke-width="1"/></g></svg></span><span class="sml-g-tx"><b>SLC</b>3D Teardown</span></button></div></div> |
| <div class="sml-g-specs"><div class="sml-g-spec"><b>RK3568 / 3576 / 3588</b><em>Three Platforms · up to 6 TOPS NPU</em></div><div class="sml-g-spec"><b>10.1″–21.5″</b><em>Six Sizes · Capacitive Touch</em></div><div class="sml-g-spec"><b>Fanless Fully Sealed</b><em>VESA / Embedded Mounting</em></div><div class="sml-g-spec"><b>Wide-Range Power</b><em>DC 12~24V ±10%</em></div></div> | <div class="sml-g-specs"><div class="sml-g-spec"><b>RK3568 / 3576 / 3588</b><em>Three Platforms · up to 6 TOPS NPU</em></div><div class="sml-g-spec"><b>10.1″–21.5″</b><em>Six Sizes · Capacitive Touch</em></div><div class="sml-g-spec"><b>Fanless Fully Sealed</b><em>VESA / Embedded Mounting</em></div><div class="sml-g-spec"><b>Wide-Range Power</b><em>DC 12~24V ±10%</em></div></div> |
| <div class="sml-g-apps"><span class="t">Typical Applications</span><span class="chip">Production Line Dashboard</span><span class="chip">Equipment HMI</span><span class="chip">Self-Service Query Terminal</span><span>Long-Term Stable Operation in Industrial Sites</span></div> | <div class="sml-g-apps"><span class="t">Typical Applications</span><span class="chip">Production Line Dashboard</span><span class="chip">Equipment HMI</span><span class="chip">Self-Service Query Terminal</span><span>Long-Term Stable Operation in Industrial Sites</span></div> |
| | **Wireless** | Onboard 2.4G/5G dual-band Wi-Fi, 802.11 a/b/g/n/ac + Bluetooth 5.0 | | | **Wireless** | Onboard 2.4G/5G dual-band Wi-Fi, 802.11 a/b/g/n/ac + Bluetooth 5.0 | |
| | **4G / 5G** | 1 × Mini-PCIe, supports LTE 4G / Wi-Fi 6 modules (optional); 1 × M.2, supports 5G modules (optional) | | | **4G / 5G** | 1 × Mini-PCIe, supports LTE 4G / Wi-Fi 6 modules (optional); 1 × M.2, supports 5G modules (optional) | |
| | **USB** | 3 × USB2.0 + 1 × USB3.0 (shared with OTG) | | | **USB** | 3 × USB2.0 + 1 × USB3.0 (supports Device mode) | |
| | **Serial Port** | 1 × RS485 (3.5mm pitch 2PIN terminal) + 1 × RS232 (DB9); 1 × 3RS232/485 module (optional, 3.5mm pitch 2×5PIN terminal) | | | **Serial Port** | 1 × RS485 (3.5mm pitch 2PIN terminal) + 1 × RS232 (DB9); 1 × 3RS232/485 module (optional, 3.5mm pitch 2×5PIN terminal) | |
| | **Audio** | 2 × Ø3.5 phone jack (8Ω 6W) or built-in 8Ω 2.5W speaker (optional), 1 × Ø3.5 phone jack Mic in (optional) | | | **Audio** | 2 × Ø3.5 phone jack (8Ω 6W) or built-in 8Ω 2.5W speaker (optional), 1 × Ø3.5 phone jack Mic in (optional) | |
| ==== 2.2 Interface Overview ==== | ==== 2.2 Interface Overview ==== |
| |
| From left to right on the **lower rear** of the unit, the external interfaces are: RS232 → RS485 → SIM & TF → Power Button → Recover → USB3.0/OTG → RJ45 → DC IN; above them are USB2.0 and HDMI. On the upper rear, from left to right: Wi-Fi/BT 4G/5G antennas (optional) → 3RS232/RS485 serial module (optional) → Ø3.5 Mic (optional) → Ø3.5 SPK (optional) → built-in speaker (optional). The interface area is shown below; the numbers in the table correspond to the silkscreen labels printed on the unit. | From left to right on the **lower rear** of the unit, the external interfaces are: RS232 → RS485 → SIM & TF → Power Button → Recover → USB3.0 → RJ45 → DC IN; above them are USB2.0 and HDMI. On the upper rear, from left to right: Wi-Fi/BT 4G/5G antennas (optional) → 3RS232/RS485 serial module (optional) → Ø3.5 Mic (optional) → Ø3.5 SPK (optional) → built-in speaker (optional). The interface area is shown below; the numbers in the table correspond to the silkscreen labels printed on the unit. |
| |
| {{wiki:stpc_e156c_io_v.jpg?600}} | {{wiki:stpc_e156c_io_v.jpg?600}} |
| |
| Lower rear: DC IN / RS232 / RS485 / SIM & TF / Power Button / Recover / USB3.0/OTG / RJ45, with USB2.0 and HDMI directly above. | Lower rear: DC IN / RS232 / RS485 / SIM & TF / Power Button / Recover / USB3.0 / RJ45, with USB2.0 and HDMI directly above. |
| |
| |
| | 1 | DC IN | Power Input | 1 | DC 12~24V, barrel power socket, center positive, outer negative | | | 1 | DC IN | Power Input | 1 | DC 12~24V, barrel power socket, center positive, outer negative | |
| | 2 | PWR | Power Indicator LED | 1 | Green, steady on when powered | | | 2 | PWR | Power Indicator LED | 1 | Green, steady on when powered | |
| | 3 | SYS | System Indicator LED | 1 | Blue, steady on while the system is running | | | 3 | SYS | System Indicator LED | 1 | Blue, blinking while the system is running | |
| | 4 | Power Button | Power Button | 1 | Powers the unit on and off | | | 4 | Power Button | Power Button | 1 | Powers the unit on and off | |
| | 5 | Recover | Flash Button | 1 | Power off, hold and power on to enter Loader / Maskrom | | | 5 | Recover | Flash Button | 1 | Power off, hold and power on to enter Loader / Maskrom | |
| | 7 | RS485 | RS485 serial port | 1 | 3.5mm pitch 2PIN terminal, see 2.3 | | | 7 | RS485 | RS485 serial port | 1 | 3.5mm pitch 2PIN terminal, see 2.3 | |
| | 8 | RJ45 | Ethernet | 2 | 10/100/1000M auto-negotiation | | | 8 | RJ45 | Ethernet | 2 | 10/100/1000M auto-negotiation | |
| | 9 | USB3.0/OTG | USB3.0 | 1 | Shared with OTG; Device mode for flashing / ADB | | | 9 | USB3.0 | USB3.0 | 1 | Lower port supports Device mode for flashing / ADB | |
| | 10 | USB2.0 | USB2.0 | 3 | Connect USB flash drives / keyboard and mouse / printers | | | 10 | USB2.0 | USB2.0 | 3 | Connect USB flash drives / keyboard and mouse / printers | |
| | 11 | HDMI | HDMI Output | 1 | Standard Type A, up to 4K (3840×2160) / 8K (RK3588) | | | 11 | HDMI | HDMI Output | 1 | Standard Type A, up to 4K (3840×2160) / 8K (RK3588) | |
| |
| ^ Connector ^ Specifications ^ | ^ Connector ^ Specifications ^ |
| | USB3.0/OTG | Host / Device dual mode; in Device mode, used for system flashing and ADB debugging | | | USB3.0 | Host / Device dual mode; in Device mode, used for system flashing and ADB debugging | |
| | USB2.0 | Host, 480Mbps; connect USB flash drives / keyboard and mouse / printers | | | USB2.0 | Host, 480Mbps; connect USB flash drives / keyboard and mouse / printers | |
| | HDMI | Standard Type A, up to 4K (3840×2160) / 8K (7680×4320, RK3588) | | | HDMI | Standard Type A, up to 4K (3840×2160) / 8K (7680×4320, RK3588) | |
| ==== 3.3 System Flashing ==== | ==== 3.3 System Flashing ==== |
| |
| Linux and Android use the same Rockchip tools for flashing; the unit requires no disassembly: connect via the **USB3.0/OTG port** and enter flashing mode via the **Recover pinhole**. | Linux and Android use the same Rockchip tools for flashing; the unit requires no disassembly: connect via the **USB3.0 port** (lower row) and enter flashing mode via the **Recover pinhole**. |
| |
| **① Connect the OTG Port** | **① Connect the USB3.0 Port** |
| |
| Take a USB3.0 male-to-male cable; connect one end to the blue **USB3.0/OTG** port in the lower row of the rear interface area and the other end to a PC USB port: | Take a USB3.0 male-to-male cable; connect one end to the blue **USB3.0** port in the lower row of the rear interface area and the other end to a PC USB port: |
| |
| {{wiki:burn_otg_v2.png?560}} | {{wiki:burn_otg_v2.png?560}} |
| === 4.1.1 USB ADB Usage ==== | === 4.1.1 USB ADB Usage ==== |
| |
| - Use a USB data cable to connect the **USB3.0/OTG port** of the unit (blue port on the lower row) to the PC | - Use a USB data cable to connect the **USB3.0 port** of the unit (blue port on the lower row) to the PC |
| - Under "Settings → About tablet", tap "Build number" 7 times consecutively to enable Developer options | - Under "Settings → About tablet", tap "Build number" 7 times consecutively to enable Developer options |
| - Enter "Developer options" and enable "USB debugging" | - Enter "Settings → System → Advanced → Developer options" and enable "USB debugging" |
| - On the PC, run adb devices; on first connection, tap "Allow" in the pop-up on the unit | - On the PC, run adb devices; on first connection, tap "Allow" in the pop-up on the unit |
| |
| - RS232 — RS232-to-USB — serial port assistant on the PC | - RS232 — RS232-to-USB — serial port assistant on the PC |
| - RS485 — RS485-to-USB — serial port assistant on the PC | - RS485 — RS485-to-USB — serial port assistant on the PC |
| - RS485 loopback: short A and B | |
| |
| **Precautions** | **Precautions** |
| ==== 4.6 USB and SD Card ==== | ==== 4.6 USB and SD Card ==== |
| |
| The unit provides 2 × USB3.0 (lower row multiplexed with OTG) and 2 × USB2.0, plus SD card support. | The unit provides 2 × USB3.0 (lower row supports Device mode) and 2 × USB2.0, plus SD card support. |
| |
| **USB Drive** | **USB Drive** |
| </code> | </code> |
| |
| **Note:** The OTG port in Device mode (flashing / ADB) cannot act as Host at the same time; before inserting a USB drive, confirm the system has exited flashing mode. For manual mounting under Linux see 5.5. | **Note:** The lower-row USB3.0 port in Device mode (flashing / ADB) cannot act as Host at the same time; before inserting a USB drive, confirm the system has exited flashing mode. For manual mounting under Linux see 5.5. |
| |
| ==== 4.7 Audio Test ==== | ==== 4.7 Audio Test ==== |
| |
| - Connect an 8Ω speaker to the SPK terminal (L+ / L- / R+ / R-) | - Connect an 8Ω speaker to the SPK terminal (L+ / L- / R+ / R-) |
| - Open the built-in "Music" player to play the test audio, and press the volume keys to confirm the volume is adjustable and the left/right channels are normal | |
| - The test file is at /nodka_test/LR_audio.wav and can be played directly with the "Files" app | |
| |
| **Microphone Recording Test** | **Microphone Recording Test** |
| ^ Item ^ Location ^ Phenomenon / Action ^ Verdict ^ | ^ Item ^ Location ^ Phenomenon / Action ^ Verdict ^ |
| | PWR Indicator LED | Left of the interface area | Solid green after DC 12V is connected | LED on indicates normal power supply | | | PWR Indicator LED | Left of the interface area | Solid green after DC 12V is connected | LED on indicates normal power supply | |
| | SYS Indicator LED | Right of PWR | Solid blue after system boot completes | LED on indicates the system is running | | | SYS Indicator LED | Right of PWR | Blinking blue after system boot completes | Blinking LED indicates the system is running | |
| | Recover | Pinhole right of the indicator LED | Hold with power off + release 2 seconds after power-on | RKDevTool detects the LOADER device | | | Recover | Pinhole right of the indicator LED | Hold with power off + release 2 seconds after power-on | RKDevTool detects the LOADER device | |
| | Return | Right of Recover | Press to go back one level; hold and power on for 3s to enter flashing mode | UI returns / Enters Loader | | | Return | Right of Recover | Press to go back one level; hold and power on for 3s to enter flashing mode | UI returns / Enters Loader | |
| **Line Drawing and Multi-Touch Detection** | **Line Drawing and Multi-Touch Detection** |
| |
| - In "Settings → Developer options → Pointer location", swipe a finger to see the X / Y coordinates and trace | - In "Settings → System → Advanced → Developer options → Pointer location", swipe a finger to see the X / Y coordinates and trace |
| - Press and hold five fingers on the screen simultaneously and check whether multiple touch points are reported at the same time (multi-touch) | - Press and hold five fingers on the screen simultaneously and check whether multiple touch points are reported at the same time (multi-touch) |
| - Tap once on each of the four corners and the center to confirm there is no offset and no dead zone (touch calibration data is written at the factory, so recalibration is generally unnecessary) | - Tap once on each of the four corners and the center to confirm there is no offset and no dead zone (touch calibration data is written at the factory, so recalibration is generally unnecessary) |
| |
| <code bash> | <code bash> |
| export PATH=$PATH:/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/ | export PATH=$PATH:/gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu/bin/ |
| aarch64-none-linux-gnu-gcc --version | aarch64-none-linux-gnu-gcc --version |
| </code> | </code> |
| |
| Use a ready-made build image; the host does not need Qt installed, isolation is good, and it suits batch compilation. | Use a ready-made build image; the host does not need Qt installed, isolation is good, and it suits batch compilation. |
| | |
| | **Download:** [[ftp://drv.nodka.com/arm_download/nodka_docker_qt_build_20230223.tar|nodka_docker_qt_build_20230223.tar]] — company FTP (drv.nodka.com) |
| |
| - Import the image | - Import the image |
| </code> | </code> |
| |
| **Note:** The image is large and is provided separately by us; the container ID (09a37c1b2fc3) is taken from the actual docker images output. | **Note:** The image is large; after import the image and the original tar each take a copy, so reserve at least 10 GB of free disk. Chrome / Edge no longer open ftp links directly — use Windows Explorer, FileZilla or a download manager instead. The container ID (09a37c1b2fc3) is taken from the actual docker images output. |
| |
| === 5.12.2 Set Up the Qt Build Environment on the Board === | === 5.12.2 Set Up the Qt Build Environment on the Board === |
| | The flashing tool keeps showing "No device found" | Not in Loader mode / USB driver error / cable issue | Follow step ④ in 3.3 to re-enter Loader mode; uninstall and reinstall the driver; change the USB port and data cable | | | The flashing tool keeps showing "No device found" | Not in Loader mode / USB driver error / cable issue | Follow step ④ in 3.3 to re-enter Loader mode; uninstall and reinstall the driver; change the USB port and data cable | |
| | Unknown device appears in Device Manager | Rockchip USB driver not installed properly | See 3.2; reinstall DriverInstall | | | Unknown device appears in Device Manager | Rockchip USB driver not installed properly | See 3.2; reinstall DriverInstall | |
| | ADB cannot connect | USB debugging not enabled / wrong USB port | See 4.1; confirm connection to the blue USB3.0/OTG lower port | | | ADB cannot connect | USB debugging not enabled / wrong USB port | See 4.1; confirm connection to the blue USB3.0 lower port | |
| | The serial port cannot be opened or returns no data | Wrong node / no permission / A-B or R-T reversed | See 4.5, 5.3; check the node and wiring against the silkscreen label | | | The serial port cannot be opened or returns no data | Wrong node / no permission / A-B or R-T reversed | See 4.5, 5.3; check the node and wiring against the silkscreen label | |
| | GPIO read/write no response | Not exported / numbering offset varies with firmware | See 2.3, 5.4; export first, then operate | | | GPIO read/write no response | Not exported / numbering offset varies with firmware | See 2.3, 5.4; export first, then operate | |
| #footer{margin-left:0!important;padding:8px 12px 20px!important;} | #footer{margin-left:0!important;padding:8px 12px 20px!important;} |
| /* 目录:整块占满,标题左对齐 */ | /* 目录:整块占满,标题左对齐 */ |
| #smltoc{display:block!important;width:100%!important;box-sizing:border-box;margin:0 0 1.2em!important;padding:10px 12px!important;} | #smltoc{display:block!important;width:100%!important;box-sizing:border-box;margin:0 0 1.2em!important;padding:10px 12px!important;overflow-x:auto;-webkit-overflow-scrolling:touch;} |
| #smltoc .hd{text-align:left!important;} | #smltoc .hd{text-align:left!important;} |
| } | } |
| } | } |
| </style></html> | </style></html> |
| | <html><script> |
| | /* sTPC 3D 拆解查看器(嵌入版,无外部依赖) |
| | 用法:SML3D(hostElement, {url:'...zip', lang:'zh', ...}) */ |
| | window.SML3D = (function(){ |
| | "use strict"; |
| | |
| | /* ===== 默认零件表(仅 sTPC-S156-3568B;其它机型由 cfg.parts 传入) ===== */ |
| | var PARTS_S156 = [ |
| | /* 0 */ {n:'机身中框', e:'Mid Frame', col:'#b8c2cd', k:0.00, d:[0,0,0]}, |
| | /* 1 */ {n:'视窗玻璃', e:'Front Glass', col:'#1e2a36', k:1.55, d:[0,0,1]}, |
| | /* 2 */ {n:'显示模组', e:'Display Module', col:'#3f4d5c', k:1.05, d:[0,0,1]}, |
| | /* 3 */ {n:'后盖', e:'Rear Cover', col:'#d4dae1', k:1.45, d:[0,0,-1]}, |
| | /* 4 */ {n:'主板载板', e:'Carrier Board', col:'#2f6f59', k:0.55, d:[0,0,1]}, |
| | /* 5 */ {n:'屏线组件', e:'Panel Cable', col:'#c9a227', k:0.55, d:[0,0,1]}, |
| | /* 6 */ {n:'天线/顶条', e:'Antenna Bar', col:'#7b5ea7', k:0.60, d:[0,0,-1]}, |
| | /* 7 */ {n:'固定卡扣', e:'Clip', col:'#8e99a6', k:0.30, d:[0,0,-1]}, |
| | /* 8 */ {n:'固定卡扣', e:'Clip', col:'#8e99a6', k:0.30, d:[0,0,-1]}, |
| | /* 9 */ {n:'紧固件', e:'Fastener', col:'#8e99a6', k:0.30, d:[0,0,-1]}, |
| | /*10 */ {n:'下侧接口座', e:'I/O Block', col:'#a45a52', k:0.45, d:[0,0,-1]}, |
| | /*11 */ {n:'接地弹片', e:'Ground Spring', col:'#9aa4b0', k:0.20, d:[0,0,-1]}, |
| | /*12 */ {n:'竖向排线', e:'Vertical FPC', col:'#c9a227', k:0.45, d:[0,0,-1]}, |
| | /*13 */ {n:'接地弹片', e:'Ground Spring', col:'#9aa4b0', k:0.20, d:[0,0,-1]}, |
| | /*14 */ {n:'喇叭', e:'Speaker', col:'#a45a52', k:0.45, d:[0,0,-1]}, |
| | /*15 */ {n:'主板组件', e:'Main Board', col:'#2f6f5c', k:0.75, d:[0,0,-1]}, |
| | /*16 */ {n:'前面框', e:'Front Bezel', col:'#cbd3dc', k:1.75, d:[0,0,1]} |
| | ]; |
| | var REAR_S156 = 3; /* 后盖索引 */ |
| | |
| | var UI = { |
| | zh:{open:'打开后盖', close:'装回后盖', xray:'透视', parts:'零件', front:'前视', back:'后视', |
| | side:'侧视', iso:'等轴', reset:'重置', exp:'拆解', hint:'拖拽旋转 · 滚轮缩放 · 点击零件查看', |
| | load:'加载 3D 模型', loading:'正在载入 3D 模型…', size:'约 1.3 MB', all:'全部显示', |
| | faces:'面数', dim:'尺寸', err:'模型载入失败', sorry:'当前浏览器不支持 WebGL,请用 Chrome / Edge 打开'}, |
| | en:{open:'Open cover', close:'Close cover', xray:'X-ray', parts:'Parts', front:'Front', back:'Rear', |
| | side:'Side', iso:'Iso', reset:'Reset', exp:'Explode', hint:'Drag to orbit · Scroll to zoom · Click a part', |
| | load:'Load 3D model', loading:'Loading 3D model…', size:'about 1.3 MB', all:'Show all', |
| | faces:'Faces', dim:'Size', err:'Failed to load model', sorry:'WebGL is not available; please use Chrome or Edge'} |
| | }; |
| | |
| | var CSS = '' |
| | + '.v3d{position:absolute;inset:0;overflow:hidden;background:radial-gradient(120% 105% at 50% 0%,#fdfefe 0%,#eaeef3 52%,#d9dfe7 100%);font:400 12px/1.45 "Segoe UI","Microsoft YaHei",sans-serif;}' |
| | + '.v3d canvas{display:block;width:100%;height:100%;cursor:grab;touch-action:none;}' |
| | + '.v3d canvas:active{cursor:grabbing;}' |
| | + '.v3d .tbar{position:absolute;left:9px;top:9px;display:flex;gap:5px;flex-wrap:wrap;max-width:calc(100% - 18px);}' |
| | + '.v3d .tb{font:inherit;font-size:11.5px;padding:3px 9px;border:1px solid #c6d0da;background:rgba(255,255,255,.94);color:#26313c;border-radius:3px;cursor:pointer;white-space:nowrap;}' |
| | + '.v3d .tb:hover{background:#eef6fd;border-color:#84aede;}' |
| | + '.v3d .tb.on{background:#0b5394;border-color:#0b5394;color:#fff;}' |
| | + '.v3d .tb.hot{border-color:#0b7a75;color:#0b7a75;}' |
| | + '.v3d .tb.hot.on{background:#0b7a75;color:#fff;}' |
| | + '.v3d .ebar{position:absolute;left:9px;right:9px;bottom:8px;display:flex;align-items:center;gap:8px;padding:5px 9px;background:rgba(255,255,255,.9);border:1px solid #dbe2ea;border-radius:3px;}' |
| | + '.v3d .ebar input{flex:1;height:3px;-webkit-appearance:none;appearance:none;background:#cfd8e2;border-radius:2px;outline:none;}' |
| | + '.v3d .ebar input::-webkit-slider-thumb{-webkit-appearance:none;width:13px;height:13px;border-radius:50%;background:#0b5394;cursor:pointer;box-shadow:0 1px 3px rgba(0,0,0,.25);}' |
| | + '.v3d .ebar .lb{font-size:11px;color:#4a5765;white-space:nowrap;}' |
| | + '.v3d .ebar .pv{font-size:11px;color:#0b5394;font-variant-numeric:tabular-nums;min-width:30px;text-align:right;}' |
| | + '.v3d .hint{position:absolute;right:9px;bottom:44px;font-size:10.5px;color:#6b7681;background:rgba(255,255,255,.82);padding:2px 7px;border-radius:2px;}' |
| | + '.v3d .plist{position:absolute;right:9px;top:44px;width:150px;max-height:calc(100% - 96px);overflow:auto;background:rgba(255,255,255,.96);border:1px solid #cbd4de;border-radius:4px;padding:5px;display:none;box-shadow:0 6px 18px rgba(20,40,60,.14);}' |
| | + '.v3d .plist.on{display:block;}' |
| | + '.v3d .pi{display:flex;align-items:center;gap:6px;padding:3px 5px;border-radius:3px;cursor:pointer;font-size:11.5px;color:#26313c;}' |
| | + '.v3d .pi:hover{background:#eef6fd;}' |
| | + '.v3d .pi.sel{background:#dbeafb;box-shadow:inset 2px 0 0 #0b5394;}' |
| | + '.v3d .pi.off{opacity:.36;}' |
| | + '.v3d .pi i{width:9px;height:9px;border-radius:2px;flex:0 0 9px;border:1px solid rgba(0,0,0,.2);}' |
| | + '.v3d .pi span{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}' |
| | + '.v3d .tip{position:absolute;padding:5px 9px;background:rgba(23,32,42,.92);color:#fff;font-size:11px;border-radius:3px;pointer-events:none;display:none;max-width:190px;line-height:1.5;}' |
| | + '.v3d .tip.on{display:block;}' |
| | + '.v3d .tip b{color:#8fc2ff;font-weight:600;}' |
| | + '.v3d .cover{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;flex-direction:column;gap:9px;background:rgba(255,255,255,.92);}' |
| | + '.v3d .cover .b{font:inherit;font-size:12.5px;padding:7px 16px;border:1px solid #0b5394;background:#0b5394;color:#fff;border-radius:3px;cursor:pointer;}' |
| | + '.v3d .cover .b:hover{background:#0a4880;}' |
| | + '.v3d .cover .s{font-size:11px;color:#78838f;}' |
| | + '.v3d .bar{width:150px;height:3px;background:#dde4ec;border-radius:2px;overflow:hidden;}' |
| | + '.v3d .bar>i{display:block;height:100%;width:6%;background:#0b5394;transition:width .18s;}'; |
| | |
| | /* ===== 数学 ===== */ |
| | function persp(f,a,n,r){var t=1/Math.tan(f/2),d=1/(n-r);return new Float32Array([t/a,0,0,0,0,t,0,0,0,0,(r+n)*d,-1,0,0,2*r*n*d,0]);} |
| | function look(e,c,u){ |
| | var zx=e[0]-c[0],zy=e[1]-c[1],zz=e[2]-c[2],zl=Math.hypot(zx,zy,zz)||1;zx/=zl;zy/=zl;zz/=zl; |
| | var xx=u[1]*zz-u[2]*zy,xy=u[2]*zx-u[0]*zz,xz=u[0]*zy-u[1]*zx,xl=Math.hypot(xx,xy,xz)||1;xx/=xl;xy/=xl;xz/=xl; |
| | var yx=zy*xz-zz*xy,yy=zz*xx-zx*xz,yz=zx*xy-zy*xx; |
| | return new Float32Array([xx,yx,zx,0,xy,yy,zy,0,xz,yz,zz,0, |
| | -(xx*e[0]+xy*e[1]+xz*e[2]),-(yx*e[0]+yy*e[1]+yz*e[2]),-(zx*e[0]+zy*e[1]+zz*e[2]),1]); |
| | } |
| | function mmul(a,b){var o=new Float32Array(16);for(var c=0;c<4;c++)for(var r=0;r<4;r++){var s=0;for(var k=0;k<4;k++)s+=a[k*4+r]*b[c*4+k];o[c*4+r]=s;}return o;} |
| | function nmat(n){ |
| | if(n.matrix)return new Float32Array(n.matrix); |
| | var t=n.translation||[0,0,0],q=n.rotation||[0,0,0,1],s=n.scale||[1,1,1]; |
| | var x=q[0],y=q[1],z=q[2],w=q[3],x2=x+x,y2=y+y,z2=z+z,xx=x*x2,xy=x*y2,xz=x*z2,yy=y*y2,yz=y*z2,zz=z*z2,wx=w*x2,wy=w*y2,wz=w*z2; |
| | return new Float32Array([(1-(yy+zz))*s[0],(xy+wz)*s[0],(xz-wy)*s[0],0,(xy-wz)*s[1],(1-(xx+zz))*s[1],(yz+wx)*s[1],0,(xz+wy)*s[2],(yz-wx)*s[2],(1-(xx+yy))*s[2],0,t[0],t[1],t[2],1]); |
| | } |
| | function ap(m,v){return [m[0]*v[0]+m[4]*v[1]+m[8]*v[2]+m[12],m[1]*v[0]+m[5]*v[1]+m[9]*v[2]+m[13],m[2]*v[0]+m[6]*v[1]+m[10]*v[2]+m[14]];} |
| | function hex(h){return [parseInt(h.slice(1,3),16)/255,parseInt(h.slice(3,5),16)/255,parseInt(h.slice(5,7),16)/255];} |
| | |
| | /* ===== 载入 ===== */ |
| | function unzip(ab){ |
| | var d=new DataView(ab); |
| | if(d.getUint32(0,true)!==0x04034b50)throw new Error('zip'); |
| | if(d.getUint16(8,true)!==0)throw new Error('zip mode'); |
| | var cs=d.getUint32(18,true),nl=d.getUint16(26,true),el=d.getUint16(28,true),st=30+nl+el; |
| | return ab.slice(st,st+cs); |
| | } |
| | function parseGLB(ab){ |
| | var d=new DataView(ab); |
| | if(d.getUint32(0,true)!==0x46546C67)throw new Error('glb'); |
| | var len=d.getUint32(8,true),o=12,j=null,b=null; |
| | while(o<len){ |
| | var cl=d.getUint32(o,true),ct=d.getUint32(o+4,true);o+=8; |
| | var c=ab.slice(o,o+cl); |
| | if(ct===0x4E4F534A)j=JSON.parse(new TextDecoder().decode(c)); |
| | else if(ct===0x004E4942)b=c; |
| | o+=cl; |
| | } |
| | return {json:j,bin:b}; |
| | } |
| | var CT={5120:Int8Array,5121:Uint8Array,5122:Int16Array,5123:Uint16Array,5125:Uint32Array,5126:Float32Array}; |
| | function acc(g,i){ |
| | var a=g.json.accessors[i],v=g.json.bufferViews[a.bufferView],T=CT[a.componentType]; |
| | var it=a.type==='VEC3'?3:a.type==='VEC2'?2:a.type==='SCALAR'?1:4; |
| | var off=(v.byteOffset||0)+(a.byteOffset||0),st=v.byteStride||0; |
| | if(st&&st!==it*T.BYTES_PER_ELEMENT){ |
| | var o=new T(a.count*it); |
| | for(var k=0;k<a.count;k++)o.set(new T(g.bin,off+k*st,it),k*it); |
| | return o; |
| | } |
| | return new T(g.bin,off,a.count*it); |
| | } |
| | function build(g){ |
| | var ps=[],pos=[],nrm=[],idx=[],vb=0,ib=0; |
| | var sc=g.json.scenes[g.json.scene||0],stack=[]; |
| | (sc.nodes||[]).forEach(function(n){stack.push([n,new Float32Array([1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1])]);}); |
| | while(stack.length){ |
| | var cur=stack.pop(),ni=g.json.nodes[cur[0]],M=mmul(cur[1],nmat(ni)); |
| | if(ni.mesh!==undefined){ |
| | g.json.meshes[ni.mesh].primitives.forEach(function(p){ |
| | var P=acc(g,p.attributes.POSITION),N=p.attributes.NORMAL!==undefined?acc(g,p.attributes.NORMAL):null, |
| | I=p.indices!==undefined?acc(g,p.indices):null; |
| | var start=ib,vc=P.length/3,i,mn=[1e9,1e9,1e9],mx=[-1e9,-1e9,-1e9]; |
| | for(i=0;i<P.length;i+=3){ |
| | var v=ap(M,[P[i],P[i+1],P[i+2]]); |
| | pos.push(v[0],v[1],v[2]); |
| | for(var a=0;a<3;a++){if(v[a]<mn[a])mn[a]=v[a];if(v[a]>mx[a])mx[a]=v[a];} |
| | } |
| | for(i=0;i<vc;i++){ |
| | if(N){var w=ap(M,[N[i*3],N[i*3+1],N[i*3+2]]),l=Math.hypot(w[0],w[1],w[2])||1;nrm.push(w[0]/l,w[1]/l,w[2]/l);} |
| | else nrm.push(0,1,0); |
| | } |
| | if(I)for(i=0;i<I.length;i++)idx.push(I[i]+vb); |
| | else for(i=0;i<vc;i++)idx.push(i+vb); |
| | ps.push({pi:ps.length,start:start,count:idx.length-start,mn:mn,mx:mx, |
| | c:[(mn[0]+mx[0])/2,(mn[1]+mx[1])/2,(mn[2]+mx[2])/2], |
| | size:[mx[0]-mn[0],mx[1]-mn[1],mx[2]-mn[2]],vis:true}); |
| | vb+=vc;ib=idx.length; |
| | }); |
| | } |
| | (ni.children||[]).forEach(function(ch){stack.push([ch,M]);}); |
| | } |
| | var box=[1e9,1e9,1e9,-1e9,-1e9,-1e9]; |
| | ps.forEach(function(p){for(var a=0;a<3;a++){box[a]=Math.min(box[a],p.mn[a]);box[a+3]=Math.max(box[a+3],p.mx[a]);}}); |
| | return {parts:ps,pos:new Float32Array(pos),nrm:new Float32Array(nrm),idx:new Uint32Array(idx),box:box, |
| | center:[(box[0]+box[3])/2,(box[1]+box[4])/2,(box[2]+box[5])/2], |
| | diag:Math.hypot(box[3]-box[0],box[4]-box[1],box[5]-box[2])}; |
| | } |
| | |
| | /* ===== 主函数 ===== */ |
| | return function(host,cfg){ |
| | cfg=cfg||{}; |
| | var L=UI[cfg.lang==='en'?'en':'zh']; |
| | var PARTS=cfg.parts||PARTS_S156, REAR=cfg.rear!==undefined?cfg.rear:REAR_S156; |
| | if(!document.getElementById('sml3d-css')){ |
| | var st=document.createElement('style');st.id='sml3d-css';st.textContent=CSS;document.head.appendChild(st); |
| | } |
| | var root=document.createElement('div');root.className='v3d'; |
| | root.innerHTML='' |
| | +'<canvas></canvas>' |
| | +'<div class="tbar">' |
| | +'<button class="tb" data-v="front">'+L.front+'</button>' |
| | +'<button class="tb" data-v="back">'+L.back+'</button>' |
| | +'<button class="tb" data-v="side">'+L.side+'</button>' |
| | +'<button class="tb on" data-v="iso">'+L.iso+'</button>' |
| | +'<button class="tb hot" data-a="cover">'+L.open+'</button>' |
| | +'<button class="tb" data-a="xray">'+L.xray+'</button>' |
| | +'<button class="tb" data-a="parts">'+L.parts+'</button>' |
| | +'</div>' |
| | +'<div class="plist"></div>' |
| | +'<div class="hint">'+L.hint+'</div>' |
| | +'<div class="ebar"><span class="lb">'+L.exp+'</span><input type="range" min="0" max="100" value="0"><span class="pv">0%</span></div>' |
| | +'<div class="tip"></div>' |
| | +'<div class="cover"><button class="b">'+L.load+'</button><span class="s">'+(cfg.size||L.size)+'</span></div>'; |
| | host.appendChild(root); |
| | |
| | var cv=root.querySelector('canvas'); |
| | var gl=cv.getContext('webgl2',{antialias:true,alpha:true,premultipliedAlpha:false}); |
| | if(!gl){root.querySelector('.cover').innerHTML='<span class="s">'+L.sorry+'</span>';return {};} |
| | |
| | var VS=['#version 300 es','in vec3 aP;in vec3 aN;uniform mat4 uP,uV;uniform vec3 uO;out vec3 vP;out vec3 vN;', |
| | 'void main(){vec3 p=aP+uO;vP=p;vN=aN;gl_Position=uP*uV*vec4(p,1.0);}'].join('\n'); |
| | var FS=['#version 300 es','precision highp float;in vec3 vP;in vec3 vN;uniform vec3 uC,uE;uniform float uS,uD,uX,uA;uniform mat4 uV;out vec4 f;', |
| | 'void main(){vec3 N=normalize(vN),V=normalize(uE-vP);if(dot(N,V)<0.0)N=-N;', |
| | 'mat3 R=mat3(uV);vec3 Nv=normalize(R*N),Vv=normalize(R*V);vec3 L1=normalize(vec3(-0.42,0.58,0.70)),L2=normalize(vec3(0.60,-0.30,0.74));', |
| | 'float k1=max(dot(Nv,L1),0.0),k2=max(dot(Nv,L2),0.0);vec3 H=normalize(L1+Vv);', |
| | 'float sp=pow(max(dot(Nv,H),0.0),46.0)*0.30;float rm=pow(1.0-max(dot(Nv,Vv),0.0),3.0)*0.20;', |
| | 'vec3 c=uC*(0.34+0.52*k1+0.20*k2)+vec3(sp)+vec3(rm)*0.55;', |
| | 'if(uS>0.5)c=mix(c,vec3(0.12,0.40,0.85),0.34);if(uX>0.5)c=mix(c,vec3(0.40,0.48,0.58),0.55);else if(uD>0.5)c=mix(c,vec3(0.72,0.76,0.81),0.62);', |
| | 'float a=1.0;if(uD>0.5)a*=mix(0.40,1.0,uX);f=vec4(c,a*uA);}'].join('\n'); |
| | function sh(t,s){var o=gl.createShader(t);gl.shaderSource(o,s);gl.compileShader(o); |
| | if(!gl.getShaderParameter(o,gl.COMPILE_STATUS))throw new Error(gl.getShaderInfoLog(o));return o;} |
| | var pr=gl.createProgram(); |
| | gl.attachShader(pr,sh(gl.VERTEX_SHADER,VS));gl.attachShader(pr,sh(gl.FRAGMENT_SHADER,FS)); |
| | gl.bindAttribLocation(pr,0,'aP');gl.bindAttribLocation(pr,1,'aN');gl.linkProgram(pr);gl.useProgram(pr); |
| | var U={};['uP','uV','uO','uC','uE','uS','uD','uX','uA'].forEach(function(n){U[n]=gl.getUniformLocation(pr,n);}); |
| | |
| | var cam={th:0.60,ph:0.19,dist:3,tgt:[0,0,0],fov:34*Math.PI/180}; |
| | var model=null,explode=0,sel=-1,xray=false,coverHidden=false; |
| | var buf={}; |
| | |
| | function eye(){var cp=Math.cos(cam.ph);return [cam.tgt[0]+cam.dist*cp*Math.sin(cam.th),cam.tgt[1]+cam.dist*Math.sin(cam.ph),cam.tgt[2]+cam.dist*cp*Math.cos(cam.th)];} |
| | function fitDist(){ |
| | var w=cv.clientWidth||1,h=cv.clientHeight||1,as=w/h; |
| | var fv=cam.fov,fh=2*Math.atan(Math.tan(fv/2)*as),R=model.diag/2*1.06; |
| | return R/Math.sin(Math.min(fv,fh)/2); |
| | } |
| | /* 视角平滑过渡 */ |
| | var tw=null; |
| | function tween(to){ |
| | var from={th:cam.th,ph:cam.ph,dist:cam.dist}; |
| | var t0=performance.now(); |
| | if(to.th!==undefined&&Math.abs(to.th-cam.th)>Math.PI)cam.th+=(cam.th>to.th?1:-1)*2*Math.PI; |
| | from.th=cam.th; |
| | tw={from:from,to:to,t0:t0,dur:420}; |
| | if(!tw.run){tw.run=true;(function step(){ if(!tw){return;} |
| | var k=Math.min(1,(performance.now()-tw.t0)/tw.dur),e=k<0.5?2*k*k:1-Math.pow(-2*k+2,2)/2; |
| | cam.th=tw.from.th+(tw.to.th-tw.from.th)*e; |
| | cam.ph=tw.from.ph+(tw.to.ph-tw.from.ph)*e; |
| | cam.dist=tw.from.dist+(tw.to.dist-tw.from.dist)*e; |
| | draw(); |
| | if(k<1)requestAnimationFrame(step);else tw=null; |
| | })();} |
| | } |
| | function off(p){ |
| | var m=PARTS[p.pi]||{k:0.5,d:[0,0,1]}; |
| | var g=explode*model.diag*0.20*(m.k===undefined?0.5:m.k); |
| | return [m.d[0]*g,m.d[1]*g,m.d[2]*g]; |
| | } |
| | function col(p){return (PARTS[p.pi]&&PARTS[p.pi].col)||'#9aa4b0';} |
| | |
| | function draw(){ |
| | var dpr=Math.min(window.devicePixelRatio||1,2),w=cv.clientWidth||1,h=cv.clientHeight||1; |
| | if(cv.width!==w*dpr||cv.height!==h*dpr){cv.width=w*dpr;cv.height=h*dpr;} |
| | gl.viewport(0,0,cv.width,cv.height); |
| | gl.clearColor(0,0,0,0);gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT); |
| | if(xray){gl.disable(gl.DEPTH_TEST);}else{gl.enable(gl.DEPTH_TEST);}gl.disable(gl.CULL_FACE);gl.enable(gl.BLEND); |
| | gl.blendFunc(gl.SRC_ALPHA,gl.ONE_MINUS_SRC_ALPHA); |
| | var e=eye(); |
| | gl.uniformMatrix4fv(U.uP,false,persp(cam.fov,w/h,model.diag*0.01,model.diag*12)); |
| | gl.uniformMatrix4fv(U.uV,false,look(e,cam.tgt,[0,1,0])); |
| | gl.uniform3fv(U.uE,e); |
| | gl.bindBuffer(gl.ARRAY_BUFFER,buf.p);gl.enableVertexAttribArray(0);gl.vertexAttribPointer(0,3,gl.FLOAT,false,0,0); |
| | gl.bindBuffer(gl.ARRAY_BUFFER,buf.n);gl.enableVertexAttribArray(1);gl.vertexAttribPointer(1,3,gl.FLOAT,false,0,0); |
| | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,buf.i); |
| | var any=sel>=0; |
| | model.parts.forEach(function(p){ |
| | if(!p.vis)return; |
| | var c=hex(col(p)); |
| | gl.uniform3f(U.uC,c[0],c[1],c[2]); |
| | gl.uniform3fv(U.uO,off(p)); |
| | gl.uniform1f(U.uS,p.pi===sel?1:0); |
| | gl.uniform1f(U.uD,(any&&p.pi!==sel)?1:0); |
| | gl.uniform1f(U.uA, xray ? (p.pi===sel ? 1.0 : (Math.max(p.size[0],p.size[1],p.size[2])>0.075?0.20:0.62)) : 1.0); |
| | gl.uniform1f(U.uX,xray&&p.pi!==sel?1:0); |
| | gl.drawElements(gl.TRIANGLES,p.count,gl.UNSIGNED_INT,p.start*4); |
| | }); |
| | } |
| | |
| | /* 交互 */ |
| | var drag=null; |
| | cv.addEventListener('pointerdown',function(e){cv.setPointerCapture(e.pointerId);drag={x:e.clientX,y:e.clientY,m:0,b:e.button};}); |
| | cv.addEventListener('pointermove',function(e){ |
| | if(!drag)return; |
| | var dx=e.clientX-drag.x,dy=e.clientY-drag.y;drag.x=e.clientX;drag.y=e.clientY;drag.m+=Math.abs(dx)+Math.abs(dy); |
| | if(drag.b===2||e.shiftKey){ |
| | var k=cam.dist*0.0016; |
| | cam.tgt[0]-=Math.cos(cam.th)*dx*k;cam.tgt[2]+=Math.sin(cam.th)*dx*k;cam.tgt[1]+=dy*k; |
| | }else{ |
| | cam.th-=dx*0.008;cam.ph=Math.max(-1.45,Math.min(1.45,cam.ph+dy*0.006)); |
| | } |
| | draw(); |
| | }); |
| | cv.addEventListener('pointerup',function(e){if(drag&&drag.m<6&&drag.b===0)pick(e);drag=null;}); |
| | cv.addEventListener('contextmenu',function(e){e.preventDefault();}); |
| | cv.addEventListener('wheel',function(e){ |
| | e.preventDefault(); |
| | cam.dist*=1+Math.sign(e.deltaY)*0.09; |
| | cam.dist=Math.max(model.diag*0.3,Math.min(model.diag*3.2,cam.dist)); |
| | draw(); |
| | },{passive:false}); |
| | |
| | function pick(e){ |
| | var r=cv.getBoundingClientRect(); |
| | var nx=((e.clientX-r.left)/r.width)*2-1,ny=1-((e.clientY-r.top)/r.height)*2; |
| | var o=eye(),f=[cam.tgt[0]-o[0],cam.tgt[1]-o[1],cam.tgt[2]-o[2]],fl=Math.hypot(f[0],f[1],f[2]); |
| | f=[f[0]/fl,f[1]/fl,f[2]/fl]; |
| | var rt=[f[1]*0-f[2]*1,f[2]*0-f[0]*0,f[0]*1-f[1]*0],rl=Math.hypot(rt[0],rt[1],rt[2])||1; |
| | rt=[rt[0]/rl,rt[1]/rl,rt[2]/rl]; |
| | var up=[rt[1]*f[2]-rt[2]*f[1],rt[2]*f[0]-rt[0]*f[2],rt[0]*f[1]-rt[1]*f[0]]; |
| | var hh=Math.tan(cam.fov/2),hw=hh*(r.width/r.height); |
| | var d=[f[0]+rt[0]*nx*hw+up[0]*ny*hh,f[1]+rt[1]*nx*hw+up[1]*ny*hh,f[2]+rt[2]*nx*hw+up[2]*ny*hh]; |
| | var dl=Math.hypot(d[0],d[1],d[2]);d=[d[0]/dl,d[1]/dl,d[2]/dl]; |
| | var best=-1,bt=1e12; |
| | model.parts.forEach(function(p){ |
| | if(!p.vis)return; |
| | var of=off(p),cx=p.c[0]+of[0],cy=p.c[1]+of[1],cz=p.c[2]+of[2]; |
| | var oc=[cx-o[0],cy-o[1],cz-o[2]],tca=oc[0]*d[0]+oc[1]*d[1]+oc[2]*d[2]; |
| | var rad=Math.hypot(p.size[0],p.size[1],p.size[2])/2; |
| | if(tca<0)return; |
| | if((oc[0]*oc[0]+oc[1]*oc[1]+oc[2]*oc[2])-tca*tca>rad*rad)return; |
| | for(var i=p.start;i<p.start+p.count;i+=3){ |
| | var a=model.idx[i]*3,b=model.idx[i+1]*3,c=model.idx[i+2]*3; |
| | var t=rt3(o,d, |
| | [model.pos[a]+of[0],model.pos[a+1]+of[1],model.pos[a+2]+of[2]], |
| | [model.pos[b]+of[0],model.pos[b+1]+of[1],model.pos[b+2]+of[2]], |
| | [model.pos[c]+of[0],model.pos[c+1]+of[1],model.pos[c+2]+of[2]]); |
| | if(t>0&&t<bt){bt=t;best=p.pi;} |
| | } |
| | }); |
| | select(best,e); |
| | } |
| | function rt3(o,d,a,b,c){ |
| | var e1=[b[0]-a[0],b[1]-a[1],b[2]-a[2]],e2=[c[0]-a[0],c[1]-a[1],c[2]-a[2]]; |
| | var p=[d[1]*e2[2]-d[2]*e2[1],d[2]*e2[0]-d[0]*e2[2],d[0]*e2[1]-d[1]*e2[0]]; |
| | var det=e1[0]*p[0]+e1[1]*p[1]+e1[2]*p[2]; |
| | if(Math.abs(det)<1e-9)return -1; |
| | var iv=1/det,t=[o[0]-a[0],o[1]-a[1],o[2]-a[2]]; |
| | var u=(t[0]*p[0]+t[1]*p[1]+t[2]*p[2])*iv; |
| | if(u<0||u>1)return -1; |
| | var q=[t[1]*e1[2]-t[2]*e1[1],t[2]*e1[0]-t[0]*e1[2],t[0]*e1[1]-t[1]*e1[0]]; |
| | var v=(d[0]*q[0]+d[1]*q[1]+d[2]*q[2])*iv; |
| | if(v<0||u+v>1)return -1; |
| | return (e2[0]*q[0]+e2[1]*q[1]+e2[2]*q[2])*iv; |
| | } |
| | |
| | var plist=root.querySelector('.plist'),tip=root.querySelector('.tip'); |
| | function nm(p){var m=PARTS[p.pi];if(!m)return (cfg.lang==='en'?'Part ':'零件 ')+(p.pi+1);return cfg.lang==='en'?m.e:m.n;} |
| | function buildList(){ |
| | plist.innerHTML=''; |
| | model.parts.slice().sort(function(a,b){return b.size[0]*b.size[1]-a.size[0]*a.size[1];}).forEach(function(p){ |
| | var el=document.createElement('div'); |
| | el.className='pi';el.dataset.pi=p.pi; |
| | el.innerHTML='<i style="background:'+col(p)+'"></i><span>'+nm(p)+'</span>'; |
| | el.addEventListener('click',function(ev){ |
| | if(ev.altKey){p.vis=!p.vis;sync();draw();return;} |
| | select(p.pi===sel?-1:p.pi); |
| | }); |
| | el.addEventListener('dblclick',function(){p.vis=!p.vis;sync();draw();}); |
| | plist.appendChild(el); |
| | }); |
| | sync(); |
| | } |
| | function sync(){ |
| | plist.querySelectorAll('.pi').forEach(function(el){ |
| | var p=model.parts[+el.dataset.pi]; |
| | el.classList.toggle('off',!p.vis);el.classList.toggle('sel',p.pi===sel); |
| | }); |
| | } |
| | function select(pi,e){ |
| | sel=pi;sync();draw(); |
| | if(pi<0||!e){tip.classList.remove('on');return;} |
| | var p=model.parts[pi],s=p.size.map(function(v){return Math.round(v*1000);}); |
| | tip.innerHTML='<b>'+nm(p)+'</b><br>'+L.dim+' '+s[0]+' × '+s[1]+' × '+s[2]+' mm<br>'+L.faces+' '+(p.count/3|0); |
| | var r=host.getBoundingClientRect(); |
| | tip.style.left=Math.min(r.width-200,e.clientX-r.left+12)+'px'; |
| | tip.style.top=Math.min(r.height-70,e.clientY-r.top+12)+'px'; |
| | tip.classList.add('on'); |
| | } |
| | |
| | /* 工具栏 */ |
| | root.querySelectorAll('.tb').forEach(function(b){ |
| | b.addEventListener('click',function(){ |
| | var v=b.dataset.v,a=b.dataset.a; |
| | if(v){ |
| | root.querySelectorAll('.tb[data-v]').forEach(function(x){x.classList.remove('on');}); |
| | b.classList.add('on'); |
| | var to={ph:v==='iso'?0.28:0.02,dist:fitDist()}; |
| | if(v==='front')to.th=0; |
| | if(v==='back')to.th=Math.PI; |
| | if(v==='side')to.th=-Math.PI/2; |
| | if(v==='iso')to.th=0.60; |
| | cam.tgt=[model.center[0],model.center[1],model.center[2]]; |
| | tween(to);return; |
| | } |
| | if(a==='parts'){plist.classList.toggle('on');b.classList.toggle('on');return;} |
| | if(a==='xray'){xray=!xray;b.classList.toggle('on',xray);draw();return;} |
| | if(a==='cover'){ |
| | coverHidden=!coverHidden; |
| | model.parts[REAR].vis=!coverHidden; |
| | b.classList.toggle('on',coverHidden); |
| | b.textContent=coverHidden?L.close:L.open; |
| | if(coverHidden){ |
| | explode=0.5;root.querySelector('.ebar input').value=50;root.querySelector('.pv').textContent='50%'; |
| | tween({th:Math.PI*0.80,ph:0.24,dist:fitDist()*1.02}); |
| | }else{ |
| | explode=0;root.querySelector('.ebar input').value=0;root.querySelector('.pv').textContent='0%'; |
| | tween({th:0.60,ph:0.28,dist:fitDist()}); |
| | } |
| | sync();draw();return; |
| | } |
| | }); |
| | }); |
| | var sld=root.querySelector('.ebar input'); |
| | sld.addEventListener('input',function(){ |
| | explode=+sld.value/100;root.querySelector('.pv').textContent=sld.value+'%'; |
| | if(coverHidden&&explode<0.15){coverHidden=false;model.parts[REAR].vis=true; |
| | var cb=root.querySelector('.tb[data-a=cover]');cb.classList.remove('on');cb.textContent=L.open;} |
| | draw(); |
| | }); |
| | |
| | /* 加载 */ |
| | var started=false; |
| | function start(){ |
| | if(started)return;started=true; |
| | var cover=root.querySelector('.cover'); |
| | cover.innerHTML=L.loading+'<div class="bar"><i></i></div>'; |
| | var bar=cover.querySelector('.bar>i'); |
| | fetch(cfg.url).then(function(r){ |
| | if(!r.ok)throw new Error('HTTP '+r.status); |
| | var tot=+r.headers.get('content-length')||0,got=0,ch=[],rd=r.body.getReader(); |
| | return (function pump(){ |
| | return rd.read().then(function(x){ |
| | if(x.done)return; |
| | ch.push(x.value);got+=x.value.length; |
| | if(tot)bar.style.width=Math.min(94,6+90*got/tot)+'%'; |
| | return pump(); |
| | }); |
| | })().then(function(){ |
| | var b=new Uint8Array(got),o=0;ch.forEach(function(c){b.set(c,o);o+=c.length;}); |
| | return b.buffer; |
| | }); |
| | }).then(function(ab){ |
| | model=build(parseGLB(unzip(ab))); |
| | buf.p=gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER,buf.p);gl.bufferData(gl.ARRAY_BUFFER,model.pos,gl.STATIC_DRAW); |
| | buf.n=gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER,buf.n);gl.bufferData(gl.ARRAY_BUFFER,model.nrm,gl.STATIC_DRAW); |
| | buf.i=gl.createBuffer();gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,buf.i);gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,model.idx,gl.STATIC_DRAW); |
| | bar.style.width='100%'; |
| | cover.style.display='none'; |
| | cam.tgt=[model.center[0],model.center[1],model.center[2]]; |
| | cam.dist=fitDist(); |
| | window.__parts=model.parts; |
| | if(cfg.only!==undefined){model.parts.forEach(function(q){q.vis=q.pi===cfg.only;});} |
| | buildList();draw(); |
| | if(cfg.boom!==undefined){ |
| | explode=cfg.boom; |
| | root.querySelector('.ebar input').value=Math.round(explode*100); |
| | root.querySelector('.pv').textContent=Math.round(explode*100)+'%'; |
| | } |
| | if(cfg.hideCover){ |
| | coverHidden=true;model.parts[REAR].vis=false; |
| | var cb=root.querySelector('.tb[data-a=cover]'); |
| | cb.classList.add('on');cb.textContent=L.close; |
| | sync(); |
| | } |
| | if(cfg.view){cam.th=cfg.view==='back'?Math.PI:cfg.view==='side'?-Math.PI/2:0.60; |
| | cam.ph=cfg.view==='iso'?0.28:0.02;} |
| | draw(); |
| | }).catch(function(err){ |
| | cover.innerHTML='<span class="s">'+L.err+':'+err.message+'</span>'; |
| | }); |
| | } |
| | root.querySelector('.cover .b').addEventListener('click',start); |
| | host.__sml3dStart=start; |
| | window.addEventListener('resize',function(){if(model)draw();}); |
| | return {start:start,ondraw:draw}; |
| | }; |
| | })(); |
| | |
| | </script></html> |
| | <html><script> |
| | /* 3D 拆解视角:捕获阶段接管图库按钮,不改动本页原有的切换脚本 */ |
| | (function () { |
| | var host = document.getElementById('sml-3d'); |
| | if (!host) return; |
| | var stage = host.parentNode, side = document.querySelector('.sml-g-side'); |
| | var v3 = null, on = false; |
| | function parseParts(btn) { |
| | try { |
| | var a = JSON.parse(btn.getAttribute('data-parts') || '[]'); |
| | return a.map(function (r) { return {n: r[0], e: r[1], col: r[2], k: r[3], d: [0, 0, r[4]]}; }); |
| | } catch (e) { return null; } |
| | } |
| | function enter(btn) { |
| | on = true; |
| | stage.className = 'sml-g-stage on3d'; |
| | if (side) side.className = 'sml-g-side on3d'; |
| | if (!v3) { |
| | if (!window.SML3D) return; |
| | v3 = window.SML3D(host, { |
| | url: btn.getAttribute('data-zip'), |
| | lang: btn.getAttribute('data-lang'), |
| | size: btn.getAttribute('data-size'), |
| | parts: parseParts(btn), |
| | rear: +btn.getAttribute('data-rear') |
| | }); |
| | v3.start(); |
| | } |
| | } |
| | function leave() { |
| | if (!on) return; |
| | on = false; |
| | stage.className = 'sml-g-stage'; |
| | if (side) side.className = 'sml-g-side'; |
| | } |
| | document.addEventListener('click', function (e) { |
| | var t = e.target; |
| | while (t && t !== document && !(t.tagName === 'BUTTON' && /sml-g-thumb/.test(t.className))) t = t.parentNode; |
| | if (!t || t === document) return; |
| | if (t.hasAttribute('data-3d')) { |
| | e.preventDefault(); |
| | e.stopPropagation(); |
| | var bs = document.querySelectorAll('button.sml-g-thumb'); |
| | for (var i = 0; i < bs.length; i++) bs[i].className = (bs[i] === t ? 'sml-g-thumb on' : 'sml-g-thumb'); |
| | var cap = document.getElementById('sml-g-cap'), cnt = document.getElementById('sml-g-count'); |
| | if (cnt) cnt.textContent = t.getAttribute('data-idx') + ' / ' + (bs.length < 10 ? '0' + bs.length : bs.length); |
| | if (cap) cap.textContent = t.getAttribute('data-cap'); |
| | enter(t); |
| | } else { |
| | leave(); |
| | } |
| | }, true); |
| | })(); |
| | </script></html> |
| |