Link test: UDP echo sweep, soak and TCP each way, driven by the app
The tablet's app sockets are the only ones bound to the USB link, so the measurement has to run in the app. tool/linktest_server.py serves the Orin end and logs every result with its own TCP_INFO. Startable without touching the screen: am start ... --es linktest <label>. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DDwfd6Ki8UfG4hK6W5YpJz
This commit is contained in:
+39
-6
@@ -6,6 +6,7 @@ import 'dart:math';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'boundary.dart';
|
||||
import 'linktest.dart';
|
||||
import 'net.dart';
|
||||
|
||||
/// Override for development, e.g. `--dart-define=YUKART_GW=ws://halogen.local:7700/`.
|
||||
@@ -16,32 +17,56 @@ Future<void> main() async {
|
||||
final usb = UsbLink();
|
||||
await usb.bindFor(Uri.parse(defaultUrl));
|
||||
final boundary = Boundary(defaultUrl)..start();
|
||||
runApp(YukartApp(boundary: boundary, usb: usb));
|
||||
final linkTest = LinkTest(usb);
|
||||
// Development hook: `am start ... --es linktest <label>` runs the test on the gateway's host.
|
||||
Future<void> runLinkTest(String label) async {
|
||||
navigatorKey.currentState?.push(MaterialPageRoute<void>(builder: (_) => linkTestPage(boundary, linkTest, usb)));
|
||||
await linkTest.run(Uri.parse(boundary.url).host, label);
|
||||
await usb.bindFor(Uri.parse(boundary.url));
|
||||
}
|
||||
|
||||
usb.onLinkTest = runLinkTest;
|
||||
runApp(YukartApp(boundary: boundary, usb: usb, linkTest: linkTest));
|
||||
final pending = await usb.takeLinkTest();
|
||||
if (pending != null) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) => runLinkTest(pending));
|
||||
}
|
||||
}
|
||||
|
||||
final navigatorKey = GlobalKey<NavigatorState>();
|
||||
|
||||
Widget linkTestPage(Boundary b, LinkTest t, UsbLink usb) => LinkTestPage(
|
||||
test: t,
|
||||
host: Uri.parse(b.url).host,
|
||||
restoreBinding: () => usb.bindFor(Uri.parse(b.url)),
|
||||
);
|
||||
|
||||
class YukartApp extends StatelessWidget {
|
||||
const YukartApp({super.key, required this.boundary, required this.usb});
|
||||
const YukartApp({super.key, required this.boundary, required this.usb, required this.linkTest});
|
||||
final Boundary boundary;
|
||||
final UsbLink usb;
|
||||
final LinkTest linkTest;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
title: 'Yukart',
|
||||
navigatorKey: navigatorKey,
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: ThemeData(colorSchemeSeed: Colors.teal, brightness: Brightness.dark, useMaterial3: true),
|
||||
home: ListenableBuilder(
|
||||
listenable: Listenable.merge([boundary, usb]),
|
||||
builder: (context, _) => Readout(boundary: boundary, usb: usb),
|
||||
builder: (context, _) => Readout(boundary: boundary, usb: usb, linkTest: linkTest),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class Readout extends StatelessWidget {
|
||||
const Readout({super.key, required this.boundary, required this.usb});
|
||||
const Readout({super.key, required this.boundary, required this.usb, required this.linkTest});
|
||||
final Boundary boundary;
|
||||
final UsbLink usb;
|
||||
final LinkTest linkTest;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -53,7 +78,7 @@ class Readout extends StatelessWidget {
|
||||
children: [
|
||||
// Mock data must look like mock data: on the surface, not in a menu.
|
||||
if (b.mock) const MockBanner(),
|
||||
LinkBar(boundary: b, usb: usb),
|
||||
LinkBar(boundary: b, usb: usb, linkTest: linkTest),
|
||||
Expanded(
|
||||
child: LayoutBuilder(
|
||||
builder: (context, c) {
|
||||
@@ -100,9 +125,10 @@ class MockBanner extends StatelessWidget {
|
||||
}
|
||||
|
||||
class LinkBar extends StatelessWidget {
|
||||
const LinkBar({super.key, required this.boundary, required this.usb});
|
||||
const LinkBar({super.key, required this.boundary, required this.usb, required this.linkTest});
|
||||
final Boundary boundary;
|
||||
final UsbLink usb;
|
||||
final LinkTest linkTest;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -127,6 +153,13 @@ class LinkBar extends StatelessWidget {
|
||||
Text('last msg $age'),
|
||||
Text('Orin−tablet clock $offset'),
|
||||
if (usb.supported) Text('USB link ${usb.up ? 'up' : 'absent'}${usb.bound ? ', bound' : ''}'),
|
||||
TextButton.icon(
|
||||
onPressed: () => Navigator.of(context).push(
|
||||
MaterialPageRoute<void>(builder: (_) => linkTestPage(b, linkTest, usb)),
|
||||
),
|
||||
icon: const Icon(Icons.speed),
|
||||
label: const Text('Link test'),
|
||||
),
|
||||
]),
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user