- Code refactored, DIagsPt1 and 2 moved into there own folder called DIagnostics
- Pre tests and final tests moved into a AiQ tests
- Mobile Pre Tests  added
- Mobile pre test - Added firmware check for the SRZ
This commit is contained in:
2025-12-22 14:37:43 +00:00
parent 7aba890514
commit 872be2e105
6 changed files with 667 additions and 471 deletions

162
AiQ Tests/AiQTests.cs Normal file
View File

@@ -0,0 +1,162 @@
using AiQ_GUI;
using AiQ_GUI.AiQ_Tests;
public class AiQTests
{
public static async void AiQPreTest()
{
if (!await CameraModules.SetZoomLockOn(MainForm.Instance.CamOnTest.IP))
Helper.RestartApp();
string LEDreply = await FlexiAPI.APIHTTPLED(MainForm.Instance.CamOnTest.IP, LEDPOWER.MID); // Set LED's to medium (0x30)
if (!LEDreply.Contains("Power levels set successfully"))
MainForm.Instance.AddToActionsList($"LED level could not be set: {LEDreply}", Level.ERROR);
await CameraModules.FactoryResetModules(MainForm.Instance.CamOnTest.IP); // Reset both modules and double check
MainForm.Instance.sshData = SSH.CollectSSHData(MainForm.Instance.CamOnTest.IP); // SSH into camera to get Vaxtor packages, filesystem size and if tailscale is installed.
await SSH.CheckFSSize(MainForm.Instance.CamOnTest.IP, MainForm.Instance.LblFilesystemSize, MainForm.Instance.sshData); // Check Filesystem size is between 100GB & 150GB
Helper.DCPowerCheck(MainForm.Instance.LblDC); // If the camera is DC powered check it is within limits
// Requests, deserialises and checks the diagnostics API is correct
await TestingFunctions.CheckDiagsAPIPt1();
// Check module has gone to default config
CameraModules.CheckCamModule(TestingFunctions.DiagsAPI.IRmodule, MainForm.Instance.LblIRModule, MainForm.Instance.CamOnTest); // IR
CameraModules.CheckCamModule(TestingFunctions.DiagsAPI.OVmodule, MainForm.Instance.LblOVModule, MainForm.Instance.CamOnTest); // OV
// Check voltage and current are OK.
LED.CheckLEDs(TestingFunctions.DiagsAPI.LedVoltage, MainForm.Instance.LblLEDV, "V", CameraAccessInfo.LED_V); // Voltage
LED.CheckLEDs(TestingFunctions.DiagsAPI.LedCurrent, MainForm.Instance.LblLEDI, "mA", CameraAccessInfo.LED_I); // Current
MainForm.Instance.Refresh(); // Make sure all labels are updated before checking them
// If there are any actions identified then fail the test.
// If any labels are red then fail. Only labels in panel so can foreach on labels not controls
if (MainForm.Instance.RhTxBxActions.Text.Length < 2 && MainForm.Instance.PnlLbls.Controls.OfType<Label>().Any(c => c.ForeColor == Color.Red) == false)
{
// If camera already has a model or serial then ask if it is new
if (RegexCache.SerialRegex().IsMatch(TestingFunctions.DiagsAPI.serialNumber) || RegexCache.ModelRegex().IsMatch(TestingFunctions.DiagsAPI.modelNumber))
{
if (await MainForm.Instance.DisplayQuestion($"Would you like to allocate a serial number to this camera?"))
await MainForm.Instance.AllocateSerial();
else if (GoogleAPI.UpdateSpreadSheetRePreTest(CameraAccessInfo.SpreadsheetID, MainForm.Instance.Vers) != "OK") // If rerun might be different values so update SS
MainForm.Instance.AddToActionsList("Failed to write to spreadsheet, please check manually", Level.WARNING);
// else if (Excel.UpdateSpreadSheetPreTest(CameraAccessInfo.SpreadsheetID, Vers, CamOnTest.GetCamDesc(), CamOnTest.Model) != "OK")
// AddToActionsList("Failed to write to spreadsheet, please check manually");
}
else // No serial or model so allocate one
await MainForm.Instance.AllocateSerial();
if (MainForm.Instance.RhTxBxActions.Text.Length < 2 && MainForm.Instance.PnlLbls.Controls.OfType<Label>().Any(c => c.ForeColor == Color.Red) == false)
await MainForm.Instance.PreTestPassed();
}
else
{
await MainForm.Instance.PreTestFailed("Diagnostic Failure");
}
}
public static async void AiQFinalTest()
{
if (MainForm.Instance.LblTestTubePing.Text == "❌") // No test tube so test like an IQ
{
string LEDreply = await FlexiAPI.APIHTTPLED(MainForm.Instance.CamOnTest.IP, LEDPOWER.SAFE); // Set LED's to safe (0x0E) to help with eye safety and trim check.
if (!LEDreply.Contains("Power levels set successfully"))
MainForm.Instance.AddToActionsList($"LED level could not be set: {LEDreply}", Level.ERROR);
}
else if (!await TestTube.CheckInTestTube(MainForm.Instance.CamOnTest.IP)) // Sets LED's to medium power after checking it is in the test tube
await MainForm.Instance.TestFailed(MainForm.Instance.BtnStartTest, "Camera not in test tube");
Task VisCheck = Helper.VisualCheck(MainForm.Instance.BtnStartTest);
if (!await CameraModules.ZoomModules("1F40", MainForm.Instance.CamOnTest.IP)) // Zoom to 8000 (1F40h) at the same time.
await MainForm.Instance.TestFailed(MainForm.Instance.BtnStartTest, "Could not zoom modules to 8000");
if (!await CameraModules.SetZoomLockOn(MainForm.Instance.CamOnTest.IP))
Helper.RestartApp();
await Task.Delay(1000); // Without sleep it kept failing the factory reset as camera modules were not ready yet
await CameraModules.FactoryResetModules(MainForm.Instance.CamOnTest.IP); // Reset both modules and double check
string VISCAReply = await FlexiAPI.APIHTTPVISCA(MainForm.Instance.CamOnTest.IP, "8101043903FF", true); // Manual mode to be able to manipulate the SIG settings.
if (VISCAReply != "9041FF9051FF")
MainForm.Instance.AddToActionsList("Couldn't set to manual mode", Level.ERROR);
await CameraModules.SetSIG(MainForm.Instance.CbBxShutter, MainForm.Instance.CbBxIris, MainForm.Instance.CbBxGain, MainForm.Instance.CamOnTest.IP); // Set SIG according to the drop downs in settings for a good picture ready for image check
await ImageProcessing.ImageCheck(MainForm.Instance.PicBxOV, MainForm.Instance.PicBxIRF2, MainForm.Instance.PicBxIRF16, MainForm.Instance.LblIRImageF2, MainForm.Instance.LblIRImageF16, MainForm.Instance.CamOnTest); // Populates the picture boxes and checks iris changes
await VisCheck; // Before changing UI elements wait for user to finish Visual check
MainForm.Instance.TabImagesandSettings.SelectedIndex = 2; // Swaps to the images tab
MainForm.Instance.Refresh(); // Show user things are happening by displaying images taken
// TODO - Force expire sighting.
Task Wait = Task.Delay(5000); // Wait for 5 seconds to allow the camera to zoom in, set settings and capture some plates before auto trim
if (CameraAccessInfo.HardwareExtras.Contains("GPS")) // Check GPS if the hardware has it
await FlexiAPI.GPSFix(MainForm.Instance.CamOnTest.IP);
// While waiting do the SSH tasks.
MainForm.Instance.sshData = SSH.CollectSSHData(MainForm.Instance.CamOnTest.IP); // SSH into camera to get Vaxtor packages, filesystem size and if tailscale is installed.
await SSH.CheckFSSize(MainForm.Instance.CamOnTest.IP, MainForm.Instance.LblFilesystemSize, MainForm.Instance.sshData); // Check Filesystem size is between 100GB & 150GB
Helper.DCPowerCheck(MainForm.Instance.LblDC); // If the camera is DC powered check it is within limits
if (CameraAccessInfo.HardwareExtras.Contains("4G")) // If it is a router camera then test the router.
{
MainForm.Instance.LblRouter.Visible = true;
if (Router.CheckRouter(Router.GetRouterInfo()))
MainForm.Instance.LblRouter.Text += "OK";
else
MainForm.Instance.LblRouter.Text += "Error with router";
}
await Wait; // Finished to 5s wait
await FlexiAPI.SetTrim(MainForm.Instance.CamOnTest.IP, MainForm.Instance.LblTestTubePing.Text); // Auto trims the cameras, some plates should have been captured in the meantime
if (!await CameraModules.ZoomModules("0000", MainForm.Instance.CamOnTest.IP)) // Zoom to full wide
await MainForm.Instance.TestFailed(MainForm.Instance.BtnStartTest, "Could not zoom modules to full wide");
await Task.Delay(1000); // Wait to be sure cameras are zoomed out.
await CameraModules.FactoryResetModules(MainForm.Instance.CamOnTest.IP); // Reset both modules and double check
if (MainForm.Instance.LblTestTubePing.Text == "❌") // Set LED's to MID in prep for diagnostics API
{
string LEDreply = await FlexiAPI.APIHTTPLED(MainForm.Instance.CamOnTest.IP, LEDPOWER.MID); // Set LED's to medium (0x30)
if (!LEDreply.Contains("Power levels set successfully"))
MainForm.Instance.AddToActionsList($"LED level could not be set: {LEDreply}", Level.ERROR);
}
await FlexiAPI.SetVaxtorMinMaxPlate(MainForm.Instance.CamOnTest.IP);
DateTime PCTime = DateTime.Now; // Grab PC time as close to the API as possible to pass onto PDF later
await TestingFunctions.CheckDiagsAPIPt1(); // Requests, deserialises and checks the diagnostics API is correct
await TestingFunctions.CheckDiagsAPIPt2(); // For only final test parts
// Check module has gone to default config
CameraModules.CheckCamModule(TestingFunctions.DiagsAPI.IRmodule, MainForm.Instance.LblIRModule, MainForm.Instance.CamOnTest); // IR
CameraModules.CheckCamModule(TestingFunctions.DiagsAPI.OVmodule, MainForm.Instance.LblOVModule, MainForm.Instance.CamOnTest); // OV
// Check voltage and current are OK.
LED.CheckLEDs(TestingFunctions.DiagsAPI.LedVoltage, MainForm.Instance.LblLEDV, "V", CameraAccessInfo.LED_V); // Voltage
LED.CheckLEDs(TestingFunctions.DiagsAPI.LedCurrent, MainForm.Instance.LblLEDI, "mA", CameraAccessInfo.LED_I); // Current
MainForm.Instance.Refresh(); // Make sure all labels are updated before checking them
// If there are any actions identified then fail the test.
// If any labels are red then fail. Only labels in panel so can foreach on labels not controls
if (MainForm.Instance.RhTxBxActions.Text.Length > 2 || MainForm.Instance.PnlLbls.Controls.OfType<Label>().Any(c => c.ForeColor == Color.Red) == true)
await MainForm.Instance.TestFailed(MainForm.Instance.BtnStartTest, "Diagnostic Failure");// If approved then pass otherwise GUI would have restarted before getting to TestPassed.
await MainForm.Instance.TestPassed(PCTime);
}
}

242
AiQ Tests/Diagnostics.cs Normal file
View File

@@ -0,0 +1,242 @@
using Renci.SshNet.Common;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
namespace AiQ_GUI.AiQ_Tests
{
public class TestingFunctions
{
public static Diags DiagsAPI = new();
// Colours
public static readonly Color BtnColour = Color.FromArgb(70, 65, 80);
public static readonly Color TxBxColour = Color.FromArgb(53, 51, 64);
// ***** Testing functions *****
public static async Task CheckDiagsAPIPt1() // Parts done on pre and final test
{
DiagsAPI = await FlexiAPI.GetDiagnostics(MainForm.Instance.CamOnTest.IP); // Diagnostic API request
MainForm.Instance.lblFlexiVer.Text += DiagsAPI.FlexiVersion; // Check Flexi Version
if (DiagsAPI.FlexiVersion == UniversalData.ExpFlexiVer)
{
MainForm.Instance.lblFlexiVer.ForeColor = Color.LightGreen;
}
else
{
MainForm.Instance.lblFlexiVer.Text += " Expected = " + UniversalData.ExpFlexiVer;
MainForm.Instance.lblFlexiVer.ForeColor = Color.Red;
}
MainForm.Instance.lblFlexiRev.Text += DiagsAPI.FlexiRevision; // Check Flexi Revision
if (DiagsAPI.FlexiRevision == UniversalData.ExpFlexiRev)
{
MainForm.Instance.lblFlexiRev.ForeColor = Color.LightGreen;
}
else
{
MainForm.Instance.lblFlexiRev.Text += " Expected = " + UniversalData.ExpFlexiRev;
MainForm.Instance.lblFlexiRev.ForeColor = Color.Red;
}
MainForm.Instance.lblMac.Text += DiagsAPI.MAC; // Display MAC
if (RegexCache.MACRegexNVIDIA().IsMatch(DiagsAPI.MAC)) // Checks it is in the right format and is a NVIDIA registered MAC address
{
MainForm.Instance.lblMac.ForeColor = Color.LightGreen;
}
else if (RegexCache.MACRegex().IsMatch(DiagsAPI.MAC)) // Is a valid MAC, but not NVIDIA
{
MainForm.Instance.lblMac.ForeColor = Color.Red;
MainForm.Instance.AddToActionsList($"{DiagsAPI.MAC} not recognised as NVIDIA MAC address", Level.ERROR);
}
else
{
MainForm.Instance.lblMac.ForeColor = Color.Red;
MainForm.Instance.AddToActionsList($"{DiagsAPI.MAC} not recognised as a MAC address", Level.ERROR);
}
// Check timestamp
DateTime dateTime = new(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
dateTime = dateTime.AddSeconds(DiagsAPI.timeStamp).ToLocalTime();
MainForm.Instance.lbltimestamp.Text += dateTime;
long timediff = DateTimeOffset.UtcNow.ToUnixTimeSeconds() - DiagsAPI.timeStamp;
if (timediff > 10) // Over 10 seconds ago
{
MainForm.Instance.lbltimestamp.Text += $" Time behind by {timediff}s";
MainForm.Instance.lbltimestamp.ForeColor = Color.Red;
}
else if (timediff < 0) // Time is in the future.
{
MainForm.Instance.lbltimestamp.Text += $" Time is in the future by {Math.Abs(timediff)}s";
MainForm.Instance.lbltimestamp.ForeColor = Color.Red;
}
else
MainForm.Instance.lbltimestamp.ForeColor = Color.LightGreen;
MainForm.Instance.lblTemp.Text += DiagsAPI.IntTemperature + "°C"; // Diagnostic API request
if (DiagsAPI.IntTemperature > 20 && DiagsAPI.IntTemperature < 70)
MainForm.Instance.lblTemp.ForeColor = Color.LightGreen;
else
MainForm.Instance.lblTemp.ForeColor = Color.Red;
MainForm.Instance.lblZoomLock.Text += DiagsAPI.zoomLock;
if (DiagsAPI.zoomLock == true)
{
if (DiagsAPI.IRmodule.zoom == DiagsAPI.OVmodule.zoom) // Checks if zoomlock is doing what is says it should
{
MainForm.Instance.lblZoomLock.ForeColor = Color.LightGreen;
}
else
{
MainForm.Instance.lblZoomLock.Text += $" Zoomlock on but {DiagsAPI.IRmodule.zoom}≠{DiagsAPI.OVmodule.zoom}";
MainForm.Instance.lblZoomLock.ForeColor = Color.Red;
}
}
else
MainForm.Instance.lblZoomLock.ForeColor = Color.Red;
}
public static async Task CheckDiagsAPIPt2() // Parts only done on final test
{
if (MainForm.Instance.RhTxBxActions.Text.Contains("Error reading JSON")) // If failed to deserialise in part 1
return;
try // In case serial or model are blank
{
MainForm.Instance.lblModel.Text += DiagsAPI.modelNumber; // Update labels with serial and model
MainForm.Instance.lblSerial.Text += DiagsAPI.serialNumber;
if (RegexCache.SerialRegex().IsMatch(DiagsAPI.serialNumber) && RegexCache.ModelRegex().IsMatch(DiagsAPI.modelNumber))
{
MainForm.Instance.lblSerial.ForeColor = MainForm.Instance.lblModel.ForeColor = Color.LightGreen; // Set both to green
if (DiagsAPI.modelNumber != MainForm.Instance.CamOnTest.Model)
{
MainForm.Instance.AddToActionsList("Model number in camera doesn't match what has been selected", Level.WARNING);
MainForm.Instance.lblModel.ForeColor = Color.Red;
}
else if (!GoogleAPI.CheckWIP(DiagsAPI.serialNumber, CameraAccessInfo.SpreadsheetID)) // Check WIP column in serial number register, if not ticked then RMA
{
MainForm.Instance.CamOnTest.RMANum = GoogleAPI.CheckRMANum(DiagsAPI.serialNumber, DiagsAPI.modelNumber); // Corrected by qualifying with the type name
if (MainForm.Instance.CamOnTest.RMANum == 0) // Couldn't find RMA num in spreadsheet
{
MainForm.Instance.CamOnTest.RMANum = Convert.ToInt32(await MainForm.Instance.DisplayInput("What is the RMA number?"));
if (MainForm.Instance.CamOnTest.RMANum == -1) // Means they chose the 'I don't know' option
await MainForm.Instance.TestFailed(MainForm.Instance.BtnStartTest, "Please get RMA number from operations team before continuing");
}
// Found RMA num and want to verify it with user
else if (!await MainForm.Instance.DisplayQuestion($"Is {MainForm.Instance.CamOnTest.RMANum} the RMA Number?")) // '!' because if its not the right RMA number let the user to it manually
{
MainForm.Instance.CamOnTest.RMANum = Convert.ToInt32(await MainForm.Instance.DisplayInput("What is the RMA number?"));
if (MainForm.Instance.CamOnTest.RMANum == -1) // Means they chose the 'I don't know' option
await MainForm.Instance.TestFailed(MainForm.Instance.BtnStartTest, "Please get RMA number from operations team before continuing");
}
}
}
else
{
MainForm.Instance.AddToActionsList("Camera has not been given a valid serial and model number, suggest you run through pre test again and check serial number register for any issues.", Level.ERROR);
}
}
catch { }
// Check licenses
List<string> licensesOnCam = []; // Temporary list for licenses on camera
if (DiagsAPI.licenses.saf1)
licensesOnCam.Add("SAF1");
if (DiagsAPI.licenses.saf2)
licensesOnCam.Add("SAF2");
if (DiagsAPI.licenses.saf3)
licensesOnCam.Add("SAF3");
if (DiagsAPI.licenses.saf4)
licensesOnCam.Add("SAF4");
if (DiagsAPI.licenses.audit)
licensesOnCam.Add("Audit");
if (DiagsAPI.licenses.stream)
licensesOnCam.Add("Stream");
if (MainForm.Instance.sshData.tailscale)
licensesOnCam.Add("Tailscale");
if (licensesOnCam.Count == 0) // No licenses found
MainForm.Instance.lblLic.Text += "None";
else if (licensesOnCam.Count != 0) // Join them comma and space seperated for displaying
MainForm.Instance.lblLic.Text += string.Join(", ", licensesOnCam);
MainForm.Instance.lblLic.ForeColor = Color.LightGreen;
double CPUround = Math.Round(DiagsAPI.CPUusage); // Check CPU usage isn't near max
MainForm.Instance.LblCPUusage.Text += CPUround + "%";
if (CPUround <= 50)
{
MainForm.Instance.LblCPUusage.Text += " Unexpectedly low CPU usage";
MainForm.Instance.LblCPUusage.ForeColor = Color.Red;
}
else if (CPUround >= 98)
{
MainForm.Instance.LblCPUusage.Text += " Unexpectedly high CPU usage";
MainForm.Instance.LblCPUusage.ForeColor = Color.Red;
}
else
{
MainForm.Instance.LblCPUusage.ForeColor = Color.LightGreen;
}
// Check Vaxtor if it doesn't need or have license OR has and wants one then pass
if (CameraAccessInfo.VaxtorLic == false && DiagsAPI.licenses.raptorKeyID == "Not Licensed" || CameraAccessInfo.VaxtorLic == true && DiagsAPI.licenses.raptorKeyID != "Not Licensed")
{
MainForm.Instance.lblVaxtor.Text += DiagsAPI.licenses.raptorKeyID;
MainForm.Instance.lblVaxtor.ForeColor = Color.LightGreen;
}
else if (await MainForm.Instance.DisplayQuestion("Was this camera licensed manually?"))
{
string ProdcutKeyID = await MainForm.Instance.DisplayInput("What is the Key ID?", false);
if (RegexCache.VaxtorRegex().IsMatch(ProdcutKeyID)) // Means they chose the 'I don't know' option or isn't valid Key ID
{
Access.Stats("Please Get A Valid Vaxtor Product Key Before Continuing", MainForm.Instance.CamOnTest.Model);
await MainForm.Instance.TestFailed(MainForm.Instance.BtnStartTest, "Please get a valid Vaxtor Product Key before continuing");
}
DiagsAPI.licenses.raptorKeyID = MainForm.Instance.TxBxProductKey.Text;
MainForm.Instance.lblVaxtor.Text += DiagsAPI.licenses.raptorKeyID;
MainForm.Instance.lblVaxtor.ForeColor = Color.LightGreen;
}
else // Should have license but doesn't OR shouldn't have but does + any other unforseen circumstance then fail
{
MainForm.Instance.lblVaxtor.Text += DiagsAPI.licenses.raptorKeyID;
MainForm.Instance.lblVaxtor.ForeColor = Color.Red;
}
// Check trim is within 10% both horizontally and vertically, from auto set done earlier in the test
MainForm.Instance.lblTrim.Text += "H: " + DiagsAPI.trim[0] + " V: " + DiagsAPI.trim[1];
// Offset accounted for in the SetTrim function, so value should be close to 0,0.
const int HMax = 96; // 5% of 1920 each way = ±96
const int VMax = 54; // 5% of 1080 each way = ±54
if (Math.Abs(DiagsAPI.trim[0]) <= HMax && Math.Abs(DiagsAPI.trim[1]) <= VMax)
MainForm.Instance.lblTrim.ForeColor = Color.LightGreen;
else
MainForm.Instance.lblTrim.ForeColor = Color.Red;
}
}
}

118
AiQ_GUI.Designer.cs generated
View File

@@ -154,6 +154,8 @@ namespace AiQ_GUI
BtnUploadBlob = new Button();
CkBxTickAll = new CheckBox();
BtnSoak = new Button();
Mobile = new TabPage();
BtnUpFirm = new Button();
ToolTipAvailable = new ToolTip(components);
TimerDDC = new System.Windows.Forms.Timer(components);
LblGUIVers = new Label();
@@ -180,6 +182,7 @@ namespace AiQ_GUI
TabSettings.SuspendLayout();
TabImages.SuspendLayout();
TabSoak.SuspendLayout();
Mobile.SuspendLayout();
SuspendLayout();
//
// CbBxCameraModel
@@ -199,6 +202,8 @@ namespace AiQ_GUI
CbBxCameraModel.Name = "CbBxCameraModel";
CbBxCameraModel.Size = new Size(494, 25);
CbBxCameraModel.TabIndex = 188;
CbBxCameraModel.SelectedIndexChanged += CbBxCameraModel_SelectedIndexChanged;
//
// BtnStartTest
//
BtnStartTest.BackColor = Color.FromArgb(70, 65, 80);
@@ -1686,6 +1691,7 @@ namespace AiQ_GUI
TabImagesandSettings.Controls.Add(TabSettings);
TabImagesandSettings.Controls.Add(TabImages);
TabImagesandSettings.Controls.Add(TabSoak);
TabImagesandSettings.Controls.Add(Mobile);
TabImagesandSettings.Font = new Font("Segoe UI Semibold", 9F, FontStyle.Bold);
TabImagesandSettings.ItemSize = new Size(60, 20);
TabImagesandSettings.Location = new Point(512, 112);
@@ -2018,6 +2024,33 @@ namespace AiQ_GUI
BtnSoak.UseVisualStyleBackColor = false;
BtnSoak.Click += BtnSoak_Click;
//
// Mobile
//
Mobile.BackColor = Color.FromArgb(39, 37, 55);
Mobile.Controls.Add(BtnUpFirm);
Mobile.Location = new Point(4, 24);
Mobile.Name = "Mobile";
Mobile.Padding = new Padding(3);
Mobile.Size = new Size(411, 806);
Mobile.TabIndex = 4;
Mobile.Text = "Mobile";
//
// BtnUpFirm
//
BtnUpFirm.BackColor = Color.FromArgb(70, 65, 80);
BtnUpFirm.FlatAppearance.BorderColor = Color.FromArgb(70, 65, 80);
BtnUpFirm.FlatAppearance.BorderSize = 0;
BtnUpFirm.FlatStyle = FlatStyle.Flat;
BtnUpFirm.Font = new Font("Segoe UI Semibold", 10F, FontStyle.Bold);
BtnUpFirm.ForeColor = SystemColors.Control;
BtnUpFirm.Location = new Point(12, 17);
BtnUpFirm.Margin = new Padding(4, 3, 4, 3);
BtnUpFirm.Name = "BtnUpFirm";
BtnUpFirm.Size = new Size(181, 49);
BtnUpFirm.TabIndex = 241;
BtnUpFirm.Text = "Upload Firmware";
BtnUpFirm.UseVisualStyleBackColor = false;
//
// ToolTipAvailable
//
ToolTipAvailable.AutoPopDelay = 2000;
@@ -2071,10 +2104,8 @@ namespace AiQ_GUI
CbBxCamType.Name = "CbBxCamType";
CbBxCamType.Size = new Size(233, 25);
CbBxCamType.TabIndex = 241;
CbBxCamType.Text = "Select Camera Type";
this.CbBxCamType.SelectedIndexChanged += new System.EventHandler(this.CbBxCamType_SelectedIndexChanged);
CbBxCamType.Text = "AiQ";
CbBxCamType.SelectedIndexChanged += CbBxCamType_SelectedIndexChanged;
//
// MainForm
//
@@ -2136,13 +2167,14 @@ namespace AiQ_GUI
TabImages.PerformLayout();
TabSoak.ResumeLayout(false);
TabSoak.PerformLayout();
Mobile.ResumeLayout(false);
ResumeLayout(false);
PerformLayout();
}
#endregion
private System.Windows.Forms.Button BtnStartTest;
public System.Windows.Forms.Button BtnStartTest;
private System.Windows.Forms.Button BtnFindCams;
private System.Windows.Forms.ComboBox CbBxFoundCams;
private System.Windows.Forms.Button BtnRestart;
@@ -2150,33 +2182,33 @@ namespace AiQ_GUI
private System.Windows.Forms.Button BtnClose;
private System.Windows.Forms.PictureBox PicBxMAV;
private System.Windows.Forms.PictureBox PicBxAiQ;
private System.Windows.Forms.Label lblFlexiVer;
private System.Windows.Forms.Label lblFlexiRev;
private System.Windows.Forms.Label lblMac;
private System.Windows.Forms.Label lbltimestamp;
private System.Windows.Forms.Label lblSerial;
private System.Windows.Forms.Label lblModel;
private System.Windows.Forms.Label lblLic;
private System.Windows.Forms.Label lblVaxtor;
private System.Windows.Forms.Label lblTemp;
private System.Windows.Forms.Label lblTrim;
private System.Windows.Forms.Label lblZoomLock;
private System.Windows.Forms.Label LblLEDI;
private System.Windows.Forms.Label LblLEDV;
private System.Windows.Forms.ComboBox CbBxCameraModel;
public System.Windows.Forms.Label lblFlexiVer;
public System.Windows.Forms.Label lblFlexiRev;
public System.Windows.Forms.Label lblMac;
public System.Windows.Forms.Label lbltimestamp;
public System.Windows.Forms.Label lblSerial;
public System.Windows.Forms.Label lblModel;
public System.Windows.Forms.Label lblLic;
public System.Windows.Forms.Label lblVaxtor;
public System.Windows.Forms.Label lblTemp;
public System.Windows.Forms.Label lblTrim;
public System.Windows.Forms.Label lblZoomLock;
public System.Windows.Forms.Label LblLEDI;
public System.Windows.Forms.Label LblLEDV;
public System.Windows.Forms.ComboBox CbBxCameraModel;
private System.Windows.Forms.Button BtnPreTest;
private System.Windows.Forms.Label LblOVModule;
private System.Windows.Forms.Label LblIRModule;
public System.Windows.Forms.Label LblOVModule;
public System.Windows.Forms.Label LblIRModule;
private System.Windows.Forms.Button BtnTest;
private System.Windows.Forms.PictureBox PicBxIRF2;
private System.Windows.Forms.Label LblIRImageF2;
private System.Windows.Forms.PictureBox PicBxIRF16;
private System.Windows.Forms.PictureBox PicBxOV;
private System.Windows.Forms.Label LblOVImage;
private System.Windows.Forms.Label LblActions;
public System.Windows.Forms.PictureBox PicBxIRF2;
public System.Windows.Forms.Label LblIRImageF2;
public System.Windows.Forms.PictureBox PicBxIRF16;
public System.Windows.Forms.PictureBox PicBxOV;
public System.Windows.Forms.Label LblOVImage;
public System.Windows.Forms.Label LblActions;
private System.Windows.Forms.Panel PanelSettings;
public System.Windows.Forms.TextBox TxBxPsuIP;
private System.Windows.Forms.Label lblPowerIP;
public System.Windows.Forms.Label lblPowerIP;
private System.Windows.Forms.Label label2;
public System.Windows.Forms.TextBox TxBxTestTubeIP;
private System.Windows.Forms.Button BtnCancel;
@@ -2216,30 +2248,30 @@ namespace AiQ_GUI
private System.Windows.Forms.Button BtnDont;
private System.Windows.Forms.NumericUpDown RMANumBox;
private System.Windows.Forms.Button BtnEzOn;
private System.Windows.Forms.Panel PnlLbls;
public System.Windows.Forms.Panel PnlLbls;
private System.Windows.Forms.Button BtnOpenWebpage;
private System.Windows.Forms.Button BtnSet211;
private System.Windows.Forms.Label LblIRImageF16;
public System.Windows.Forms.Label LblIRImageF16;
private System.Windows.Forms.ToolTip ToolTipClipboard;
private System.Windows.Forms.TabControl TabImagesandSettings;
public System.Windows.Forms.TabControl TabImagesandSettings;
private System.Windows.Forms.TabPage TabImages;
private System.Windows.Forms.TabPage TabControls;
private System.Windows.Forms.Label LblPSUPing;
private System.Windows.Forms.Label LblTestTubePing;
public System.Windows.Forms.Label LblTestTubePing;
private System.Windows.Forms.Label LblZebraPing;
private System.Windows.Forms.Label LblEzPing;
private System.Windows.Forms.ToolTip ToolTipAvailable;
private System.Windows.Forms.Label LblCPUusage;
public System.Windows.Forms.Label LblCPUusage;
private System.Windows.Forms.Timer TimerDDC;
private System.Windows.Forms.Button BtnLicVaxtor;
private System.Windows.Forms.ComboBox CbBxShutter;
private System.Windows.Forms.ComboBox CbBxGain;
private System.Windows.Forms.ComboBox CbBxIris;
public System.Windows.Forms.ComboBox CbBxShutter;
public System.Windows.Forms.ComboBox CbBxGain;
public System.Windows.Forms.ComboBox CbBxIris;
private System.Windows.Forms.Label label10;
private System.Windows.Forms.TextBox TxBxProductKey;
private System.Windows.Forms.Label LblFilesystemSize;
public System.Windows.Forms.TextBox TxBxProductKey;
public System.Windows.Forms.Label LblFilesystemSize;
private Button BtnRerun;
private Label LblGUIVers;
public Label LblGUIVers;
private System.Windows.Forms.Timer timerTypeIP;
private Button BtnSetAll211;
public System.Windows.Forms.Timer TimerFlash;
@@ -2257,11 +2289,11 @@ namespace AiQ_GUI
private GroupBox groupBox1;
private GroupBox groupBox3;
private GroupBox groupBox4;
private Label LblDC;
public Label LblDC;
public ComboBox CbBxUserName;
private Button BtnZoom8000;
private Button BtnZoomWide;
private Label LblRouter;
public Label LblRouter;
private Button BtnUploadBlob;
private Button BtnFirewall;
private Button BtnAdminStart;
@@ -2269,7 +2301,9 @@ namespace AiQ_GUI
private Button BtnFactoryDefault;
private Button BtnUploadWonwooSetOV;
private Button BtnUploadWonwooSetIR;
private RichTextBox RhTxBxActions;
public RichTextBox RhTxBxActions;
public ComboBox CbBxCamType;
public TabPage Mobile;
private Button BtnUpFirm;
}
}

View File

@@ -1,7 +1,11 @@
using Newtonsoft.Json;
using AiQ_GUI.AiQ_Tests;
using Newtonsoft.Json;
using System.ComponentModel;
using System.Diagnostics;
using System.Net.Http.Json;
using System.Reflection;
using System.Text.Json;
using System.Windows.Forms;
namespace AiQ_GUI
{
@@ -17,11 +21,11 @@ namespace AiQ_GUI
{
// Classes
LocalDataStore localDataStore = new();
Diags DiagsAPI = new();
//public Diags DiagsAPI = new();
VaxtorLic VaxtorLicResp = new();
Versions Vers = new();
readonly Camera CamOnTest = new();
SSHData sshData = new();
public Versions Vers = new();
public readonly Camera CamOnTest = new();
public SSHData sshData = new();
private List<Camera> soakCameraList = [];
private List<CancellationTokenSource> soakCtsList = [];
@@ -34,6 +38,8 @@ namespace AiQ_GUI
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public static MainForm? Instance { get; private set; }
private TabPage CurrentTab; // remember what's currently inserted
public MainForm()
{
InitializeComponent();
@@ -61,14 +67,16 @@ namespace AiQ_GUI
BtnStartTest.Text = "Offline Mode";
}
// Hide on default so will only show based on the camera type selected later
TabImagesandSettings.TabPages.Remove(TabSoak);
TabImagesandSettings.TabPages.Remove(Mobile);
GUIUpdate.GUIVerShort = await guiVerTask; // Guess the GUI version will be first to finish
this.Name = "AiQ GUI V" + GUIUpdate.GUIVerShort;
LblGUIVers.Text += GUIUpdate.GUIVerShort;
await UniDataTask; // Have to wait for expected GUI version to compare to.
GUIUpdate.UpdateGUI(); // Check if a GUI update is available
// Load local data store
localDataStore = await LDSWAIT;
Logging.LogMessage("Opening GUI"); // Done after LDS to make sure directory exists.
@@ -91,22 +99,47 @@ namespace AiQ_GUI
await CheckHWOnline;
Flags.Start = false;
}
private void InsertCamTab(string camType)
{
// Remove previously inserted tab if present
if (CurrentTab != null && TabImagesandSettings.TabPages.Contains(CurrentTab))
TabImagesandSettings.TabPages.Remove(CurrentTab);
// Choose desired tab
TabPage desired = null;
if (camType == "Mobile") desired = Mobile;
else if (camType == "AiQ") desired = TabSoak;
// Insert desired tab if any
if (desired != null && !TabImagesandSettings.TabPages.Contains(desired))
{
int idx = Math.Min(3, TabImagesandSettings.TabPages.Count);
TabImagesandSettings.TabPages.Insert(idx, desired);
CurrentTab = desired;
}
else
{
CurrentTab = desired; // may be null
}
}
private async void CbBxCamType_SelectedIndexChanged(object sender, EventArgs e)
{
CbBxCameraModel.Items.Clear(); // REQUIRED
CbBxCameraModel.Items.Clear();
string camType = CbBxCamType.Text;
string[] models = await Task.Run(() => Access.ReadCamTypes(camType));
var camType = CbBxCamType.Text;
InsertCamTab(camType);
var models = await Task.Run(() => Access.ReadCamTypes(camType));
if (models != null && models.Length > 0)
CbBxCameraModel.Items.AddRange(models);
}
private void PopulateUIWithLDS(LocalDataStore lds)
{
CbBxUserName.Text = lds.User;
@@ -145,101 +178,14 @@ namespace AiQ_GUI
BtnPreTest.Enabled = BtnStartTest.Enabled = false; // Disable buttons to stop user rnning multiple tests at the same time.
Logging.LogMessage("Final Test Started");
if (LblTestTubePing.Text == "") // No test tube so test like an IQ
if (CbBxCameraModel.Text == "AiQ")
{
string LEDreply = await FlexiAPI.APIHTTPLED(CamOnTest.IP, LEDPOWER.SAFE); // Set LED's to safe (0x0E) to help with eye safety and trim check.
if (!LEDreply.Contains("Power levels set successfully"))
AddToActionsList($"LED level could not be set: {LEDreply}", Level.ERROR);
AiQTests.AiQFinalTest();
}
else if (!await TestTube.CheckInTestTube(CamOnTest.IP)) // Sets LED's to medium power after checking it is in the test tube
await TestFailed(BtnStartTest, "Camera not in test tube");
Task VisCheck = Helper.VisualCheck(BtnStartTest);
if (!await CameraModules.ZoomModules("1F40", CamOnTest.IP)) // Zoom to 8000 (1F40h) at the same time.
await TestFailed(BtnStartTest, "Could not zoom modules to 8000");
if (!await CameraModules.SetZoomLockOn(CamOnTest.IP))
Helper.RestartApp();
await Task.Delay(1000); // Without sleep it kept failing the factory reset as camera modules were not ready yet
await CameraModules.FactoryResetModules(CamOnTest.IP); // Reset both modules and double check
string VISCAReply = await FlexiAPI.APIHTTPVISCA(CamOnTest.IP, "8101043903FF", true); // Manual mode to be able to manipulate the SIG settings.
if (VISCAReply != "9041FF9051FF")
AddToActionsList("Couldn't set to manual mode",Level.ERROR);
await CameraModules.SetSIG(CbBxShutter, CbBxIris, CbBxGain, CamOnTest.IP); // Set SIG according to the drop downs in settings for a good picture ready for image check
await ImageProcessing.ImageCheck(PicBxOV, PicBxIRF2, PicBxIRF16, LblIRImageF2, LblIRImageF16, CamOnTest); // Populates the picture boxes and checks iris changes
await VisCheck; // Before changing UI elements wait for user to finish Visual check
TabImagesandSettings.SelectedIndex = 2; // Swaps to the images tab
this.Refresh(); // Show user things are happening by displaying images taken
// TODO - Force expire sighting.
Task Wait = Task.Delay(5000); // Wait for 5 seconds to allow the camera to zoom in, set settings and capture some plates before auto trim
if (CameraAccessInfo.HardwareExtras.Contains("GPS")) // Check GPS if the hardware has it
await FlexiAPI.GPSFix(CamOnTest.IP);
// While waiting do the SSH tasks.
sshData = SSH.CollectSSHData(CamOnTest.IP); // SSH into camera to get Vaxtor packages, filesystem size and if tailscale is installed.
await SSH.CheckFSSize(CamOnTest.IP, LblFilesystemSize, sshData); // Check Filesystem size is between 100GB & 150GB
Helper.DCPowerCheck(LblDC); // If the camera is DC powered check it is within limits
if (CameraAccessInfo.HardwareExtras.Contains("4G")) // If it is a router camera then test the router.
else if (CbBxCameraModel.Text == "Mobile")
{
LblRouter.Visible = true;
if (Router.CheckRouter(Router.GetRouterInfo()))
LblRouter.Text += "OK";
else
LblRouter.Text += "Error with router";
await PreTestPassed();
}
await Wait; // Finished to 5s wait
await FlexiAPI.SetTrim(CamOnTest.IP, LblTestTubePing.Text); // Auto trims the cameras, some plates should have been captured in the meantime
if (!await CameraModules.ZoomModules("0000", CamOnTest.IP)) // Zoom to full wide
await TestFailed(BtnStartTest, "Could not zoom modules to full wide");
await Task.Delay(1000); // Wait to be sure cameras are zoomed out.
await CameraModules.FactoryResetModules(CamOnTest.IP); // Reset both modules and double check
if (LblTestTubePing.Text == "❌") // Set LED's to MID in prep for diagnostics API
{
string LEDreply = await FlexiAPI.APIHTTPLED(CamOnTest.IP, LEDPOWER.MID); // Set LED's to medium (0x30)
if (!LEDreply.Contains("Power levels set successfully"))
AddToActionsList($"LED level could not be set: {LEDreply}", Level.ERROR);
}
await FlexiAPI.SetVaxtorMinMaxPlate(CamOnTest.IP);
DateTime PCTime = DateTime.Now; // Grab PC time as close to the API as possible to pass onto PDF later
await CheckDiagsAPIPt1(); // Requests, deserialises and checks the diagnostics API is correct
await CheckDiagsAPIPt2(); // For only final test parts
// Check module has gone to default config
CameraModules.CheckCamModule(DiagsAPI.IRmodule, LblIRModule, CamOnTest); // IR
CameraModules.CheckCamModule(DiagsAPI.OVmodule, LblOVModule, CamOnTest); // OV
// Check voltage and current are OK.
LED.CheckLEDs(DiagsAPI.LedVoltage, LblLEDV, "V", CameraAccessInfo.LED_V); // Voltage
LED.CheckLEDs(DiagsAPI.LedCurrent, LblLEDI, "mA", CameraAccessInfo.LED_I); // Current
this.Refresh(); // Make sure all labels are updated before checking them
// If there are any actions identified then fail the test.
// If any labels are red then fail. Only labels in panel so can foreach on labels not controls
if (RhTxBxActions.Text.Length > 2 || PnlLbls.Controls.OfType<Label>().Any(c => c.ForeColor == Color.Red) == true)
await TestFailed(BtnStartTest, "Diagnostic Failure");// If approved then pass otherwise GUI would have restarted before getting to TestPassed.
await TestPassed(PCTime);
}
private async void BtnPreTest_Click(object sender, EventArgs e)
@@ -247,68 +193,24 @@ namespace AiQ_GUI
// Show user test has started
BtnPreTest.BackColor = Color.Orange;
BtnPreTest.Text = "Pre-Test underway";
BtnPreTest.Enabled = BtnStartTest.Enabled = false; // Disable buttons to stop user rnning multiple tests at the same time.
BtnPreTest.Enabled = BtnStartTest.Enabled = false; // Disable buttons to stop user running multiple tests at the same time.
Logging.LogMessage("Pre Test Started");
if (!await CameraModules.SetZoomLockOn(CamOnTest.IP))
Helper.RestartApp();
string LEDreply = await FlexiAPI.APIHTTPLED(CamOnTest.IP, LEDPOWER.MID); // Set LED's to medium (0x30)
if (!LEDreply.Contains("Power levels set successfully"))
AddToActionsList($"LED level could not be set: {LEDreply}", Level.ERROR);
await CameraModules.FactoryResetModules(CamOnTest.IP); // Reset both modules and double check
sshData = SSH.CollectSSHData(CamOnTest.IP); // SSH into camera to get Vaxtor packages, filesystem size and if tailscale is installed.
await SSH.CheckFSSize(CamOnTest.IP, LblFilesystemSize, sshData); // Check Filesystem size is between 100GB & 150GB
Helper.DCPowerCheck(LblDC); // If the camera is DC powered check it is within limits
// Requests, deserialises and checks the diagnostics API is correct
await CheckDiagsAPIPt1();
// Check module has gone to default config
CameraModules.CheckCamModule(DiagsAPI.IRmodule, LblIRModule, CamOnTest); // IR
CameraModules.CheckCamModule(DiagsAPI.OVmodule, LblOVModule, CamOnTest); // OV
// Check voltage and current are OK.
LED.CheckLEDs(DiagsAPI.LedVoltage, LblLEDV, "V", CameraAccessInfo.LED_V); // Voltage
LED.CheckLEDs(DiagsAPI.LedCurrent, LblLEDI, "mA", CameraAccessInfo.LED_I); // Current
this.Refresh(); // Make sure all labels are updated before checking them
// If there are any actions identified then fail the test.
// If any labels are red then fail. Only labels in panel so can foreach on labels not controls
if (RhTxBxActions.Text.Length < 2 && PnlLbls.Controls.OfType<Label>().Any(c => c.ForeColor == Color.Red) == false)
if (CbBxCamType.Text == "AiQ")
{
// If camera already has a model or serial then ask if it is new
if (RegexCache.SerialRegex().IsMatch(DiagsAPI.serialNumber) || RegexCache.ModelRegex().IsMatch(DiagsAPI.modelNumber))
{
if (await DisplayQuestion($"Would you like to allocate a serial number to this camera?"))
await AllocateSerial();
else if (GoogleAPI.UpdateSpreadSheetRePreTest(CameraAccessInfo.SpreadsheetID, Vers) != "OK") // If rerun might be different values so update SS
AddToActionsList("Failed to write to spreadsheet, please check manually",Level.WARNING);
// else if (Excel.UpdateSpreadSheetPreTest(CameraAccessInfo.SpreadsheetID, Vers, CamOnTest.GetCamDesc(), CamOnTest.Model) != "OK")
// AddToActionsList("Failed to write to spreadsheet, please check manually");
}
else // No serial or model so allocate one
await AllocateSerial();
if (RhTxBxActions.Text.Length < 2 && PnlLbls.Controls.OfType<Label>().Any(c => c.ForeColor == Color.Red) == false)
await PreTestPassed();
AiQTests.AiQPreTest();
}
else
else if (CbBxCamType.Text == "Mobile")
{
await PreTestFailed("Diagnostic Failure");
await PreTestPassed();
}
}
// ***** Pass/Fails *****
private async Task TestPassed(DateTime PCTime)
public async Task TestPassed(DateTime PCTime)
{
// Updates Vaxtor versions, licenses and unticks WIP
string err = GoogleAPI.UpdateSpreadSheetFinalTest(CameraAccessInfo.SpreadsheetID, DiagsAPI, sshData, CamOnTest.RMANum);
string err = GoogleAPI.UpdateSpreadSheetFinalTest(CameraAccessInfo.SpreadsheetID, TestingFunctions.DiagsAPI, sshData, CamOnTest.RMANum);
if (err != string.Empty) // If there is an error message, display it
AddToActionsList("Failed to write to spreadsheet " + err, Level.ERROR);
@@ -437,7 +339,7 @@ namespace AiQ_GUI
Helper.RestartApp();
}
private async Task PreTestPassed()
public async Task PreTestPassed()
{
BtnPreTest.BackColor = Color.ForestGreen; // Indicators to the user the test has passed
BtnPreTest.Text = "Pre Test Passed";
@@ -454,7 +356,7 @@ namespace AiQ_GUI
Helper.RestartApp();
}
private async Task PreTestFailed(string ErrMssg)
public async Task PreTestFailed(string ErrMssg)
{
BtnPreTest.BackColor = Color.Maroon; // Indicators to the user the test has failed
BtnPreTest.Text = "Test Failed";
@@ -479,228 +381,7 @@ namespace AiQ_GUI
Helper.RestartApp();
}
// ***** Testing functions *****
private async Task CheckDiagsAPIPt1() // Parts done on pre and final test
{
DiagsAPI = await FlexiAPI.GetDiagnostics(CamOnTest.IP); // Diagnostic API request
lblFlexiVer.Text += DiagsAPI.FlexiVersion; // Check Flexi Version
if (DiagsAPI.FlexiVersion == UniversalData.ExpFlexiVer)
{
lblFlexiVer.ForeColor = Color.LightGreen;
}
else
{
lblFlexiVer.Text += " Expected = " + UniversalData.ExpFlexiVer;
lblFlexiVer.ForeColor = Color.Red;
}
lblFlexiRev.Text += DiagsAPI.FlexiRevision; // Check Flexi Revision
if (DiagsAPI.FlexiRevision == UniversalData.ExpFlexiRev)
{
lblFlexiRev.ForeColor = Color.LightGreen;
}
else
{
lblFlexiRev.Text += " Expected = " + UniversalData.ExpFlexiRev;
lblFlexiRev.ForeColor = Color.Red;
}
lblMac.Text += DiagsAPI.MAC; // Display MAC
if (RegexCache.MACRegexNVIDIA().IsMatch(DiagsAPI.MAC)) // Checks it is in the right format and is a NVIDIA registered MAC address
{
lblMac.ForeColor = Color.LightGreen;
}
else if (RegexCache.MACRegex().IsMatch(DiagsAPI.MAC)) // Is a valid MAC, but not NVIDIA
{
lblMac.ForeColor = Color.Red;
AddToActionsList($"{DiagsAPI.MAC} not recognised as NVIDIA MAC address", Level.ERROR);
}
else
{
lblMac.ForeColor = Color.Red;
AddToActionsList($"{DiagsAPI.MAC} not recognised as a MAC address", Level.ERROR);
}
// Check timestamp
DateTime dateTime = new(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
dateTime = dateTime.AddSeconds(DiagsAPI.timeStamp).ToLocalTime();
lbltimestamp.Text += dateTime;
long timediff = DateTimeOffset.UtcNow.ToUnixTimeSeconds() - DiagsAPI.timeStamp;
if (timediff > 10) // Over 10 seconds ago
{
lbltimestamp.Text += $" Time behind by {timediff}s";
lbltimestamp.ForeColor = Color.Red;
}
else if (timediff < 0) // Time is in the future.
{
lbltimestamp.Text += $" Time is in the future by {Math.Abs(timediff)}s";
lbltimestamp.ForeColor = Color.Red;
}
else
lbltimestamp.ForeColor = Color.LightGreen;
lblTemp.Text += DiagsAPI.IntTemperature + "°C"; // Diagnostic API request
if (DiagsAPI.IntTemperature > 20 && DiagsAPI.IntTemperature < 70)
lblTemp.ForeColor = Color.LightGreen;
else
lblTemp.ForeColor = Color.Red;
lblZoomLock.Text += DiagsAPI.zoomLock;
if (DiagsAPI.zoomLock == true)
{
if (DiagsAPI.IRmodule.zoom == DiagsAPI.OVmodule.zoom) // Checks if zoomlock is doing what is says it should
{
lblZoomLock.ForeColor = Color.LightGreen;
}
else
{
lblZoomLock.Text += $" Zoomlock on but {DiagsAPI.IRmodule.zoom}≠{DiagsAPI.OVmodule.zoom}";
lblZoomLock.ForeColor = Color.Red;
}
}
else
lblZoomLock.ForeColor = Color.Red;
}
private async Task CheckDiagsAPIPt2() // Parts only done on final test
{
if (RhTxBxActions.Text.Contains("Error reading JSON")) // If failed to deserialise in part 1
return;
try // In case serial or model are blank
{
lblModel.Text += DiagsAPI.modelNumber; // Update labels with serial and model
lblSerial.Text += DiagsAPI.serialNumber;
if (RegexCache.SerialRegex().IsMatch(DiagsAPI.serialNumber) && RegexCache.ModelRegex().IsMatch(DiagsAPI.modelNumber))
{
lblSerial.ForeColor = lblModel.ForeColor = Color.LightGreen; // Set both to green
if (DiagsAPI.modelNumber != CamOnTest.Model)
{
AddToActionsList("Model number in camera doesn't match what has been selected", Level.WARNING);
lblModel.ForeColor = Color.Red;
}
else if (!GoogleAPI.CheckWIP(DiagsAPI.serialNumber, CameraAccessInfo.SpreadsheetID)) // Check WIP column in serial number register, if not ticked then RMA
{
CamOnTest.RMANum = GoogleAPI.CheckRMANum(DiagsAPI.serialNumber, DiagsAPI.modelNumber); // Corrected by qualifying with the type name
if (CamOnTest.RMANum == 0) // Couldn't find RMA num in spreadsheet
{
CamOnTest.RMANum = Convert.ToInt32(await DisplayInput("What is the RMA number?"));
if (CamOnTest.RMANum == -1) // Means they chose the 'I don't know' option
await TestFailed(BtnStartTest, "Please get RMA number from operations team before continuing");
}
// Found RMA num and want to verify it with user
else if (!await DisplayQuestion($"Is {CamOnTest.RMANum} the RMA Number?")) // '!' because if its not the right RMA number let the user to it manually
{
CamOnTest.RMANum = Convert.ToInt32(await DisplayInput("What is the RMA number?"));
if (CamOnTest.RMANum == -1) // Means they chose the 'I don't know' option
await TestFailed(BtnStartTest, "Please get RMA number from operations team before continuing");
}
}
}
else
{
AddToActionsList("Camera has not been given a valid serial and model number, suggest you run through pre test again and check serial number register for any issues.", Level.ERROR);
}
}
catch { }
// Check licenses
List<string> licensesOnCam = []; // Temporary list for licenses on camera
if (DiagsAPI.licenses.saf1)
licensesOnCam.Add("SAF1");
if (DiagsAPI.licenses.saf2)
licensesOnCam.Add("SAF2");
if (DiagsAPI.licenses.saf3)
licensesOnCam.Add("SAF3");
if (DiagsAPI.licenses.saf4)
licensesOnCam.Add("SAF4");
if (DiagsAPI.licenses.audit)
licensesOnCam.Add("Audit");
if (DiagsAPI.licenses.stream)
licensesOnCam.Add("Stream");
if (sshData.tailscale)
licensesOnCam.Add("Tailscale");
if (licensesOnCam.Count == 0) // No licenses found
lblLic.Text += "None";
else if (licensesOnCam.Count != 0) // Join them comma and space seperated for displaying
lblLic.Text += string.Join(", ", licensesOnCam);
lblLic.ForeColor = Color.LightGreen;
double CPUround = Math.Round(DiagsAPI.CPUusage); // Check CPU usage isn't near max
LblCPUusage.Text += CPUround + "%";
if (CPUround <= 50)
{
LblCPUusage.Text += " Unexpectedly low CPU usage";
LblCPUusage.ForeColor = Color.Red;
}
else if (CPUround >= 98)
{
LblCPUusage.Text += " Unexpectedly high CPU usage";
LblCPUusage.ForeColor = Color.Red;
}
else
{
LblCPUusage.ForeColor = Color.LightGreen;
}
// Check Vaxtor if it doesn't need or have license OR has and wants one then pass
if (CameraAccessInfo.VaxtorLic == false && DiagsAPI.licenses.raptorKeyID == "Not Licensed" || CameraAccessInfo.VaxtorLic == true && DiagsAPI.licenses.raptorKeyID != "Not Licensed")
{
lblVaxtor.Text += DiagsAPI.licenses.raptorKeyID;
lblVaxtor.ForeColor = Color.LightGreen;
}
else if (await DisplayQuestion("Was this camera licensed manually?"))
{
string ProdcutKeyID = await DisplayInput("What is the Key ID?", false);
if (RegexCache.VaxtorRegex().IsMatch(ProdcutKeyID)) // Means they chose the 'I don't know' option or isn't valid Key ID
{
Access.Stats("Please Get A Valid Vaxtor Product Key Before Continuing", CamOnTest.Model);
await TestFailed(BtnStartTest, "Please get a valid Vaxtor Product Key before continuing");
}
DiagsAPI.licenses.raptorKeyID = TxBxProductKey.Text;
lblVaxtor.Text += DiagsAPI.licenses.raptorKeyID;
lblVaxtor.ForeColor = Color.LightGreen;
}
else // Should have license but doesn't OR shouldn't have but does + any other unforseen circumstance then fail
{
lblVaxtor.Text += DiagsAPI.licenses.raptorKeyID;
lblVaxtor.ForeColor = Color.Red;
}
// Check trim is within 10% both horizontally and vertically, from auto set done earlier in the test
lblTrim.Text += "H: " + DiagsAPI.trim[0] + " V: " + DiagsAPI.trim[1];
// Offset accounted for in the SetTrim function, so value should be close to 0,0.
const int HMax = 96; // 5% of 1920 each way = ±96
const int VMax = 54; // 5% of 1080 each way = ±54
if (Math.Abs(DiagsAPI.trim[0]) <= HMax && Math.Abs(DiagsAPI.trim[1]) <= VMax)
lblTrim.ForeColor = Color.LightGreen;
else
lblTrim.ForeColor = Color.Red;
}
private async Task AllocateSerial()
public async Task AllocateSerial()
{
// Update the serial number register with new cameras details
// Cam description is in model drop down 6 digit model num + 3 for " - "
@@ -723,15 +404,15 @@ namespace AiQ_GUI
if (!JSONResponse.Contains(NewSerial) || !JSONResponse.Contains(CamOnTest.Model))
{
AddToActionsList("Could not set model or serial numbers into camera.",Level.ERROR);
AddToActionsList("Could not set model or serial numbers into camera.", Level.ERROR);
await PreTestFailed("Failed To Set Model Or Serial Number");
}
DiagsAPI.modelNumber = CamOnTest.Model; // Update Diags and labels
DiagsAPI.serialNumber = NewSerial;
lblModel.Text += DiagsAPI.modelNumber;
TestingFunctions.DiagsAPI.modelNumber = CamOnTest.Model; // Update Diags and labels
TestingFunctions.DiagsAPI.serialNumber = NewSerial;
lblModel.Text += TestingFunctions.DiagsAPI.modelNumber;
lblModel.ForeColor = lblSerial.ForeColor = Color.LightGreen;
lblSerial.Text += DiagsAPI.serialNumber;
lblSerial.Text += TestingFunctions.DiagsAPI.serialNumber;
Printer.ZebraIP = localDataStore.ZebraIP;
Printer.PrintGBLbl(); // Print GB label
@@ -850,41 +531,52 @@ namespace AiQ_GUI
string selectedText = CbBxFoundCams.Text.Trim();
string ipOnly = selectedText.Split(' ', StringSplitOptions.RemoveEmptyEntries)[0];
bool isOnvif = selectedText.Contains("Onvif", StringComparison.OrdinalIgnoreCase);
if (RegexCache.RegexIPPattern().IsMatch(ipOnly)) // Check IP address is valid
{
CamOnTest.IP = ipOnly; // Always store clean IP
CbBxFoundCams.BackColor = BtnColour;
// ONVIF cameras: webpage only
if (isOnvif)
{
BtnOpenWebpage.Enabled = true;
TestStartConditions();
return;
}
// Non-ONVIF cameras
if (!await Network.PingIP(ipOnly))
{
CbBxFoundCams.BackColor = Color.Red;
return;
}
CamOnTest.IP = ipOnly; //Always store clean IP
CbBxFoundCams.BackColor = BtnColour;
BtnSecret.Enabled = true;
Vers = await FlexiAPI.GetVersions(ipOnly);
// Wont be filled out before the pre test but needed for final test
if (RegexCache.SerialRegex().IsMatch(CamOnTest.Serial) && RegexCache.ModelRegex().IsMatch(CamOnTest.Model))
if (RegexCache.SerialRegex().IsMatch(CamOnTest.Serial) &&
RegexCache.ModelRegex().IsMatch(CamOnTest.Model))
{
CamOnTest.Serial = Vers.Serial; // Set the serial number from the versions API
CamOnTest.Model = Vers.Model; // Set the serial number from the versions API
CamOnTest.Serial = Vers.Serial;
CamOnTest.Model = Vers.Model;
}
if (Vers == null) // If failed to get versions then return. Flexi most likely not running yet.
if (Vers == null) // Flexi not running or not AiQ
{
AddToActionsList("Failed to get API from camera. Flexi not running yet or not an AiQ", Level.WARNING);
return;
}
Lics.DisplayDevPassword(Vers, CamOnTest); // Generate and display secret for use later
Lics.DisplayDevPassword(Vers, CamOnTest);
string networkConfigText = await FlexiAPI.ProcessNetworkConfig(ipOnly);
BtnSet211.Text = string.IsNullOrEmpty(networkConfigText) ? "Set to 211" : networkConfigText;
ShowToolTip(BtnSecret); // Set dev password to Tooltip and clipboard
ShowToolTip(BtnSecret);
}
else if (selectedText.Contains("Found"))
{
@@ -893,12 +585,23 @@ namespace AiQ_GUI
else
{
CbBxFoundCams.BackColor = Color.Red;
BtnSecret.Enabled = BtnOpenWebpage.Enabled = BtnSet211.Enabled = BtnSetGodMode.Enabled = BtnUploadWonwooSetIR.Enabled = BtnUploadWonwooSetOV.Enabled = false;
BtnSecret.Enabled =
BtnOpenWebpage.Enabled =
BtnSet211.Enabled =
BtnSetGodMode.Enabled =
BtnUploadWonwooSetIR.Enabled =
BtnUploadWonwooSetOV.Enabled = false;
}
TestStartConditions();
}
private void CbBxCameraModel_SelectedIndexChanged(object sender, EventArgs e)
{
TestStartConditions();
}
private void btnPsuOn_Click(object sender, EventArgs e)
{
PSU.PSU_ON(PSU.PSUIP);
@@ -1064,7 +767,7 @@ namespace AiQ_GUI
}
// Display the input panel for either RMA number input (default) or Vaxtor Key ID input
private async Task<string> DisplayInput(string Request, bool RMAorVaxtor = true)
public async Task<string> DisplayInput(string Request, bool RMAorVaxtor = true)
{
RMANumBox.Visible = BtnRerun.Visible = RMAorVaxtor;
TxBxProductKey.Visible = !RMAorVaxtor;
@@ -1725,47 +1428,16 @@ namespace AiQ_GUI
}
// ***** Test & Debug *****
private void BtnTest_Click(object sender, EventArgs e)
private async void BtnTest_Click(object sender, EventArgs e)
{
Stopwatch stopWatchTest = Stopwatch.StartNew();
//StatsExcel excelExporter = new();
//excelExporter.ExportDatabaseToExcel();
// /api/config-ids - For getting all available config IDs
// Make every log file in the soak log directory into a soak test report PDF
//var files = from file in Directory.EnumerateFiles("C:\\ProgramData\\MAV\\AiQ_GUI") select file;
//foreach (var file in files)
//{
// if (file.Contains("SoakLog"))
// {
// // File name: SoakLog_{Serial}_{Model}.log
// string[] parts = file.Split('_', '.').Select(p => p.Trim()).ToArray();
// Camera NewCam = new()
// {
// Model = parts[3],
// Serial = parts[2],
// };
// PDF.CreateSoakTestReport(NewCam, "SoakTestRig", DateTime.Now, file);
// }
await MobilePreTest.CheckFirmwareAsync();
var password = @"mavPA\$\$";
var psi = new ProcessStartInfo
{
FileName = @"C:\Program Files (x86)\Mobatek\MobaXterm\MobaXterm.exe",
Arguments = $@"-newtab -ssh {CamOnTest.IP} -user mav -pass ""{password}""",
UseShellExecute = true
};
Process.Start(psi);
stopWatchTest.Stop();
AddToActionsList("RunTime " + stopWatchTest.Elapsed.ToString(@"hh\:mm\:ss\.ff"), Level.LOG);
}
}
}

View File

@@ -218,6 +218,7 @@ namespace AiQ_GUI
public static string LatestVersion { get; set; } = string.Empty;
public static int PowerConsumption { get; set; } = 0;
public static string LicencingServerURL { get; set; } = string.Empty;
public static string SRZFirmware { get; set; } = string.Empty;
}
public class CameraAccessInfo

View File

@@ -0,0 +1,85 @@
using AiQ_GUI;
using System;
using System.Net.Http;
using System.Net.Http.Json;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
public static class MobilePreTest
{
public static async Task CheckFirmwareAsync()
{
const string cameraIp = "192.168.0.112";
using HttpClient client = new HttpClient
{
BaseAddress = new Uri($"http://{cameraIp}")
};
try
{
// Login and get JWT token
string token = await LoginAsync(client, "ADMIN", "1234");
// Attach JWT to all requests
client.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
// Request firmware information
HttpResponseMessage response =
await client.GetAsync("/app/v1/system/firmware");
string body = await response.Content.ReadAsStringAsync();
MainForm.Instance.AddToActionsList(
$"Firmware check response: {(int)response.StatusCode} {response.StatusCode} | {body}",
Level.LOG);
response.EnsureSuccessStatusCode();
JsonElement json =
JsonSerializer.Deserialize<JsonElement>(body);
string version =
json.GetProperty("version").GetString();
MainForm.Instance.AddToActionsList(
$"Current firmware version: {version}",
Level.Success);
}
catch (Exception ex)
{
MainForm.Instance.AddToActionsList(
$"Firmware check failed: {ex.Message}",
Level.ERROR);
}
}
private static async Task<string> LoginAsync(HttpClient client, string user, string password)
{
var payload = new
{
userId = user,
userPassword = Sha256(password)
};
HttpResponseMessage response =
await client.PostAsJsonAsync("/app/v1/login", payload);
response.EnsureSuccessStatusCode();
JsonElement json =
await response.Content.ReadFromJsonAsync<JsonElement>();
return json.GetProperty("token").GetString();
}
private static string Sha256(string input)
{
using SHA256 sha = SHA256.Create();
byte[] bytes = sha.ComputeHash(Encoding.UTF8.GetBytes(input));
return BitConverter.ToString(bytes).Replace("-", "").ToLower();
}
}