24
24
25
25
package org .photonvision ;
26
26
27
+ import static org .junit .jupiter .api .Assertions .assertDoesNotThrow ;
28
+ import static org .photonvision .UnitTestUtils .waitForCondition ;
29
+ import static org .photonvision .UnitTestUtils .waitForSequenceNumber ;
30
+
27
31
import edu .wpi .first .hal .HAL ;
32
+ import edu .wpi .first .math .geometry .Rotation2d ;
28
33
import edu .wpi .first .networktables .NetworkTableInstance ;
29
34
import edu .wpi .first .networktables .NetworkTablesJNI ;
30
35
import edu .wpi .first .wpilibj .Timer ;
31
36
import java .io .IOException ;
37
+ import java .util .stream .Stream ;
38
+ import org .junit .jupiter .api .AfterEach ;
32
39
import org .junit .jupiter .api .Assertions ;
33
40
import org .junit .jupiter .api .BeforeAll ;
41
+ import org .junit .jupiter .api .BeforeEach ;
34
42
import org .junit .jupiter .api .Test ;
43
+ import org .junit .jupiter .params .ParameterizedTest ;
44
+ import org .junit .jupiter .params .provider .Arguments ;
45
+ import org .junit .jupiter .params .provider .MethodSource ;
35
46
import org .photonvision .common .dataflow .structures .Packet ;
36
47
import org .photonvision .jni .PhotonTargetingJniLoader ;
48
+ import org .photonvision .jni .TimeSyncClient ;
37
49
import org .photonvision .jni .WpilibLoader ;
50
+ import org .photonvision .simulation .PhotonCameraSim ;
38
51
import org .photonvision .targeting .PhotonPipelineResult ;
39
52
40
53
class PhotonCameraTest {
@@ -43,6 +56,16 @@ public static void load_wpilib() {
43
56
WpilibLoader .loadLibraries ();
44
57
}
45
58
59
+ @ BeforeEach
60
+ public void setup () {
61
+ HAL .initialize (500 , 0 );
62
+ }
63
+
64
+ @ AfterEach
65
+ public void teardown () {
66
+ HAL .shutdown ();
67
+ }
68
+
46
69
@ Test
47
70
public void testEmpty () {
48
71
Assertions .assertDoesNotThrow (
@@ -92,4 +115,119 @@ public void testTimeSyncServerWithPhotonCamera() throws InterruptedException, IO
92
115
93
116
HAL .shutdown ();
94
117
}
118
+
119
+ private static Stream <Arguments > testNtOffsets () {
120
+ return Stream .of (
121
+ // various initializaiton orders
122
+ Arguments .of (1 , 10 , 30 , 30 ),
123
+ Arguments .of (10 , 2 , 30 , 30 ),
124
+ Arguments .of (10 , 10 , 30 , 30 ),
125
+ // Reboot just the robot
126
+ Arguments .of (1 , 1 , 10 , 30 ),
127
+ // Reboot just the coproc
128
+ Arguments .of (1 , 1 , 30 , 10 ));
129
+ }
130
+
131
+ /**
132
+ * Try starting client before server and vice-versa, making sure that we never fail the version
133
+ * check
134
+ */
135
+ @ ParameterizedTest
136
+ @ MethodSource ("testNtOffsets" )
137
+ public void testRestartingRobotAndCoproc (
138
+ int robotStart , int coprocStart , int robotRestart , int coprocRestart ) throws Throwable {
139
+ var robotNt = NetworkTableInstance .create ();
140
+ var coprocNt = NetworkTableInstance .create ();
141
+
142
+ robotNt .addLogger (10 , 255 , (it ) -> System .out .println ("ROBOT: " + it .logMessage .message ));
143
+ coprocNt .addLogger (10 , 255 , (it ) -> System .out .println ("CLIENT: " + it .logMessage .message ));
144
+
145
+ TimeSyncClient tspClient = null ;
146
+
147
+ var robotCamera = new PhotonCamera (robotNt , "MY_CAMERA" );
148
+
149
+ // apparently need a PhotonCamera to hand down
150
+ var fakePhotonCoprocCam = new PhotonCamera (coprocNt , "MY_CAMERA" );
151
+ var coprocSim = new PhotonCameraSim (fakePhotonCoprocCam );
152
+ coprocSim .prop .setCalibration (640 , 480 , Rotation2d .fromDegrees (90 ));
153
+ coprocSim .prop .setFPS (30 );
154
+ coprocSim .setMinTargetAreaPixels (20.0 );
155
+
156
+ for (int i = 0 ; i < 20 ; i ++) {
157
+ int seq = i + 1 ;
158
+
159
+ if (i == coprocRestart ) {
160
+ System .out .println ("Restarting coprocessor NT client" );
161
+
162
+ fakePhotonCoprocCam .close ();
163
+ coprocNt .close ();
164
+ coprocNt = NetworkTableInstance .create ();
165
+
166
+ coprocNt .addLogger (10 , 255 , (it ) -> System .out .println ("CLIENT: " + it .logMessage .message ));
167
+
168
+ fakePhotonCoprocCam = new PhotonCamera (coprocNt , "MY_CAMERA" );
169
+ coprocSim = new PhotonCameraSim (fakePhotonCoprocCam );
170
+ coprocSim .prop .setCalibration (640 , 480 , Rotation2d .fromDegrees (90 ));
171
+ coprocSim .prop .setFPS (30 );
172
+ coprocSim .setMinTargetAreaPixels (20.0 );
173
+ }
174
+ if (i == robotRestart ) {
175
+ System .out .println ("Restarting robot NT server" );
176
+
177
+ robotNt .close ();
178
+ robotNt = NetworkTableInstance .create ();
179
+ robotNt .addLogger (10 , 255 , (it ) -> System .out .println ("ROBOT: " + it .logMessage .message ));
180
+ robotCamera = new PhotonCamera (robotNt , "MY_CAMERA" );
181
+ }
182
+
183
+ if (i == coprocStart || i == coprocRestart ) {
184
+ coprocNt .setServer ("127.0.0.1" , 5940 );
185
+ coprocNt .startClient4 ("testClient" );
186
+
187
+ // PhotonCamera makes a server by default - connect to it
188
+ tspClient = new TimeSyncClient ("127.0.0.1" , 5810 , 0.5 );
189
+ }
190
+
191
+ if (i == robotStart || i == robotRestart ) {
192
+ robotNt .startServer ("networktables_random.json" , "" , 5941 , 5940 );
193
+ }
194
+
195
+ Thread .sleep (100 );
196
+
197
+ if (i == Math .max (coprocStart , robotStart )) {
198
+ final var c = coprocNt ;
199
+ final var r = robotNt ;
200
+ waitForCondition ("Coproc connection" , () -> c .getConnections ().length == 1 );
201
+ waitForCondition ("Rio connection" , () -> r .getConnections ().length == 1 );
202
+ }
203
+
204
+ var result1 = new PhotonPipelineResult ();
205
+ result1 .metadata .captureTimestampMicros = seq * 100 ;
206
+ result1 .metadata .publishTimestampMicros = seq * 150 ;
207
+ result1 .metadata .sequenceID = seq ;
208
+ if (tspClient != null ) {
209
+ result1 .metadata .timeSinceLastPong = tspClient .getPingMetadata ().timeSinceLastPong ();
210
+ } else {
211
+ result1 .metadata .timeSinceLastPong = Long .MAX_VALUE ;
212
+ }
213
+
214
+ coprocSim .submitProcessedFrame (result1 , NetworkTablesJNI .now ());
215
+ coprocNt .flush ();
216
+
217
+ if (i > robotStart && i > coprocStart ) {
218
+ var ret = waitForSequenceNumber (robotCamera , seq );
219
+ System .out .println (ret );
220
+ }
221
+
222
+ // force verifyVersion to do checks
223
+ robotCamera .lastVersionCheckTime = -100 ;
224
+ robotCamera .prevTimeSyncWarnTime = -100 ;
225
+ assertDoesNotThrow (robotCamera ::verifyVersion );
226
+ }
227
+
228
+ coprocSim .close ();
229
+ coprocNt .close ();
230
+ robotNt .close ();
231
+ tspClient .stop ();
232
+ }
95
233
}
0 commit comments