Last active
March 13, 2025 01:19
-
-
Save bugobliterator/88de3076f5d5edaa5542a8ac60992c96 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| function GPSBand(config) | |
| local self = { | |
| name = "GPS_" .. config.name, -- The name of the band | |
| offset = config.offset, -- The offset of the band | |
| frequencies = config.frequencies, -- The frequencies to test | |
| lowGoodIndex = config.lowGoodIndex, -- The minimum allowed frequency index | |
| highGoodIndex = config.highGoodIndex, -- The maximum allowed frequency index | |
| maxTimeMS = config.maxTimeMS, -- How long to wait for the test to complete | |
| allowedGoodMisses = config.allowedGoodMisses, -- How many misses in the good range should we allow | |
| allowedBadHits = config.allowedBadHits, -- How many hits in the bad range are allowed | |
| minValue = config.minValue, -- The minimum frequency level to be accepted | |
| minGain = config.minGain, -- The min gain level to be accepted | |
| maxGain = config.maxGain, -- The max gain level to be accepted | |
| minGainSeen = config.minGainSeen, -- The highest gain value allowed to be seen at all times | |
| avgFreqValue = {}, -- The average frequency value | |
| num_samples = 0, -- The number of samples seen | |
| minChange = config.minChange, -- The minimum change in frequency to be accepted | |
| }; | |
| -- Offset the frequencies | |
| for i = 1, #self.frequencies do | |
| self.frequencies[i] = self.frequencies[i] + self.offset | |
| end | |
| -- setup last gain seen | |
| for i = 1, #self.frequencies do | |
| self.avgFreqValue[i] = 0 | |
| end | |
| self.num_samples = 0 | |
| return self | |
| end | |
| function GPSTest(gpsBands, expectedFreqTimeMS) | |
| local self = { | |
| gpsBands = gpsBands, -- The GPS bands to test | |
| expectedFreqTimeMS = expectedFreqTimeMS -- The expected time to see a frequency | |
| } | |
| -- Add the runtime variables to the bands | |
| for i = 1, #self.gpsBands do | |
| self.gpsBands[i].startTime = nil -- The time that the test started at | |
| self.gpsBands[i].nextCheck = nil -- The time to check the results | |
| self.gpsBands[i].gpsDetected = nil -- If the GPS signal has been detected | |
| self.gpsBands[i].detectedFrequencies = nil -- The frequencies that have been detected | |
| self.gpsBands[i].freqTime = nil -- The time the frequency has been detected for | |
| self.gpsBands[i].lowestGainSeen = nil -- The lowest gain seen | |
| self.gpsBands[i].gainChangedAt = millis() -- What was the last time a gain change was seen | |
| self.gpsBands[i].lastGainSeen = nil -- What was the last gain seen | |
| end | |
| -- Reset a GPS band test | |
| function self:reset_band(band) | |
| band.startTime = millis() | |
| band.nextCheck = millis() + 10000 | |
| band.gpsDetected = false; | |
| if band.freqTime == nil then | |
| band.freqTime = {}; | |
| band.detectedFrequencies = {}; | |
| end | |
| for i = 1, #band.frequencies do | |
| band.detectedFrequencies[i] = false; | |
| end | |
| end | |
| -- Print out the frequencies for debug purposes | |
| function self:print_gps(band, peakFreqIndex, highestFreqChangeValue, antennaGain) | |
| local builder = ""; | |
| for j = 1, #band.frequencies do | |
| if j == band.lowGoodIndex then | |
| builder = builder .. "|"; | |
| end | |
| if peakFreqIndex == j then | |
| if j >= band.lowGoodIndex and j <= band.highGoodIndex then | |
| builder = builder .. "[G] "; | |
| else | |
| builder = builder .. "[B] "; | |
| end | |
| elseif band.detectedFrequencies[j] == true then | |
| if j >= band.lowGoodIndex and j <= band.highGoodIndex then | |
| builder = builder .. "G "; | |
| else | |
| builder = builder .. "B "; | |
| end | |
| else | |
| builder = builder .. ". "; | |
| end | |
| if j == band.highGoodIndex then | |
| builder = builder:sub(1, -2) .. "| "; | |
| end | |
| end | |
| send_gcs(band.name .. "-> " .. builder .. " [" .. tostring(peakFreqIndex) .. " " .. tostring(highestFreqChangeValue) .. | |
| " " .. tostring(antennaGain) .. " " .. tostring(band.frequencies[peakFreqIndex]) .. "]"); | |
| end | |
| -- Find the current highest frequency. | |
| --- @param seenForMs number The number of milliseconds we have seen this frequency for | |
| --- @return number The index of the highest frequency if found | |
| function self:find_highest_change_in_freq(band, seenForMs) | |
| -- Find the current highest frequency | |
| local peakFreqIndex = nil; | |
| local highestFreqChangeValue = 0; | |
| -- Get all the frequencies with the same antenna gain | |
| local detectedFreq = {} | |
| local antennaGainDetected = nil; | |
| for j = 1, #band.frequencies do | |
| local freqLevel, antennaGain = gps:get_frequency_db(band.frequencies[j]); | |
| if antennaGainDetected == nil then | |
| antennaGainDetected = antennaGain | |
| end | |
| -- If the gain is not the same break | |
| if antennaGain ~= antennaGainDetected then | |
| antennaGainDetected = nil | |
| break; | |
| end | |
| detectedFreq[j] = freqLevel; | |
| end | |
| -- Search for the peak frequency level | |
| if antennaGainDetected ~= nil and antennaGainDetected <= band.maxGain and antennaGainDetected >= band.minGain then | |
| for j = 1, #detectedFreq do | |
| -- Calculate the average frequency value | |
| if detectedFreq[j] ~= nil then | |
| band.avgFreqValue[j] = ((band.avgFreqValue[j] * band.num_samples) + detectedFreq[j]) / (band.num_samples + 1) | |
| if (detectedFreq[j] - band.avgFreqValue[j]) > highestFreqChangeValue and detectedFreq[j] >= band.minValue then | |
| peakFreqIndex = j; | |
| highestFreqChangeValue = detectedFreq[j] - band.avgFreqValue[j]; | |
| end | |
| end | |
| end | |
| band.num_samples = band.num_samples + 1 | |
| end | |
| if highestFreqChangeValue < band.minChange then | |
| peakFreqIndex = nil; | |
| end | |
| -- if the peak is detected outside the GoodIndex also check that its the overall peak as well | |
| if peakFreqIndex ~= nil and (peakFreqIndex < band.lowGoodIndex or peakFreqIndex > band.highGoodIndex) then | |
| local overallPeak = true; | |
| for j = 1, #detectedFreq do | |
| if detectedFreq[j] ~= nil and detectedFreq[j] > detectedFreq[peakFreqIndex] then | |
| overallPeak = false; | |
| break; | |
| end | |
| end | |
| if overallPeak == false then | |
| peakFreqIndex = nil; | |
| end | |
| end | |
| -- If there was a peak make sure it stays the peak for the required period of time | |
| if peakFreqIndex ~= nil then | |
| if band.freqTime[peakFreqIndex] == nil then | |
| band.freqTime = {}; | |
| band.freqTime[peakFreqIndex] = 1; | |
| else | |
| band.freqTime[peakFreqIndex] = band.freqTime[peakFreqIndex] + 1; | |
| end | |
| end | |
| -- Check if any frequencies were seen for long enough | |
| for j = 1, #band.frequencies do | |
| if band.freqTime[j] ~= nil and band.freqTime[j] > calculate_ms(seenForMs) then | |
| band.freqTime = {}; | |
| return j, highestFreqChangeValue, antennaGainDetected; | |
| end | |
| end | |
| return nil, nil, antennaGainDetected | |
| end | |
| --- Run the GPS test for a singular band | |
| ---@param band any The band to test | |
| function self:test_band(band) | |
| -- Count how long the test has been running for | |
| if band.startTime == nil then | |
| self:reset_band(band); | |
| end | |
| -- Find the frequencies and check that they are in range | |
| local highestFreqIndex, highestFreqChangeValue, antennaGain = self:find_highest_change_in_freq(band, self.expectedFreqTimeMS); | |
| -- Require the gain to stabilize for 3 seconds before we check the readings | |
| if band.lastGainSeen ~= antennaGain then | |
| band.gainChangedAt = millis(); | |
| band.lastGainSeen = antennaGain; | |
| end | |
| if band.gainChangedAt + 3000 > millis() then | |
| highestFreqIndex = nil; | |
| end | |
| if antennaGain ~= nil and (band.lowestGainSeen == nil or antennaGain < band.lowestGainSeen) then | |
| band.lowestGainSeen = antennaGain; | |
| end | |
| if highestFreqIndex ~= nil then | |
| band.detectedFrequencies[highestFreqIndex] = true; | |
| band.gpsDetected = true; | |
| self:print_gps(band, highestFreqIndex, highestFreqChangeValue, antennaGain); | |
| -- Check if we have got all the frequencies in the good range | |
| band.goodPass = true; | |
| local goodMissCount = 0; | |
| for j = band.lowGoodIndex, band.highGoodIndex do | |
| if band.detectedFrequencies[j] ~= true then | |
| goodMissCount = goodMissCount + 1; | |
| if goodMissCount > band.allowedGoodMisses then | |
| band.goodPass = false; | |
| break | |
| end | |
| end | |
| end | |
| -- Check if we have got any frequencies in the bad range | |
| band.badPass = true; | |
| local badHitCount = 0; | |
| for j = 1, #band.frequencies do | |
| if j < band.lowGoodIndex or j > band.highGoodIndex then | |
| if band.detectedFrequencies[j] == true then | |
| badHitCount = badHitCount + 1; | |
| if badHitCount >= band.allowedBadHits then | |
| band.badPass = false; | |
| break | |
| end | |
| end | |
| end | |
| end | |
| end | |
| -- Check every 10 seconds for a result | |
| if band.nextCheck < millis() then | |
| local resultCode = ""; | |
| local result = ""; | |
| band.nextCheck = millis() + 10000; | |
| -- If we have detected all our good frequencies but not our bad ones then pass | |
| if resultCode == "" and (band.goodPass ~= nil and band.badPass ~= nil) then | |
| if band.goodPass == true and band.badPass == true then | |
| resultCode = "PASS"; | |
| elseif band.badPass == false then | |
| resultCode = band.name .. "-OGR"; | |
| result = "Detected frequencies outside of the good range"; | |
| end | |
| end | |
| -- If we can out of time then fail | |
| if resultCode == "" and band.startTime + band.maxTimeMS < millis() then | |
| -- If the lowest gain level is higher than expected then fail | |
| if band.lowestGainSeen ~= nil and band.lowestGainSeen > band.minGainSeen then | |
| resultCode = band.name .. "-BCP"; | |
| result = "Lowest gain seen was " .. tostring(band.lowestGainSeen) .. "dB"; | |
| elseif band.gpsDetected == false then | |
| resultCode = band.name .. "-NSD"; | |
| result = "GPS signal not detected"; | |
| else | |
| resultCode = band.name .. "-NFS"; | |
| result = "Did not detect the full sweep"; | |
| end | |
| end | |
| -- If we have a result code then handle it | |
| if resultCode ~= "" then | |
| if resultCode == "PASS" then | |
| local failureCount = num_test_fails(band.name); | |
| if failureCount > 0 then | |
| if get_test_state_without_codes(band.name) == "" then | |
| fail(band.name, "previously reported " .. tostring(failureCount) .. " failures", | |
| band.name .. "-PBH", false); | |
| end | |
| else | |
| pass(band.name); | |
| end | |
| elseif resultCode ~= "" then | |
| fail(band.name, result, resultCode, true); | |
| end | |
| end | |
| end | |
| end | |
| -- Initialize the GPS test | |
| function self:initialize() | |
| for i = 1, #self.gpsBands do | |
| if add_test(self.gpsBands[i].name) then | |
| add_test_params(self.gpsBands[i].name); | |
| end | |
| end | |
| end | |
| -- Run the GPS test | |
| function self:test() | |
| -- Check if the ublox module is in recovery mode, if so fail the tests | |
| if gps:in_recovery_mode() then | |
| for i = 1, #gpsBands do | |
| -- Fail all the GPS bands with -UBX | |
| fail(gpsBands[i].name, "The ublox is in recovery mode", gpsBands[i].name .. "-UBX", true); | |
| end | |
| else | |
| -- Otherwise run the tests on the bands | |
| for i = 1, #gpsBands do | |
| self:test_band(gpsBands[i]); | |
| end | |
| end | |
| end | |
| return self | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment