ๅบไบ Flutter ๅผๅ็ Android ๅบ็จ๏ผ็จไบๆฅๆถๅนถไฟๅญ Livox MID-360 ๆฟๅ ้ท่พพ็ UDP ็นไบๆฐๆฎใ
- โ ้่ฟ UDP Socket ็ดๆฅๆฅๆถ้ท่พพ็นไบๆฐๆฎ
- โ ๆฏๆ UDP ๅๆญๆจกๅผ
- โ ้ซๆ็ๆฐๆฎๅๅ ฅ๏ผ้ฟๅ ไธขๅ
- โ ๆฏๆ PCAP ๆ ผๅผไฟๅญ๏ผๅฏ็จ Wireshark ๆๅผๅๆ๏ผ
- โ ๆฏๆๅๅงไบ่ฟๅถๆ ผๅผไฟๅญ
- โ ๅฎๆถๆพ็คบ้้็ถๆๅ็ป่ฎกไฟกๆฏ
lib/
โโโ main.dart # ๅบ็จๅ
ฅๅฃๅไธป็้ข
โโโ models/
โ โโโ capture_state.dart # ้้็ถๆๆจกๅ
โโโ controllers/
โ โโโ capture_controller.dart # ้้ๆงๅถๅจ
โโโ services/
โ โโโ udp_capture_service.dart # UDP ๆฅๆถๆๅก๏ผๆ ธๅฟ๏ผ
โโโ utils/
โ โโโ pcap_writer.dart # PCAP ๆ ผๅผๅๅ
ฅๅทฅๅ
ท
โโโ widgets/
โโโ capture_control_card.dart # ๆงๅถๆ้ฎ็ปไปถ
โโโ stats_card.dart # ็ป่ฎกไฟกๆฏ็ปไปถ
โโโ config_card.dart # ้
็ฝฎไฟกๆฏ็ปไปถ
- ๆ ๅ็ฝ็ปๆๅ ๆ ผๅผ๏ผๅฏ็จ Wireshark ็ดๆฅๆๅผ
- ๅ ๅซๅฎๆด็ IP ๅคดๅ UDP ๅคดไฟกๆฏ
- ๆไปถๆฉๅฑๅ:
.pcap - ๅ ๅซๆถ้ดๆณใๆบ/็ฎๆ IPใ็ซฏๅฃ็ญๅ ๆฐๆฎ
- ๅๅง UDP payload ๆฐๆฎ
- ไธๅ ๅซไปปไฝๅ่ฎฎๅคด
- ๆไปถๆฉๅฑๅ:
.bin - ๆไปถไฝ็งฏๆดๅฐ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ PCAP Global Header (24B) โ โ ๆไปถๅคด๏ผๅชๅไธๆฌก
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Packet Header (16B) โ โ ๆฏไธชUDPๅ
็ๅคด
โ IP Header (20B) โ
โ UDP Header (8B) โ
โ UDP Payload (ๅ้ฟ) โ โ ็นไบๆฐๆฎ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Packet Header (16B) โ
โ IP Header (20B) โ
โ UDP Header (8B) โ
โ UDP Payload (ๅ้ฟ) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ ... โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Main Isolate (UI) โ
โ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ CaptureControllerโโโโโถโ UdpCaptureService โ โ
โ โ (็ถๆ็ฎก็) โ โ - ๅฏๅจ/ๅๆญข Isolate โ โ
โ โโโโโโโโโโโโโโโโโโโ โ - ๆฅๆถ็ป่ฎกๆฐๆฎ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ SendPort/ReceivePort
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Worker Isolate (UDPๆฅๆถ) โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ โโ
โ โ RawDatagramSocket โโถ PcapWriter โโถ BytesBuilder โโถ Fileโโ
โ โ (UDPๆฅๆถ) (ๅฐ่ฃ
PCAP) (ๅๅ
ฅ็ผๅฒๅบ) (็ฃ็) โโ
โ โ โโ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
| ็ปไปถ | ่่ดฃ |
|---|---|
UdpCaptureService |
็ฎก็ Isolate ็ๅฝๅจๆ๏ผไธ Worker ้ไฟก |
Worker Isolate |
็ฌ็ซ็บฟ็จๆง่ก UDP ๆฅๆถๅๆไปถๅๅ ฅ |
PcapWriter |
็ๆๆ ๅ PCAP ๆ ผๅผๆฐๆฎ |
CaptureController |
ไธๅก้ป่พๆงๅถ๏ผ็ถๆ็ฎก็ |
CaptureState |
ไธๅฏๅ็ถๆๆจกๅ |
- UDP ๆฅๆถๅจ็ฌ็ซ Isolate ไธญ่ฟ่ก๏ผๅฎๅ จไธๅ UI ็บฟ็จๅฝฑๅ
- ๅณไฝฟ UI ๅก้กฟ๏ผๆฐๆฎๆฅๆถไนไธไผไธญๆญ
// ไฝฟ็จ BytesBuilder ็ดฏ็งฏๆฐๆฎ
final writeBuffer = BytesBuilder(copy: false);
const writeBufferThreshold = 256 * 1024; // 256KB ็ผๅฒๅบ้ๅผ
// ๅฝ็ผๅฒๅบ่พพๅฐ้ๅผๆถๆน้ๅๅ
ฅ
if (writeBuffer.length >= writeBufferThreshold) {
final data = writeBuffer.takeBytes();
file.writeFromSync(data);
}// ไธๆฌกไบไปถไธญ่ฏปๅๆๆๅฏ็จๆฐๆฎ
while (running) {
final datagram = socket.receive();
if (datagram == null) break;
writeBuffer.add(datagram.data);
}// ๆฏ 500ms ๅทๆฐไธๆฌก็ผๅฒๅบ๏ผ็กฎไฟๆฐๆฎไธไผ้ฟๆถ้ดๅ็ๅจๅ
ๅญ
Timer.periodic(Duration(milliseconds: 500), (timer) {
if (writeBuffer.length > 0) {
final data = writeBuffer.takeBytes();
file.writeFromSync(data);
}
});finally {
// 1. ๅๅ
ฅๅฉไฝ็ผๅฒๅบๆฐๆฎ
if (writeBuffer.length > 0 && file != null) {
final data = writeBuffer.takeBytes();
file.writeFromSync(data);
}
// 2. ๆพๅผๅทๆฐๆไปถ็ผๅฒๅบ
file.flushSync();
// 3. ๅ
ณ้ญๆไปถๅฅๆ
file.closeSync();
// 4. ๅ
ณ้ญ Socket
socket?.close();
}@override
void didChangeAppLifecycleState(AppLifecycleState state) {
// ๅบ็จ่ฟๅ
ฅๅๅฐๆถ่ชๅจๅๆญข้้
if (state == AppLifecycleState.paused ||
state == AppLifecycleState.detached) {
if (_controller.state.isCapturing) {
_controller.stopCapture();
}
}
}| ๅๆฐ | ๅผ | ่ฏดๆ |
|---|---|---|
| ้ท่พพๆบ็ซฏๅฃ | 56300 | Livox MID-360 ๅ้ๆฐๆฎ็็ซฏๅฃ |
| ๆฌๆบ็ๅฌ็ซฏๅฃ | 56301 | Android ่ฎพๅคๆฅๆถๆฐๆฎ็็ซฏๅฃ |
<!-- AndroidManifest.xml -->
<!-- ็ฝ็ปๆ้ - UDP Socket ้ไฟกๅฟ
้ -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- ๅญๅจๆ้ - ็จไบไฟๅญ็นไบๆฐๆฎๆไปถ -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- ไฟๆๅค้ - ้ฟๆถ้ด้้ๆถ้ฒๆญขไผ็ -->
<uses-permission android:name="android.permission.WAKE_LOCK" />- PCAP ๆ ผๅผ:
.pcapๆไปถ๏ผๅฏ็จ Wireshark ๆๅผ๏ผ - RAW ๆ ผๅผ:
.binๅๅงไบ่ฟๅถๆไปถ - ๆไปถๅฝๅ:
mid360_pointcloud_<timestamp>.<pcap|bin> - ๅญๅจ่ทฏๅพ:
/Android/data/com.livox.mid360_capture/files/MID360/
- ๅฐ
.pcapๆไปถไปๆๆบๅคๅถๅฐ็ต่ - ็จ Wireshark ๆๅผๆไปถ
- ๅฏไปฅ็ๅฐๆฏไธช UDP ๆฐๆฎๅ
็๏ผ
- ๆถ้ดๆณ
- ๆบ IP ๅ็ซฏๅฃ
- ็ฎๆ IP ๅ็ซฏๅฃ
- UDP payload๏ผ็นไบๆฐๆฎ๏ผ
- ไฝฟ็จ่ฟๆปคๅจ
udp.port == 56301็ญ้ๆฐๆฎ
# ่ทๅไพ่ต
flutter pub get
# ๅๆไปฃ็
flutter analyze
# ็ผ่ฏ APK
flutter build apk --release
# ๆ็ดๆฅ่ฟ่ก
flutter run- ็ฝ็ป้ ็ฝฎ: ็กฎไฟ Android ่ฎพๅคไธ MID-360 ๅจๅไธๅฑๅ็ฝ ๆๅฅฝๅฐIP่ฎพ็ฝฎไธบ192.168.1.50
- ้ท่พพ้ ็ฝฎ: ๅฐ้ท่พพ็็ฎๆ IP ่ฎพ็ฝฎไธบ Android ่ฎพๅค IP๏ผ็ฎๆ ็ซฏๅฃ่ฎพ็ฝฎไธบ 56301
- ๅผๅง้้: ็นๅป"ๅผๅง้้"ๆ้ฎ
- ็ๆง็ถๆ: ่งๅฏ UDP ๅ ๆฐ้ๅๆฐๆฎๅคงๅฐๆฏๅฆๅข้ฟ
- ๅๆญข้้: ็นๅป"ๅๆญข้้"ๆ้ฎ๏ผๆฐๆฎๅฐ่ชๅจไฟๅญ
- ่ฎพ่ฎก็ฎๆ : ๆฏๆ MID-360 ๆๅคงๆฐๆฎ้็ (~10MB/s)
- ็ผๅฒๅบๅคงๅฐ: 256KB ๅๅ ฅ็ผๅฒๅบ
- ๅทๆฐ้ด้: 500ms ็ป่ฎกๆดๆฐ๏ผ1000ms ๅฎๆถๅท็
- ๆฏๆๆถ้ฟ: ็่ฎบไธๅฏๆฏๆๆฐๅฐๆถ่ฟ็ปญ้้๏ผๅๅณไบๅญๅจ็ฉบ้ด๏ผ
- Flutter: ่ทจๅนณๅฐ UI ๆกๆถ
- Dart Isolate: ๅค็บฟ็จๅค็
- RawDatagramSocket: UDP ็ฝ็ป้ไฟก
- Provider: ็ถๆ็ฎก็
- path_provider: ๆไปถ่ทฏๅพ็ฎก็