This commit is contained in:
2025-09-16 10:42:51 +01:00
parent 50bb9c9781
commit 0c463ad929
8 changed files with 351 additions and 200 deletions

View File

@@ -183,7 +183,7 @@ namespace AiQ_GUI
} }
await Wait; // Finished to 5s wait await Wait; // Finished to 5s wait
await SetTrim(); // Auto trims the cameras, some plates should have been captured in the meantime await FlexiAPI.SetTrim(CamOnTest.IP, LblTestTubePing.Text); // Auto trims the cameras, some plates should have been captured in the meantime
if (!await FlexiAPI.ZoomModules("0000", CamOnTest.IP)) // Zoom to full wide if (!await FlexiAPI.ZoomModules("0000", CamOnTest.IP)) // Zoom to full wide
await TestFailed(BtnStartTest, "Could not zoom modules to full wide"); await TestFailed(BtnStartTest, "Could not zoom modules to full wide");
@@ -686,81 +686,6 @@ namespace AiQ_GUI
Printer.PrintSerialLbl(CamOnTest.Model, NewSerial, CameraAccessInfo.Processor); // Print model/serial label Printer.PrintSerialLbl(CamOnTest.Model, NewSerial, CameraAccessInfo.Processor); // Print model/serial label
} }
private async Task SetTrim(int RetryCount = 0) // Sets trim by getting plate postion as metric
{
Trim trim;
string trimData = await FlexiAPI.APIHTTPRequest("/SightingCreator-plate-positions", CamOnTest.IP, 5); // Get plate positions
try // Deserialise the JSON
{
Logging.LogMessage("Trim Data: " + trimData);
trim = JsonConvert.DeserializeObject<Trim>(trimData);
}
catch
{
await TestFailed(BtnStartTest, "Error reading JSON - " + trimData);
return;
}
// Check no value is -1 (no plate found) or if the positions are identical (one plate found). If it is then try again 3 times
if (new[] { trim.infraredX, trim.infraredY, trim.colourX, trim.colourY }.Any(value => value == -1)
|| (trim.infraredX == trim.colourX && trim.infraredY == trim.colourY))
{
if (RetryCount >= 3)
{
await DisplayOK("Please align trim in webpage then click OK."); // Awaited till OK has been clicked
return;
}
await Task.Delay(5000); // Give 5 second delay for it to see a plate
await SetTrim(RetryCount++);
}
int offset = 105;
if (LblTestTubePing.Text == "❌") // Test tube not connected so do the 2.7m check.
offset = 98;
// Horizontal distance offset for 2.7m compared to 30m is 98 pixels. This was empirically found from testing in the car park
// Colour camera is to the right of the infrared so it gets the offset.
// Using similar triangles going from 2.7m -> 0.65m which is the length of the test tube (Also exactly 1/4 length).
// 98 * (29.35/27.3) = 105.35 pixels
int OverviewX = trim.colourX + offset;
if (OverviewX > 1920) // If adding on the offset has pushed it out of limits then remove 0.1
{
if (OverviewX < 2120 && trim.infraredX > 400) // Within enough of a limit to automatically do it
{
OverviewX -= 200;
trim.infraredX -= 200;
}
else // Ask user to centre the plate in the field of view
{
await DisplayOK("Please centralise plate in view THEN press OK"); // Awaited till OK has been clicked
if (RetryCount >= 3)
{
await DisplayOK("Please align trim in webpage then click OK."); // Awaited till OK has been clicked
return;
}
await Task.Delay(5000); // Give 5 second delay for it to see a plate
await SetTrim(RetryCount++);
}
}
// Compensated trim values, therefore should be close to 0,0 with limits of ±5% of 1920 and 1080 respectivly being ±96 and ±54
int TrimX = trim.infraredX - OverviewX;
int TrimY = trim.infraredY - trim.colourY;
// Update trim values
string[,] Trim_JSON = { { "propInterCameraOffsetX", Convert.ToString(TrimX) }, { "propInterCameraOffsetY", Convert.ToString(TrimY) } };
string TrimResp = await FlexiAPI.HTTP_Update("SightingCreator", CamOnTest.IP, Trim_JSON);
AddToActionsList(TrimResp, false);
if (!TrimResp.Contains($"\"propInterCameraOffsetX\": {{\"value\": \"{Convert.ToString(TrimX)}\", \"datatype\": \"int\"}}, \"propInterCameraOffsetY\": {{\"value\": \"{Convert.ToString(TrimY)}\", \"datatype\": \"int\"}},"))
AddToActionsList("Could not set camera trim");
}
// ***** Top right buttons ***** // ***** Top right buttons *****
private void BtnClose_Click(object sender, EventArgs e) private void BtnClose_Click(object sender, EventArgs e)
{ {
@@ -800,7 +725,8 @@ namespace AiQ_GUI
private async void BtnFindCams_Click(object sender, EventArgs e) private async void BtnFindCams_Click(object sender, EventArgs e)
{ {
CbBxFoundCams.Text = "Searching"; CbBxFoundCams.Text = "Searching";
BtnFindCams.Enabled = BtnSetAll211.Enabled = BtnSoak.Enabled = BtnSet211.Enabled = BtnSetGodMode.Enabled = BtnUploadBlob.Enabled = SetGodModeAll.Enabled = false; BtnFindCams.Enabled = BtnSetAll211.Enabled = BtnSoak.Enabled = BtnSet211.Enabled = BtnSetGodMode.Enabled = BtnUploadBlob.Enabled = SetGodModeAll.Enabled = BtnFactoryDefault.Enabled = false;
BtnSetGodMode.BackColor = BtnUploadBlob.BackColor = BtnFactoryDefault.BackColor = BtnSetAll211.BackColor = BtnColour;
CbBxFoundCams.Items.Clear(); CbBxFoundCams.Items.Clear();
soakCameraList.Clear(); soakCameraList.Clear();
@@ -838,7 +764,7 @@ namespace AiQ_GUI
int cameraCount = CbBxFoundCams.Items.Count; int cameraCount = CbBxFoundCams.Items.Count;
CbBxFoundCams.Text = cameraCount > 0 ? $"{cameraCount} Camera{(cameraCount == 1 ? "" : "s")} Found" : "No Cameras Found"; CbBxFoundCams.Text = cameraCount > 0 ? $"{cameraCount} Camera{(cameraCount == 1 ? "" : "s")} Found" : "No Cameras Found";
BtnFindCams.Enabled = BtnSetAll211.Enabled = SetGodModeAll.Enabled = BtnSoak.Enabled = BtnUploadBlob.Enabled = true; BtnFindCams.Enabled = BtnSetAll211.Enabled = SetGodModeAll.Enabled = BtnSoak.Enabled = BtnUploadBlob.Enabled = BtnFactoryDefault.Enabled = true;
} }
private void BtnYes_Click(object sender, EventArgs e) private void BtnYes_Click(object sender, EventArgs e)
@@ -947,6 +873,7 @@ namespace AiQ_GUI
private async void BtnSetGodMode_Click(object sender, EventArgs e) private async void BtnSetGodMode_Click(object sender, EventArgs e)
{ {
BtnSetGodMode.BackColor = BtnColour;
bool isGodModeCurrentlyOn = BtnSetGodMode.Text.Contains("On"); bool isGodModeCurrentlyOn = BtnSetGodMode.Text.Contains("On");
string newGodModeValue = isGodModeCurrentlyOn ? "true" : "false"; string newGodModeValue = isGodModeCurrentlyOn ? "true" : "false";
string[,] GOD_JSON = { { "propGodMode", newGodModeValue } }; string[,] GOD_JSON = { { "propGodMode", newGodModeValue } };
@@ -954,13 +881,8 @@ namespace AiQ_GUI
try try
{ {
await FlexiAPI.HTTP_Update("Internal Config", CamOnTest.IP, GOD_JSON); await FlexiAPI.HTTP_Update("Internal Config", CamOnTest.IP, GOD_JSON);
BtnSetGodMode.Text = newGodModeValue == "true" ? "Set God Mode Off" : "Set God Mode On"; BtnSetGodMode.Text = newGodModeValue == "true" ? "Set God Mode Off" : "Set God Mode On";
Color originalColor = BtnSetGodMode.BackColor;
BtnSetGodMode.BackColor = Color.Green; BtnSetGodMode.BackColor = Color.Green;
await Task.Delay(500);
BtnSetGodMode.BackColor = originalColor;
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -1663,6 +1585,7 @@ namespace AiQ_GUI
private async void BtnUploadBlob_Click(object sender, EventArgs e) private async void BtnUploadBlob_Click(object sender, EventArgs e)
{ {
BtnUploadBlob.BackColor = BtnColour;
const string networkFolderPath = @"G:\Shared drives\MAV Production\MAV_146_AiQ_Mk2\Flexi"; const string networkFolderPath = @"G:\Shared drives\MAV Production\MAV_146_AiQ_Mk2\Flexi";
string fileToUpload = null; string fileToUpload = null;
@@ -1716,10 +1639,13 @@ namespace AiQ_GUI
AddToActionsList($"Upload result for {cam.IP}: {result}", false); AddToActionsList($"Upload result for {cam.IP}: {result}", false);
await Task.Delay(500); await Task.Delay(500);
} }
BtnUploadBlob.BackColor = Color.Green;
} }
private async void BtnFactoryDefault_Click(object sender, EventArgs e) private async void BtnFactoryDefault_Click(object sender, EventArgs e)
{ {
BtnFactoryDefault.BackColor = BtnColour;
foreach (Camera SCL in soakCameraList) // Reset all cameras that were being soaked to default module settings foreach (Camera SCL in soakCameraList) // Reset all cameras that were being soaked to default module settings
{ {
if (!SCL.IsChecked) if (!SCL.IsChecked)
@@ -1728,116 +1654,70 @@ namespace AiQ_GUI
Network.Initialize("developer", SCL.DevPass); // Ensure network is initialized to the right camera, cannot be done in soak test finally becuase of this. Network.Initialize("developer", SCL.DevPass); // Ensure network is initialized to the right camera, cannot be done in soak test finally becuase of this.
await CameraModules.FactoryResetModules(SCL.IP); await CameraModules.FactoryResetModules(SCL.IP);
} }
BtnFactoryDefault.BackColor = Color.Green;
} }
private async void SwitchTest(string TestingType) // Constants
const double RealPlateWidthMeters = 0.52; // UK standard plate width
const double FocalLengthPixels = (50 * 1280) / 14.111224; // focal mm * pixel width / sensor width for IQ
// const double FocalLengthPixels = (50 * 1920) / 6.95; // focal mm * pixel width / sensor width for AiQ
const double FrameRate = 25.0; // Frames per second
public class FrameData
{ {
object sender = new(); public long FrameID;
EventArgs e = new(); public int PlatePosX;
public int PlatePosY;
Properties.Settings.Default.UnitTesting = TestingType; public int PlateWidthPixels;
Properties.Settings.Default.Save();
CAMTYPE CAMTYPE = TestingType.Substring(0, TestingType.IndexOf('_')) switch
{
"GOOD" => CAMTYPE.GOOD,
"BAD" => CAMTYPE.BAD,
"BIZARRE" => CAMTYPE.BIZARRE,
_ => CAMTYPE.GOOD,
};
FakeCamera fakeCamera = new(80); // Create an instance of FakeCamera
_ = fakeCamera.StartAsync(CAMTYPE).ContinueWith(task =>
{
if (task.IsFaulted)
AddToActionsList("Error starting FakeCamera: " + task.Exception?.Message);
else
AddToActionsList($"FakeCamera started successfully. IP: {fakeCamera}", false);
});
await Task.Delay(5000); // Wait for server to start
CbBxFoundCams.Text = "localhost"; // Should force update in creds an network reinit
CbBxFoundCams_SelectedIndexChanged(sender, e);
CbBxCameraType.SelectedIndex = CbBxCameraType.Items.Count - 1; // Selects AB12CD as model number
while(TxBxOutput.Text.Length < 2) // Wait for developer password to be generated
await Task.Delay(1000);
if (TestingType.Contains("FINAL"))
BtnStartTest_Click(sender, e); // Run final test
else if (TestingType.Contains("PRE"))
BtnPreTest_Click(sender, e); // Run pre-test
fakeCamera.Stop(); // Stop the server
} }
public double EstimateSpeed(List<FrameData> frames)
{
double TimeElapsed = 0;
int frameCount = frames.Count;
for (int i = 1; i < frameCount; i++)
{
double time = (frames[i].FrameID - frames[i - 1].FrameID) / FrameRate;
TimeElapsed += time;
}
double FarDist = (FocalLengthPixels * RealPlateWidthMeters) / frames[0].PlateWidthPixels;
double CloseDist = (FocalLengthPixels * RealPlateWidthMeters) / frames[frameCount - 1].PlateWidthPixels;
double speedMph = (Math.Abs(FarDist - CloseDist) / TimeElapsed) * 2.237;
return speedMph;
}
// ***** Test & Debug ***** // ***** Test & Debug *****
private void BtnTest_Click(object sender, EventArgs e) private void BtnTest_Click(object sender, EventArgs e)
{ {
Stopwatch stopWatchTest = Stopwatch.StartNew(); Stopwatch stopWatchTest = Stopwatch.StartNew();
// *** To be put in startup code!!!! ***
if (Properties.Settings.Default.UnitTesting != "NOT_STARTED")
BtnTest_Click(sender, e);
// *** TO be put in test button *** List<FrameData> frames = new List<FrameData>
if (Properties.Settings.Default.UnitTesting == "NOT_STARTED")
{ {
SwitchTest("GOOD_PRE"); new FrameData { FrameID = 60192555, PlatePosX = 1172, PlatePosY = 393, PlateWidthPixels = 108 },
new FrameData { FrameID = 60192556, PlatePosX = 1103, PlatePosY = 361, PlateWidthPixels = 105 },
new FrameData { FrameID = 60192558, PlatePosX = 983, PlatePosY = 331, PlateWidthPixels = 99 },
new FrameData { FrameID = 60192559, PlatePosX = 930, PlatePosY = 301, PlateWidthPixels = 95 },
new FrameData { FrameID = 60192560, PlatePosX = 880, PlatePosY = 304, PlateWidthPixels = 93 },
new FrameData { FrameID = 60192561, PlatePosX = 834, PlatePosY = 278, PlateWidthPixels = 89 },
new FrameData { FrameID = 60192562, PlatePosX = 792, PlatePosY = 229, PlateWidthPixels = 87 },
new FrameData { FrameID = 60192563, PlatePosX = 752, PlatePosY = 208, PlateWidthPixels = 85 },
new FrameData { FrameID = 60192565, PlatePosX = 680, PlatePosY = 187, PlateWidthPixels = 81 },
new FrameData { FrameID = 60192566, PlatePosX = 648, PlatePosY = 167, PlateWidthPixels = 78 },
new FrameData { FrameID = 60192567, PlatePosX = 617, PlatePosY = 149, PlateWidthPixels = 76 },
new FrameData { FrameID = 60192568, PlatePosX = 588, PlatePosY = 132, PlateWidthPixels = 75 },
new FrameData { FrameID = 60192569, PlatePosX = 561, PlatePosY = 100, PlateWidthPixels = 70 },
new FrameData { FrameID = 60192570, PlatePosX = 535, PlatePosY = 85, PlateWidthPixels = 72 },
new FrameData { FrameID = 60192572, PlatePosX = 488, PlatePosY = 70, PlateWidthPixels = 69 },
new FrameData { FrameID = 60192573, PlatePosX = 466, PlatePosY = 55, PlateWidthPixels = 67 }
};
// Run Good pre test double Spd = EstimateSpeed(frames);
// Check it was the correct outcome AddToActionsList("Estimated Speed: " + Spd.ToString("F2") + " MPH");
// Restart GUI
}
else if (Properties.Settings.Default.UnitTesting == "GOOD_PRE")
{
SwitchTest("GOOD_FINAL");
// Run Good final test
// Check it was the correct outcome
// Restart GUI
}
else if (Properties.Settings.Default.UnitTesting == "GOOD_FINAL")
{
SwitchTest("BAD_PRE");
// Run Bad pre test
// Check it was the correct outcome
// Restart GUI
}
// etc...
//// SSH testing
//sshData = SSH.CollectSSHData("localhost");
//AddToActionsList(sshData.packages);
//AddToActionsList(sshData.FilesystemSize);
//AddToActionsList($"{sshData.tailscale}");
//// Functionality testing
//// TODO - SSH server needs to be running at this point for this to work
//var server = new FakeCamera(80); // Start the HTTP server in a background task
//_ = server.StartAsync(CAMTYPE.GOOD); // Start the server running with correct responses
//Task.Delay(1000).Wait(); // Wait for server to start
//CbBxCameraType.SelectedIndex = CbBxCameraType.Items.Count - 1; // Selects AB12CD as model number
//CbBxFoundCams.Text = "localhost"; // Should force update in creds an network reinit
//BtnPreTest_Click(sender, e); // Run pre-test
//BtnStartTest_Click(sender, e); // Run full test
//server.Stop(); // Stop the server
//_ = server.StartAsync(CAMTYPE.BAD); // Start the server running with bad responses
//Task.Delay(1000).Wait(); // Wait for server to start
//BtnPreTest_Click(sender, e); // Run pre-test
//BtnStartTest_Click(sender, e); // Run full test
//server.Stop(); // Stop the server
//_ = server.StartAsync(CAMTYPE.BIZARRE); // Start the server running with incorrect types and odd responses
//Task.Delay(1000).Wait(); // Wait for server to start
//BtnPreTest_Click(sender, e); // Run pre-test
//BtnStartTest_Click(sender, e); // Run full test
//server.Stop(); // Stop the server
stopWatchTest.Stop(); stopWatchTest.Stop();
AddToActionsList("RunTime " + stopWatchTest.Elapsed.ToString(@"hh\:mm\:ss\.ff")); AddToActionsList("RunTime " + stopWatchTest.Elapsed.ToString(@"hh\:mm\:ss\.ff"));

View File

@@ -16,7 +16,7 @@
<Product>AiQ GUI</Product> <Product>AiQ GUI</Product>
<Authors>MAV Systems Ltd</Authors> <Authors>MAV Systems Ltd</Authors>
<PackageId>AiQ GUI</PackageId> <PackageId>AiQ GUI</PackageId>
<Version>3.12.0</Version> <Version>3.14.0</Version>
<Description>A GUI to control and test the AiQ</Description> <Description>A GUI to control and test the AiQ</Description>
<Copyright>MAV Systems Ltd 2025</Copyright> <Copyright>MAV Systems Ltd 2025</Copyright>
<PackageIcon>MAV - Plain - Blue.png</PackageIcon> <PackageIcon>MAV - Plain - Blue.png</PackageIcon>
@@ -25,6 +25,7 @@
<RootNamespace>AiQ_GUI</RootNamespace> <RootNamespace>AiQ_GUI</RootNamespace>
<ProduceReferenceAssembly>False</ProduceReferenceAssembly> <ProduceReferenceAssembly>False</ProduceReferenceAssembly>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<SignAssembly>False</SignAssembly>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
@@ -41,18 +42,18 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="ClosedXML" Version="0.105.0" /> <PackageReference Include="ClosedXML" Version="0.105.0" />
<PackageReference Include="Emgu.CV" Version="4.12.0.5763" /> <PackageReference Include="Emgu.CV" Version="4.12.0.5764" />
<PackageReference Include="Emgu.CV.runtime.windows" Version="4.12.0.5763" /> <PackageReference Include="Emgu.CV.runtime.windows" Version="4.12.0.5764" />
<PackageReference Include="Google.Apis.Auth" Version="1.70.0" /> <PackageReference Include="Google.Apis.Auth" Version="1.71.0" />
<PackageReference Include="Google.Apis.Gmail.v1" Version="1.70.0.3833" /> <PackageReference Include="Google.Apis.Gmail.v1" Version="1.70.0.3833" />
<PackageReference Include="Google.Apis.Sheets.v4" Version="1.70.0.3819" /> <PackageReference Include="Google.Apis.Sheets.v4" Version="1.70.0.3819" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
<PackageReference Include="PDFsharp-MigraDoc-gdi" Version="6.2.1" /> <PackageReference Include="PDFsharp-MigraDoc-gdi" Version="6.2.1" />
<PackageReference Include="Selenium.Support" Version="4.35.0" /> <PackageReference Include="Selenium.Support" Version="4.35.0" />
<PackageReference Include="Selenium.WebDriver" Version="4.35.0" /> <PackageReference Include="Selenium.WebDriver" Version="4.35.0" />
<PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="139.0.7258.15400" /> <PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="140.0.7339.8200" />
<PackageReference Include="SSH.NET" Version="2025.0.0" /> <PackageReference Include="SSH.NET" Version="2025.0.0" />
<PackageReference Include="System.Data.OleDb" Version="9.0.8" /> <PackageReference Include="System.Data.OleDb" Version="9.0.9" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

127
AvailableCondigID.json Normal file
View File

@@ -0,0 +1,127 @@
{
"ids": [
"Dispatcher3-meta",
"RaptorOCRColour",
"MMCQueueInfrared",
"Wizards",
"TargetDetection--sequence-target-finder",
"Colour--LiveVideoInput",
"SightingCreator--CropPreview",
"Dispatcher2-json",
"SightingAmmend0-lane-ids",
"SightingAmmend1-custom-fields",
"colourHistory",
"Dispatcher0-json",
"SightingAmmend1-lane-ids",
"TargetDetectionColour-zone-10",
"Audit--Infrared",
"Dispatcher1-utmc-constants",
"-dev-ttyACM1",
"SightingAmmend2-zone-names",
"TargetDetection-zone--2",
"TargetDetection-zone--1",
"Dispatcher3-json",
"-dev-ttyACM0",
"Dispatcher2-utmc-constants",
"SightingAmmend0-overlay",
"SightingAmmend0-zone-name-overrides",
"TargetDetection-zone-4",
"TargetDetection-zone-5",
"GLOBAL--GPS",
"Dispatcher2-bof2-constants",
"TargetDetection-zone-1",
"TargetDetection-zone-2",
"SightingCreator-timing-line-config",
"TargetDetection-zone-3",
"Infrared",
"Dispatcher1-bof2",
"UpdateSentinel",
"Infrared--RTSP",
"Colour",
"TargetDetectionColour--TrakVideoWidget",
"Infrared--VMS",
"Dispatcher0-bof2",
"SightingCreator",
"TargetDetection",
"SightingAmmend3-overlay",
"Telemetry",
"Colour--camera-control-widget-config",
"GLOBAL--NetworkConfig",
"Audit",
"Dispatcher2-meta",
"TargetDetection--VideoPreview",
"TargetDetectionColour--sequence-target-finder",
"MMCQueueColour",
"mergedHistory",
"TargetDetection--TrakVideoWidget",
"SightingCreator--SightingHeatMap",
"GLOBAL--Passwords",
"TargetDetectionColour--VideoPreview",
"LogView",
"Colour--RTSP",
"Dispatcher2-utmc",
"Dispatcher3-utmc-constants",
"SightingAmmend3-zone-name-overrides",
"SightingAmmend0-zone-names",
"SightingAmmend2",
"SightingAmmend1",
"SightingAmmend0",
"SightingCreator-camera-offset",
"SightingAmmend3",
"TargetDetectionColour--TargetDetectionFilter",
"SightingAmmend3-lane-ids",
"Dispatcher3-bof2",
"Dispatcher1-utmc",
"Dispatcher0-utmc-constants",
"Audit--Recorder",
"Dispatcher0-bof2-constants",
"SightingAmmend2-overlay",
"Store2",
"Store1",
"Store3",
"TargetDetectionColour-zone--2",
"TargetDetectionColour",
"TargetDetectionColour-zone--1",
"SightingAmmend0-custom-fields",
"Dispatcher1-bof2-constants",
"RaptorOCR",
"Dispatcher0-utmc",
"Store0",
"Dispatcher1",
"Dispatcher2",
"TargetIdentifiedProcessingQueue",
"Dispatcher0",
"GLOBAL--Device",
"Dispatcher3-utmc",
"SightingAmmend3-zone-names",
"Dispatcher3",
"Dispatcher0-meta",
"SightingCreator--TimingLineVideoWidgetInfrared",
"SightingCreator--TimingLineVideoWidgetColour",
"SightingAmmend2-lane-ids",
"Dispatcher3-bof2-constants",
"WidgetViewer",
"TargetDetectionColour-zone-8",
"TargetDetectionColour-zone-9",
"TargetDetectionColour-zone-6",
"TargetDetectionColour-zone-7",
"Dispatcher1-meta",
"SightingAmmend1-zone-names",
"Audit--Colour",
"SightingAmmend1-zone-name-overrides",
"TargetDetectionProcessingQueue",
"SightingAmmend2-zone-name-overrides",
"Infrared--camera-control-widget-config",
"SightingAmmend3-custom-fields",
"Infrared--LiveVideoInput",
"TargetDetectionProcessingQueueColour",
"VideoFramePairCreator",
"Colour--VMS",
"Dispatcher2-bof2",
"infraredHistory",
"Dispatcher1-json",
"SightingAmmend1-overlay",
"SightingAmmend2-custom-fields",
"TargetDetection--TargetDetectionFilter"
]
}

View File

@@ -71,10 +71,8 @@ namespace AiQ_GUI
string OneshotReply = await FlexiAPI.APIHTTPVISCA(IPAddress, "8101041801FF", true); // Oneshot auto focus string OneshotReply = await FlexiAPI.APIHTTPVISCA(IPAddress, "8101041801FF", true); // Oneshot auto focus
if (!ShutterReply.Contains("41") || !IrisReply.Contains("41") || !GainReply.Contains("41") || !OneshotReply.Contains("41")) if (!ShutterReply.Contains("41") || !IrisReply.Contains("41") || !GainReply.Contains("41") || !OneshotReply.Contains("41"))
{
MainForm.Instance.AddToActionsList("Could not set Shutter, Iris, Gain correctly" + Environment.NewLine + "Shutter: " + ShutterReply + Environment.NewLine + "Iris: " + IrisReply + Environment.NewLine + "Gain: " + GainReply + Environment.NewLine + "Oneshot: " + OneshotReply); MainForm.Instance.AddToActionsList("Could not set Shutter, Iris, Gain correctly" + Environment.NewLine + "Shutter: " + ShutterReply + Environment.NewLine + "Iris: " + IrisReply + Environment.NewLine + "Gain: " + GainReply + Environment.NewLine + "Oneshot: " + OneshotReply);
} }
}
// Sets back to the latest factory defaults CSV that is in Flexi. // Sets back to the latest factory defaults CSV that is in Flexi.
public static async Task FactoryResetModules(string IPAddress) public static async Task FactoryResetModules(string IPAddress)

View File

@@ -49,9 +49,8 @@ namespace AiQ_GUI
{ {
try try
{ {
string JSONdata = "{ \"id\":\"" + ID + "\" }"; string url = $"http://{IPAddress}/api/fetch-config?id={ID}";
string url = $"http://{IPAddress}/api/fetch-config"; return await Network.SendHttpRequest(url, HttpMethod.Get, Timeout);
return await Network.SendHttpRequest(url, HttpMethod.Get, Timeout, JSONdata);
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -87,14 +86,13 @@ namespace AiQ_GUI
try try
{ {
Network.Client.DefaultRequestHeaders.ExpectContinue = false; Network.Client.DefaultRequestHeaders.ExpectContinue = false;
MultipartFormDataContent content;
byte[] fileBytes = await File.ReadAllBytesAsync(filePath).ConfigureAwait(false); byte[] fileBytes = await File.ReadAllBytesAsync(filePath).ConfigureAwait(false);
MemoryStream ms = new(fileBytes); MemoryStream ms = new(fileBytes);
StreamContent streamContent = new(ms); StreamContent streamContent = new(ms);
streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
content = new MultipartFormDataContent { { streamContent, "upload", fileName } }; MultipartFormDataContent content = new() { { streamContent, "upload", fileName } };
using HttpResponseMessage response = await Network.Client.PostAsync(url, content); using HttpResponseMessage response = await Network.Client.PostAsync(url, content);
string responseBody = await response.Content.ReadAsStringAsync(); string responseBody = await response.Content.ReadAsStringAsync();
@@ -189,6 +187,80 @@ namespace AiQ_GUI
return false; return false;
} }
public static async Task SetTrim(string IPAddress, string LblTxt, int RetryCount = 0) // Sets trim by getting plate postion as metric
{
Trim trim;
string trimData = await APIHTTPRequest("/SightingCreator-plate-positions", IPAddress, 5); // Get plate positions
try // Deserialise the JSON
{
Logging.LogMessage("Trim Data: " + trimData);
trim = JsonConvert.DeserializeObject<Trim>(trimData);
}
catch
{
MainForm.Instance.AddToActionsList("Error reading trim JSON - " + trimData);
return;
}
// Check no value is -1 (no plate found) or if the positions are identical (one plate found). If it is then try again 3 times
if (new[] { trim.infraredX, trim.infraredY, trim.colourX, trim.colourY }.Any(value => value == -1)
|| (trim.infraredX == trim.colourX && trim.infraredY == trim.colourY))
{
if (RetryCount >= 3)
{
await MainForm.Instance.DisplayOK("Please align trim in webpage then click OK."); // Awaited till OK has been clicked
return;
}
await Task.Delay(5000); // Give 5 second delay for it to see a plate
await SetTrim(IPAddress, LblTxt, RetryCount++);
}
int offset = 105;
if (LblTxt == "❌") // Test tube not connected so do the 2.7m check.
offset = 98;
// Horizontal distance offset for 2.7m compared to 30m is 98 pixels. This was empirically found from testing in the car park
// Colour camera is to the right of the infrared so it gets the offset.
// Using similar triangles going from 2.7m -> 0.65m which is the length of the test tube (Also exactly 1/4 length).
// 98 * (29.35/27.3) = 105.35 pixels
int OverviewX = trim.colourX + offset;
if (OverviewX > 1920) // If adding on the offset has pushed it out of limits then remove 0.1
{
if (OverviewX < 2120 && trim.infraredX > 400) // Within enough of a limit to automatically do it
{
OverviewX -= 200;
trim.infraredX -= 200;
}
else // Ask user to centre the plate in the field of view
{
await MainForm.Instance.DisplayOK("Please centralise plate in view THEN press OK"); // Awaited till OK has been clicked
if (RetryCount >= 3)
{
await MainForm.Instance.DisplayOK("Please align trim in webpage then click OK."); // Awaited till OK has been clicked
return;
}
await Task.Delay(5000); // Give 5 second delay for it to see a plate
await SetTrim(IPAddress, LblTxt, RetryCount++);
}
}
// Compensated trim values, therefore should be close to 0,0 with limits of ±5% of 1920 and 1080 respectivly being ±96 and ±54
int TrimX = trim.infraredX - OverviewX;
int TrimY = trim.infraredY - trim.colourY;
// Update trim values
string[,] Trim_JSON = { { "propInterCameraOffsetX", Convert.ToString(TrimX) }, { "propInterCameraOffsetY", Convert.ToString(TrimY) } };
string TrimResp = await HTTP_Update("SightingCreator", IPAddress, Trim_JSON);
if (!TrimResp.Contains($"\"propInterCameraOffsetX\": {{\"value\": \"{Convert.ToString(TrimX)}\", \"datatype\": \"int\"}}, \"propInterCameraOffsetY\": {{\"value\": \"{Convert.ToString(TrimY)}\", \"datatype\": \"int\"}},"))
MainForm.Instance.AddToActionsList("Could not set camera trim");
}
// Processes the network config from the camera and returns a string indicating the status // Processes the network config from the camera and returns a string indicating the status
public static async Task<string> ProcessNetworkConfig(string IPAddress) public static async Task<string> ProcessNetworkConfig(string IPAddress)
{ {
@@ -210,7 +282,7 @@ namespace AiQ_GUI
} }
// Knowing the format this builds the message to send to AiQ // Knowing the format this builds the message to send to AiQ
private static string BuildJsonUpdate(string[,] jsonData, string id) public static string BuildJsonUpdate(string[,] jsonData, string id)
{ {
if (jsonData == null || jsonData.GetLength(1) != 2) if (jsonData == null || jsonData.GetLength(1) != 2)
throw new ArgumentException("Input data must be a non-null 2D array with two columns."); throw new ArgumentException("Input data must be a non-null 2D array with two columns.");

View File

@@ -14,7 +14,7 @@ namespace AiQ_GUI
try try
{ {
using SshClient client = new SshClient(IPAddress, SSHUsername, SSHPassword); using SshClient client = new(IPAddress, SSHUsername, SSHPassword);
client.Connect(); client.Connect();
try try

View File

@@ -12,7 +12,7 @@ namespace AiQ_GUI
public static void Initialize(string username, string password) public static void Initialize(string username, string password)
{ {
HttpClientHandler handler = new HttpClientHandler HttpClientHandler handler = new()
{ {
MaxConnectionsPerServer = 25, MaxConnectionsPerServer = 25,
Credentials = new NetworkCredential(username, password) Credentials = new NetworkCredential(username, password)
@@ -30,7 +30,7 @@ namespace AiQ_GUI
{ {
try try
{ {
HttpRequestMessage request = new HttpRequestMessage(method, url); HttpRequestMessage request = new(method, url);
if (jsonData != null) // Fills in the body of the request if jsonData is provided if (jsonData != null) // Fills in the body of the request if jsonData is provided
request.Content = new StringContent(jsonData, Encoding.UTF8, "application/json"); request.Content = new StringContent(jsonData, Encoding.UTF8, "application/json");
@@ -48,8 +48,8 @@ namespace AiQ_GUI
} }
} }
int timeoutMs = (Timeout ?? 10) * 1000; // Convert from seconds to ms int timeoutMs = (Timeout ?? 10) * 1000; // Convert from seconds to ms, default to 10s if null
using CancellationTokenSource cts = new CancellationTokenSource(timeoutMs); using CancellationTokenSource cts = new(timeoutMs);
using HttpResponseMessage response = await Client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cts.Token); using HttpResponseMessage response = await Client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cts.Token);
response.EnsureSuccessStatusCode(); response.EnsureSuccessStatusCode();

73
Test.json Normal file
View File

@@ -0,0 +1,73 @@
{
"id": "GLOBAL--Device",
"configHash": "101478235",
"propHardwarePlatform": {
"value": "JETSON_NANO",
"datatype": "mav.flexi.web.pages.SystemConfig$HardwareConfigurationOption",
"accepted": "[NONE, JETSON_NANO, JETSON_XAVIER, RASPBERRY_PI_CM4, RASPBERRY_PI_CM5, DEVELOPER_WORKSTATION]"
},
"propApplicationPlatform": {
"value": "CUSTOM",
"datatype": "mav.flexi.web.pages.SystemConfig$ApplicationConfigurationOption",
"accepted": "[NONE, CUSTOM, MONO_BASIC_ANPR, DUAL_CAMERA_BASIC_ANPR, SINGLE_SAF_DUAL_CAMERA_BASIC_ANPR, DUAL_CAMERA_STREAMING, BAYGUARD, SITE_ACCESS_CONTROL_WITH_MODBUS, WAPOL_IQ50_VRM_CORRECTION, BAYWATCH_MONO_CAM, BAYWATCH_DUAL_CAM, BAYWATCH_TRIPLE_CAM, BAYWATCH_QUADRUPLE_CAM, IN_CAR_ANPR]"
},
"propDeviceName": {
"value": "Test Nano",
"datatype": "java.lang.String"
},
"propLocalTimeZone": {
"value": "Europe/London (UTC+00)",
"datatype": "mav.util.TimeZoneEnum",
"accepted": "[Africa/Cairo (UTC+02), Africa/Johannesburg (UTC+02), Africa/Lagos (UTC+01), Africa/Monrousing (UTC+00), America/Anchorage (UTC-09), America/Chicago (UTC-06), America/Denver (UTC-07), America/Edmonton (UTC-07), America/Jamaica (UTC-05), America/Los Angeles (UTC-08), America/Mexico City (UTC-06), America/Montreal (UTC-05), America/New/York (UTC-05), America/Phoenix (UTC-07), America/Puerto Rico (UTC-04), America/Sao Paulo (UTC-03), America/Toronto (UTC-05), America/Vancouver (UTC-08), Asia/Hong Kong (UTC+08), Asia/Jerusalem (UTC+02), Asia/Manila (UTC+08), Asia/Seoul (UTC+09), Asia/Tokyo (UTC+09), Atlantic/Reykjavik (UTC+00), Australia/Perth (UTC+08), Australia/Sydney (UTC+10), Europe/Athens (UTC+02), Europe/Berlin (UTC+01), Europe/Brussels (UTC+01), Europe/Copenhagen (UTC+01), Europe/London (UTC+00), Europe/Madrid (UTC+01), Europe/Moscow (UTC+04), Europe/Paris (UTC+01), Europe/Prague (UTC+01), Europe/Rome (UTC+01), Europe/Warsaw (UTC+01), Pacific/Guam (UTC+10), Pacific/Honolulu (UTC-10), UTC (UTC-00)]"
},
"propTimeSource": {
"value": "SNTP Only",
"datatype": "mav.flexi.web.pages.SystemConfig$TimeSourceEnum",
"accepted": "[SNTP Only, GPS Only, SNTP + Soft GPS]"
},
"propSNTPServer": {
"value": "1.uk.pool.ntp.org",
"datatype": "java.lang.String"
},
"propSNTPIntervalMinutes": {
"value": "public long mav.flexi.web.pages.SystemConfig$DeviceConfig.propSNTPIntervalMinutes",
"datatype": "long",
"range": {
"minimum": "1.000000",
"maximum": "99999.000000"
}
},
"propOutputsMaxTimeSyncAge": {
"value": "24 hours",
"datatype": "mav.flexi.web.pages.SystemConfig$HoursEnum",
"accepted": "[NO LIMIT, 01 hours, 02 hours, 03 hours, 04 hours, 05 hours, 06 hours, 07 hours, 08 hours, 09 hours, 10 hours, 11 hours, 12 hours, 18 hours, 24 hours, 36 hours, 48 hours, 72 hours, 96 hours]"
},
"propReservedMemoryMegabytes": {
"value": "public long mav.flexi.web.pages.SystemConfig$DeviceConfig.propReservedMemoryMegabytes",
"datatype": "long",
"range": {
"minimum": "1000.000000",
"maximum": "128000.000000"
}
},
"propClientTrustStorePassword": {
"value": "",
"datatype": "java.lang.String"
},
"propFlexiScriptPath": {
"value": "/home/mav/FlexiAI/bin/FlexiAI",
"datatype": "java.lang.String"
},
"propVideo0Tee": {
"value": "video0tee",
"datatype": "java.lang.String"
},
"propVideo1Tee": {
"value": "video1tee",
"datatype": "java.lang.String"
},
"propRestartCameraModulesOnBoot": {
"value": "true",
"datatype": "boolean"
}
}