@@ -1028,6 +1028,63 @@ def test_device_mtp(board):
10281028 mtp .disconnect ()
10291029
10301030
1031+ def test_device_net_lwip_webserver (board ):
1032+ # MAC hard-coded in examples/device/net_lwip_webserver/src/main.c; Linux names the
1033+ # USB network interface enx<MAC_lowercase_no_colons>. Device IP is 192.168.7.1 and
1034+ # the example runs an iperf2 TCP server on port 5001 (INCLUDE_IPERF).
1035+ import socket
1036+ mac_no_colons = '0202846a9600'
1037+ iface = 'enx' + mac_no_colons
1038+ device_ip = '192.168.7.1'
1039+ iperf_port = 5001
1040+
1041+ # Wait for the host to get an IPv4 address in the device's subnet (DHCP served by the device).
1042+ deadline = time .time () + ENUM_TIMEOUT
1043+ host_ip = None
1044+ while time .time () < deadline :
1045+ ret = subprocess .run (['ip' , '-o' , '-4' , 'addr' , 'show' , iface ],
1046+ capture_output = True , text = True , timeout = 2 )
1047+ m = re .search (r'inet (192\.168\.7\.\d+)/' , ret .stdout ) if ret .returncode == 0 else None
1048+ if m :
1049+ host_ip = m .group (1 )
1050+ break
1051+ time .sleep (0.5 )
1052+ assert host_ip , f'USB net iface { iface } did not come up with 192.168.7.x within { ENUM_TIMEOUT } s'
1053+
1054+ # Poll the iperf TCP port until the device is accepting. The net stack comes up a bit
1055+ # after DHCP completes; iperf server binding isn't instantaneous after reflash.
1056+ deadline = time .time () + ENUM_TIMEOUT
1057+ last_err = None
1058+ while time .time () < deadline :
1059+ try :
1060+ with socket .create_connection ((device_ip , iperf_port ), timeout = 1 ):
1061+ last_err = None
1062+ break
1063+ except OSError as e :
1064+ last_err = e
1065+ time .sleep (0.3 )
1066+ assert last_err is None , f'iperf TCP { device_ip } :{ iperf_port } not accepting within { ENUM_TIMEOUT } s: { last_err } '
1067+
1068+ # Throughput: 5-second iperf2 TCP test, CSV output for stable parsing.
1069+ # iperf2 CSV final summary line: timestamp,src_ip,src_port,dst_ip,dst_port,id,interval,bytes,bps
1070+ ret = subprocess .run (['iperf' , '-c' , device_ip , '-t' , '5' , '-y' , 'C' ],
1071+ capture_output = True , text = True , timeout = 30 )
1072+ stderr = ret .stderr .strip ()
1073+ stdout = ret .stdout .strip ()
1074+ assert ret .returncode == 0 , f'iperf rc={ ret .returncode } : stderr={ stderr !r} stdout={ stdout !r} '
1075+ lines = [l for l in stdout .splitlines () if l ]
1076+ assert lines , f'iperf produced no output (rc={ ret .returncode } , stderr={ stderr !r} )'
1077+ try :
1078+ bps = int (lines [- 1 ].split (',' )[- 1 ])
1079+ except (ValueError , IndexError ) as e :
1080+ raise AssertionError (f'could not parse iperf output: { lines [- 1 ]!r} ({ e } )' )
1081+ mbps = bps / 1e6
1082+ print (f' iperf { mbps :5.1f} Mbps' , end = '' )
1083+
1084+ # Reject implausibly low throughput - a working USB-net link should clear this easily.
1085+ assert mbps >= 1.0 , f'iperf throughput too low: { mbps :.2f} Mbps'
1086+
1087+
10311088def test_device_msc_dual_lun (board ):
10321089 uid = board ['uid' ]
10331090
@@ -1150,7 +1207,8 @@ def test_device_hid_generic_inout(board):
11501207 'device/hid_generic_inout' ,
11511208 'device/printer_to_cdc' ,
11521209 'device/midi_test' ,
1153- 'device/mtp'
1210+ 'device/mtp' ,
1211+ 'device/net_lwip_webserver'
11541212]
11551213
11561214dual_tests = [
0 commit comments