@@ -131,7 +131,8 @@ function parseQuadraJsonOutput($args) {
131131 $ json = fixQuadraJson ($ block [0 ]);
132132 $ parsed = json_decode ($ json , true );
133133 if ($ parsed !== null && isset ($ parsed [$ key ])) {
134- $ result [$ key ] = $ parsed [$ key ];
134+ if (!isset ($ result [$ key ])) $ result [$ key ] = [];
135+ $ result [$ key ] = array_merge ($ result [$ key ], $ parsed [$ key ]);
135136 $ sectionCount ++;
136137 } else {
137138 $ jsonError = json_last_error_msg ();
@@ -167,15 +168,6 @@ function formatBitrate($bps) {
167168$ quadraSummary = parseQuadraJsonOutput ('-o json ' );
168169$ quadraDetailed = parseQuadraJsonOutput ('-d -o json ' );
169170
170- // Extract device info from the first available section entry
171- $ deviceInfo = null ;
172- foreach (['decoder ' , 'encoder ' , 'scaler ' , 'AI ' , 'uploader ' , 'nvme ' ] as $ sect ) {
173- if (!empty ($ quadraSummary [$ sect ][0 ])) {
174- $ deviceInfo = $ quadraSummary [$ sect ][0 ];
175- break ;
176- }
177- }
178-
179171$ resourceSections = [
180172 'decoder ' => ['label ' => 'Decoder ' , 'icon ' => 'input ' ],
181173 'encoder ' => ['label ' => 'Encoder ' , 'icon ' => 'output ' ],
@@ -190,6 +182,53 @@ function formatBitrate($bps) {
190182 'pcie ' => ['label ' => 'PCIe ' , 'icon ' => 'settings_ethernet ' ],
191183];
192184
185+ // Build per-card data indexed by card INDEX
186+ // Each entry in the summary/detailed arrays has an INDEX field identifying the card
187+ $ cards = [];
188+ $ allSections = array_merge (array_keys ($ resourceSections ), array_keys ($ infraSections ));
189+ foreach ($ allSections as $ sect ) {
190+ if (empty ($ quadraSummary [$ sect ])) continue ;
191+ foreach ($ quadraSummary [$ sect ] as $ entry ) {
192+ $ idx = $ entry ['INDEX ' ] ?? 0 ;
193+ if (!isset ($ cards [$ idx ])) {
194+ $ cards [$ idx ] = [
195+ 'device ' => $ entry ['DEVICE ' ] ?? 'N/A ' ,
196+ 'pcie_addr ' => $ entry ['PCIE_ADDR ' ] ?? 'N/A ' ,
197+ 'numa_node ' => $ entry ['NUMA_NODE ' ] ?? '? ' ,
198+ 'firmware ' => $ entry ['FR ' ] ?? ($ quadraSummary ['version ' ] ?? 'N/A ' ),
199+ 'summary ' => [],
200+ 'detailed ' => [],
201+ ];
202+ }
203+ if (!isset ($ cards [$ idx ]['summary ' ][$ sect ])) $ cards [$ idx ]['summary ' ][$ sect ] = [];
204+ $ cards [$ idx ]['summary ' ][$ sect ][] = $ entry ;
205+ }
206+ }
207+ // Build DEVICE -> card index lookup from summary data
208+ $ deviceToCard = [];
209+ foreach ($ cards as $ idx => $ card ) {
210+ $ deviceToCard [$ card ['device ' ]] = $ idx ;
211+ }
212+ // Assign detailed session data to cards by matching DEVICE field.
213+ // In detailed output INDEX is the session number, not the card index.
214+ foreach (['decoder ' , 'encoder ' ] as $ sect ) {
215+ if (empty ($ quadraDetailed [$ sect ])) continue ;
216+ foreach ($ quadraDetailed [$ sect ] as $ entry ) {
217+ $ dev = $ entry ['DEVICE ' ] ?? '' ;
218+ if (isset ($ deviceToCard [$ dev ])) {
219+ $ idx = $ deviceToCard [$ dev ];
220+ } else {
221+ // Fall back to first card if DEVICE not found
222+ $ idx = array_key_first ($ cards );
223+ if ($ idx === null ) continue ;
224+ }
225+ if (!isset ($ cards [$ idx ]['detailed ' ][$ sect ])) $ cards [$ idx ]['detailed ' ][$ sect ] = [];
226+ $ cards [$ idx ]['detailed ' ][$ sect ][] = $ entry ;
227+ }
228+ }
229+ ksort ($ cards );
230+ $ hasData = !empty ($ cards );
231+
193232xhtmlHeaders (__FILE__ , 'Quadra Status ' );
194233getBodyTopHTML ();
195234echo getNavBarHTML ();
@@ -208,55 +247,56 @@ function formatBitrate($bps) {
208247 <strong>Error running ni_rsrc_mon:</strong><br>
209248 <?php echo htmlspecialchars ($ quadraSummary ['error ' ]) ?>
210249 </div>
211- <?php elseif (!$ deviceInfo && empty ( $ quadraSummary [ ' decoder ' ]) && empty ( $ quadraSummary [ ' encoder ' ]) ): ?>
250+ <?php elseif (!$ hasData ): ?>
212251 <div class="alert alert-warning">
213252 <strong>No data:</strong> ni_rsrc_mon returned no resource data.
214253 Check that a NetInt Quadra device is installed and that the web server user has permission to access it.
215254 </div>
216255<?php else : ?>
217256
218- <!-- Device Information -->
257+ <!-- System-wide info -->
219258 <div class="card mb-3">
220259 <div class="card-header">
221- <i class="material-icons md-18">info</i> Device Information
260+ <i class="material-icons md-18">info</i> System Information
222261 </div>
223262 <div class="card-body">
224263 <div class="row">
225264 <div class="col-md-3">
226265 <strong>Timestamp:</strong> <?php echo htmlspecialchars ($ quadraSummary ['timestamp ' ] ?: 'N/A ' ) ?>
227266 </div>
228- <div class="col-md-2 ">
267+ <div class="col-md-3 ">
229268 <strong>Uptime:</strong> <?php echo htmlspecialchars ($ quadraSummary ['uptime ' ] ?: 'N/A ' ) ?>
230269 </div>
231- <div class="col-md-2">
232- <strong>Firmware:</strong> v<?php echo htmlspecialchars ($ quadraSummary ['version ' ] ?: 'N/A ' ) ?>
233- </div>
234- <?php if ($ deviceInfo ): ?>
235- <div class="col-md-2">
236- <strong>Device:</strong> <?php echo htmlspecialchars ($ deviceInfo ['DEVICE ' ] ?? 'N/A ' ) ?>
237- </div>
238270 <div class="col-md-3">
239- <strong>PCIe:</strong> <?php echo htmlspecialchars ($ deviceInfo ['PCIE_ADDR ' ] ?? 'N/A ' ) ?>
240- (NUMA <?php echo htmlspecialchars ($ deviceInfo ['NUMA_NODE ' ] ?? '? ' ) ?> )
271+ <strong>Cards detected:</strong> <?php echo count ($ cards ) ?>
241272 </div>
242- <?php endif ; ?>
243273 </div>
244274 </div>
245275 </div>
246276
247- <!-- Resource Utilization -->
277+ <?php foreach ($ cards as $ cardIdx => $ card ): ?>
278+ <!-- Card <?php echo $ cardIdx ?> -->
279+ <div class="card mb-3">
280+ <div class="card-header">
281+ <i class="material-icons md-18">memory</i>
282+ <strong>Card <?php echo $ cardIdx ?> </strong>
283+ — <?php echo htmlspecialchars ($ card ['device ' ]) ?>
284+ @ <?php echo htmlspecialchars ($ card ['pcie_addr ' ]) ?>
285+ (NUMA <?php echo htmlspecialchars ($ card ['numa_node ' ]) ?> )
286+ — FW v<?php echo htmlspecialchars ($ card ['firmware ' ]) ?>
287+ </div>
288+ <div class="card-body">
289+
290+ <!-- Resource Utilization -->
248291<?php
249292$ hasResources = false ;
250293foreach ($ resourceSections as $ key => $ meta ) {
251- if (!empty ($ quadraSummary [$ key ])) { $ hasResources = true ; break ; }
294+ if (!empty ($ card [ ' summary ' ] [$ key ])) { $ hasResources = true ; break ; }
252295}
253296if ($ hasResources ):
254297?>
255- <div class="card mb-3">
256- <div class="card-header">
257- <i class="material-icons md-18">speed</i> Resource Utilization
258- </div>
259- <div class="card-body table-responsive">
298+ <h6><i class="material-icons md-18">speed</i> Resource Utilization</h6>
299+ <div class="table-responsive mb-3">
260300 <table class="table table-sm table-striped table-hover">
261301 <thead class="thead-highlight text-left">
262302 <tr>
@@ -272,8 +312,8 @@ function formatBitrate($bps) {
272312 </thead>
273313 <tbody>
274314<?php foreach ($ resourceSections as $ key => $ meta ):
275- if (empty ($ quadraSummary [$ key ])) continue ;
276- foreach ($ quadraSummary [$ key ] as $ entry ):
315+ if (empty ($ card [ ' summary ' ] [$ key ])) continue ;
316+ foreach ($ card [ ' summary ' ] [$ key ] as $ entry ):
277317?>
278318 <tr>
279319 <td><i class="material-icons md-18"><?php echo $ meta ['icon ' ] ?> </i> <?php echo $ meta ['label ' ] ?> </td>
@@ -289,22 +329,18 @@ function formatBitrate($bps) {
289329 </tbody>
290330 </table>
291331 </div>
292- </div>
293332<?php endif ; ?>
294333
295- <!-- Infrastructure -->
334+ <!-- Infrastructure -->
296335<?php
297336$ hasInfra = false ;
298337foreach ($ infraSections as $ key => $ meta ) {
299- if (!empty ($ quadraSummary [$ key ])) { $ hasInfra = true ; break ; }
338+ if (!empty ($ card [ ' summary ' ] [$ key ])) { $ hasInfra = true ; break ; }
300339}
301340if ($ hasInfra ):
302341?>
303- <div class="card mb-3">
304- <div class="card-header">
305- <i class="material-icons md-18">developer_board</i> Infrastructure
306- </div>
307- <div class="card-body table-responsive">
342+ <h6><i class="material-icons md-18">developer_board</i> Infrastructure</h6>
343+ <div class="table-responsive mb-3">
308344 <table class="table table-sm table-striped table-hover">
309345 <thead class="thead-highlight text-left">
310346 <tr>
@@ -316,8 +352,8 @@ function formatBitrate($bps) {
316352 </thead>
317353 <tbody>
318354<?php foreach ($ infraSections as $ key => $ meta ):
319- if (empty ($ quadraSummary [$ key ])) continue ;
320- foreach ($ quadraSummary [$ key ] as $ entry ):
355+ if (empty ($ card [ ' summary ' ] [$ key ])) continue ;
356+ foreach ($ card [ ' summary ' ] [$ key ] as $ entry ):
321357?>
322358 <tr>
323359 <td><i class="material-icons md-18"><?php echo $ meta ['icon ' ] ?> </i> <?php echo $ meta ['label ' ] ?> </td>
@@ -329,16 +365,12 @@ function formatBitrate($bps) {
329365 </tbody>
330366 </table>
331367 </div>
332- </div>
333368<?php endif ; ?>
334369
335- <!-- Active Decoder Sessions -->
336- <?php if (!empty ($ quadraDetailed ['decoder ' ])): ?>
337- <div class="card mb-3">
338- <div class="card-header">
339- <i class="material-icons md-18">input</i> Active Decoder Sessions (<?php echo count ($ quadraDetailed ['decoder ' ]) ?> )
340- </div>
341- <div class="card-body table-responsive">
370+ <!-- Active Decoder Sessions -->
371+ <?php if (!empty ($ card ['detailed ' ]['decoder ' ])): ?>
372+ <h6><i class="material-icons md-18">input</i> Active Decoder Sessions (<?php echo count ($ card ['detailed ' ]['decoder ' ]) ?> )</h6>
373+ <div class="table-responsive mb-3">
342374 <table class="table table-sm table-striped table-hover">
343375 <thead class="thead-highlight text-left">
344376 <tr>
@@ -357,7 +389,7 @@ function formatBitrate($bps) {
357389$ totalDecoderFps = 0 ;
358390$ totalDecoderInFrames = 0 ;
359391$ totalDecoderOutFrames = 0 ;
360- foreach ($ quadraDetailed ['decoder ' ] as $ decoder ):
392+ foreach ($ card [ ' detailed ' ] ['decoder ' ] as $ decoder ):
361393 $ totalDecoderFps += floatval ($ decoder ['FrameRate ' ] ?? 0 );
362394 $ totalDecoderInFrames += intval ($ decoder ['InFrame ' ] ?? 0 );
363395 $ totalDecoderOutFrames += intval ($ decoder ['OutFrame ' ] ?? 0 );
@@ -387,16 +419,12 @@ function formatBitrate($bps) {
387419 </tfoot>
388420 </table>
389421 </div>
390- </div>
391422<?php endif ; ?>
392423
393- <!-- Active Encoder Sessions -->
394- <?php if (!empty ($ quadraDetailed ['encoder ' ])): ?>
395- <div class="card mb-3">
396- <div class="card-header">
397- <i class="material-icons md-18">output</i> Active Encoder Sessions (<?php echo count ($ quadraDetailed ['encoder ' ]) ?> )
398- </div>
399- <div class="card-body table-responsive">
424+ <!-- Active Encoder Sessions -->
425+ <?php if (!empty ($ card ['detailed ' ]['encoder ' ])): ?>
426+ <h6><i class="material-icons md-18">output</i> Active Encoder Sessions (<?php echo count ($ card ['detailed ' ]['encoder ' ]) ?> )</h6>
427+ <div class="table-responsive mb-3">
400428 <table class="table table-sm table-striped table-hover">
401429 <thead class="thead-highlight text-left">
402430 <tr>
@@ -420,7 +448,7 @@ function formatBitrate($bps) {
420448$ totalEncoderAvgBitrate = 0 ;
421449$ totalEncoderInFrames = 0 ;
422450$ totalEncoderOutFrames = 0 ;
423- foreach ($ quadraDetailed ['encoder ' ] as $ encoder ):
451+ foreach ($ card [ ' detailed ' ] ['encoder ' ] as $ encoder ):
424452 $ totalEncoderFps += floatval ($ encoder ['FrameRate ' ] ?? 0 );
425453 $ totalEncoderBitrate += intval ($ encoder ['BR ' ] ?? 0 );
426454 $ totalEncoderAvgBitrate += intval ($ encoder ['AvgBR ' ] ?? 0 );
@@ -457,9 +485,12 @@ function formatBitrate($bps) {
457485 </tfoot>
458486 </table>
459487 </div>
460- </div>
461488<?php endif ; ?>
462489
490+ </div><!-- card-body -->
491+ </div><!-- card -->
492+ <?php endforeach ; ?>
493+
463494<?php endif ; ?>
464495 </div><!-- content -->
465496</div>
0 commit comments