| /* |
| * Copyright (c) 2026, The OpenThread Authors. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. Neither the name of the copyright holder nor the |
| * names of its contributors may be used to endorse or promote products |
| * derived from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| * POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "instance/instance.hpp" |
| |
| #include "test_platform.h" |
| #include "test_util.hpp" |
| |
| namespace ot { |
| |
| #if OPENTHREAD_CONFIG_SEEKER_ENABLE || OPENTHREAD_CONFIG_JOINER_ENABLE |
| |
| class UnitTester |
| { |
| public: |
| using Seeker = MeshCoP::Seeker; |
| using CandidateEntry = MeshCoP::Seeker::CandidateEntry; |
| |
| static void CreateScanResult(ScanResult &aResult, uint64_t aExtPanId, uint64_t aExtAddr, int8_t aRssi) |
| { |
| ClearAllBytes(aResult); |
| LittleEndian::WriteUint64(aExtPanId, aResult.mExtendedPanId.m8); |
| LittleEndian::WriteUint64(aExtAddr, aResult.mExtAddress.m8); |
| aResult.mRssi = aRssi; |
| aResult.mPanId = static_cast<uint16_t>(aExtPanId & 0xffff); |
| aResult.mChannel = 11; |
| aResult.mJoinerUdpPort = 1000; |
| } |
| |
| static void LogCandidate(const CandidateEntry &aEntry) |
| { |
| if (aEntry.IsEmpty()) |
| { |
| printf(" empty\n"); |
| } |
| else |
| { |
| printf(" ext-addr:%2.2s, ext-panid:%4.4s, rssi:%d, prf:%u, conn-attempted:%u\n", |
| aEntry.mExtAddr.ToString().AsCString(), aEntry.mExtPanId.ToString().AsCString(), aEntry.mRssi, |
| aEntry.mPreferred, aEntry.mConnAttempted); |
| } |
| } |
| |
| static void LogCandidates(const Seeker &aSeeker) |
| { |
| CandidateEntry entry; |
| |
| printf("\nCandidates:\n"); |
| |
| for (entry.InitForIteration(); aSeeker.mCandidates.ReadNext(entry) == kErrorNone;) |
| { |
| LogCandidate(entry); |
| } |
| |
| printf("\n"); |
| } |
| |
| static void SaveCandidate(Seeker &aSeeker, uint64_t aExtPanId, uint64_t aExtAddr, int8_t aRssi, bool aPreferred) |
| { |
| ScanResult result; |
| |
| CreateScanResult(result, aExtPanId, aExtAddr, aRssi); |
| aSeeker.SaveCandidate(result, aPreferred); |
| } |
| |
| static bool Contains(const Seeker &aSeeker, uint64_t aExtPanId, uint64_t aExtAddr) |
| { |
| MeshCoP::ExtendedPanId extPanId; |
| Mac::ExtAddress extAddr; |
| CandidateEntry entry; |
| |
| LittleEndian::WriteUint64(aExtPanId, extPanId.m8); |
| LittleEndian::WriteUint64(aExtAddr, extAddr.m8); |
| |
| return (aSeeker.mCandidates.FindMatching(entry, extPanId, extAddr) == kErrorNone); |
| } |
| |
| static void StartCandidateSelection(Seeker &aSeeker) |
| { |
| // Manually set the state so we can call and validate the |
| // `SelectNextCandidate()`. |
| |
| aSeeker.SetState(Seeker::kStateConnectingNetworks); |
| } |
| |
| static void SelectNextCandidate(Seeker &aSeeker, CandidateEntry &aEntry) |
| { |
| Error error = aSeeker.SelectNextCandidate(aEntry); |
| |
| if (error == kErrorNone) |
| { |
| aEntry.mConnAttempted = true; |
| SuccessOrQuit(aSeeker.mCandidates.Write(aEntry)); |
| } |
| else |
| { |
| aEntry.MarkAsEmpty(); |
| } |
| } |
| |
| static constexpr uint16_t kSelectionArraySize = 32; |
| |
| using ExtAddrArray = Array<uint64_t, kSelectionArraySize>; |
| |
| static void CheckSelection(Seeker &aSeeker, const ExtAddrArray &aExtAddrs) |
| { |
| CandidateEntry entry; |
| Mac::ExtAddress extAddr; |
| |
| printf("\nSelection order:\n"); |
| |
| StartCandidateSelection(aSeeker); |
| |
| for (uint64_t addr : aExtAddrs) |
| { |
| SelectNextCandidate(aSeeker, entry); |
| LogCandidate(entry); |
| |
| VerifyOrQuit(!entry.IsEmpty()); |
| |
| LittleEndian::WriteUint64(addr, extAddr.m8); |
| VerifyOrQuit(entry.mExtAddr == extAddr); |
| VerifyOrQuit(entry.mConnAttempted); |
| } |
| |
| SelectNextCandidate(aSeeker, entry); |
| VerifyOrQuit(entry.IsEmpty()); |
| } |
| |
| static void TestSeekerCandidates(void) |
| { |
| Instance *instance; |
| |
| printf("TestSeekerCandidates()\n"); |
| |
| instance = static_cast<Instance *>(testInitInstance()); |
| VerifyOrQuit(instance != nullptr); |
| |
| Seeker &seeker = instance->Get<Seeker>(); |
| CandidateEntry entry; |
| ExtAddrArray selectionOrder; |
| |
| printf("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n"); |
| printf("Basic addition & replacement\n\n"); |
| |
| seeker.Stop(); |
| |
| printf("Save a single candidate"); |
| SaveCandidate(seeker, 0xaaaa, 0xa1, -50, false); |
| LogCandidates(seeker); |
| |
| VerifyOrQuit(seeker.mCandidates.GetLength() == 1); |
| VerifyOrQuit(Contains(seeker, 0xaaaa, 0xa1)); |
| |
| printf("Save same candidate with better RSSI"); |
| SaveCandidate(seeker, 0xaaaa, 0xa1, -40, false); |
| LogCandidates(seeker); |
| |
| VerifyOrQuit(seeker.mCandidates.GetLength() == 1); |
| VerifyOrQuit(seeker.mCandidates.ReadAt(0, entry) == kErrorNone); |
| VerifyOrQuit(entry.mRssi == -40); |
| |
| printf("Save same candidate with worse RSSI, still should replace as it is same extAddr\n"); |
| SaveCandidate(seeker, 0xaaaa, 0xa1, -60, false); |
| LogCandidates(seeker); |
| |
| VerifyOrQuit(seeker.mCandidates.GetLength() == 1); |
| VerifyOrQuit(seeker.mCandidates.ReadAt(0, entry) == kErrorNone); |
| VerifyOrQuit(entry.mRssi == -60); |
| |
| printf("Validate candidate selection with single entry in array\n\n"); |
| |
| selectionOrder.Clear(); |
| SuccessOrQuit(selectionOrder.PushBack(0xa1)); |
| |
| CheckSelection(seeker, selectionOrder); |
| |
| printf("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n"); |
| printf("Max candidates per network (limit = 3)\n\n"); |
| |
| seeker.Stop(); |
| |
| printf("Save 3 candidates for network 0xaaaa along with some extra entries\n"); |
| |
| SaveCandidate(seeker, 0xaaaa, 0xa1, -50, false); |
| SaveCandidate(seeker, 0xbbbb, 0xb1, -70, true); |
| SaveCandidate(seeker, 0xaaaa, 0xa2, -52, false); |
| SaveCandidate(seeker, 0xcccc, 0xc1, -80, true); |
| SaveCandidate(seeker, 0xaaaa, 0xa3, -51, false); |
| SaveCandidate(seeker, 0xdddd, 0xd1, -40, false); |
| LogCandidates(seeker); |
| |
| VerifyOrQuit(seeker.mCandidates.GetLength() == 6); |
| VerifyOrQuit(Contains(seeker, 0xaaaa, 0xa1)); |
| VerifyOrQuit(Contains(seeker, 0xaaaa, 0xa2)); |
| VerifyOrQuit(Contains(seeker, 0xaaaa, 0xa3)); |
| |
| printf("Try adding 4th for 0xaaaa (worse RSSI) -> should be dropped\n"); |
| |
| SaveCandidate(seeker, 0xaaaa, 0xa4, -90, false); |
| LogCandidates(seeker); |
| |
| VerifyOrQuit(seeker.mCandidates.GetLength() == 6); |
| VerifyOrQuit(!Contains(seeker, 0xaaaa, 0xa4)); |
| VerifyOrQuit(Contains(seeker, 0xaaaa, 0xa1)); |
| VerifyOrQuit(Contains(seeker, 0xaaaa, 0xa2)); |
| VerifyOrQuit(Contains(seeker, 0xaaaa, 0xa3)); |
| |
| printf("Try adding 4th for 0xaaaa (better RSSI) -> should replace a2 (lowest RSSI)\n"); |
| |
| SaveCandidate(seeker, 0xaaaa, 0xa5, -40, false); |
| LogCandidates(seeker); |
| |
| VerifyOrQuit(seeker.mCandidates.GetLength() == 6); |
| VerifyOrQuit(Contains(seeker, 0xaaaa, 0xa5)); |
| VerifyOrQuit(Contains(seeker, 0xaaaa, 0xa1)); |
| VerifyOrQuit(!Contains(seeker, 0xaaaa, 0xa2)); |
| VerifyOrQuit(Contains(seeker, 0xaaaa, 0xa3)); |
| |
| printf("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n"); |
| printf("Behavior under full candidates array and eviction\n\n"); |
| |
| SaveCandidate(seeker, 0xbbbb, 0xb2, -75, true); |
| SaveCandidate(seeker, 0xeeee, 0xe1, -30, false); |
| LogCandidates(seeker); |
| |
| VerifyOrQuit(seeker.mCandidates.GetLength() == 8); |
| VerifyOrQuit(seeker.mCandidates.IsFull()); |
| |
| VerifyOrQuit(Contains(seeker, 0xaaaa, 0xa1)); |
| VerifyOrQuit(Contains(seeker, 0xaaaa, 0xa5)); |
| VerifyOrQuit(Contains(seeker, 0xaaaa, 0xa3)); |
| VerifyOrQuit(Contains(seeker, 0xbbbb, 0xb1)); |
| VerifyOrQuit(Contains(seeker, 0xbbbb, 0xb2)); |
| VerifyOrQuit(Contains(seeker, 0xcccc, 0xc1)); |
| VerifyOrQuit(Contains(seeker, 0xdddd, 0xd1)); |
| VerifyOrQuit(Contains(seeker, 0xeeee, 0xe1)); |
| |
| printf("Try adding new entry 0xb3 for 0xbbbb with better RSSI -> should replace 0xb2\n"); |
| SaveCandidate(seeker, 0xbbbb, 0xb3, -65, true); |
| LogCandidates(seeker); |
| |
| VerifyOrQuit(seeker.mCandidates.GetLength() == 8); |
| VerifyOrQuit(seeker.mCandidates.IsFull()); |
| |
| VerifyOrQuit(Contains(seeker, 0xbbbb, 0xb1)); |
| VerifyOrQuit(Contains(seeker, 0xbbbb, 0xb3)); |
| VerifyOrQuit(!Contains(seeker, 0xbbbb, 0xb2)); |
| |
| VerifyOrQuit(Contains(seeker, 0xaaaa, 0xa1)); |
| VerifyOrQuit(Contains(seeker, 0xaaaa, 0xa5)); |
| VerifyOrQuit(Contains(seeker, 0xaaaa, 0xa3)); |
| VerifyOrQuit(Contains(seeker, 0xcccc, 0xc1)); |
| VerifyOrQuit(Contains(seeker, 0xdddd, 0xd1)); |
| VerifyOrQuit(Contains(seeker, 0xeeee, 0xe1)); |
| |
| printf("Try adding new entry 0xb4 for 0xbbbb with worst RSSI -> should be dropped\n"); |
| SaveCandidate(seeker, 0xbbbb, 0xb4, -95, true); |
| LogCandidates(seeker); |
| |
| VerifyOrQuit(seeker.mCandidates.GetLength() == 8); |
| VerifyOrQuit(seeker.mCandidates.IsFull()); |
| |
| VerifyOrQuit(Contains(seeker, 0xaaaa, 0xa1)); |
| VerifyOrQuit(Contains(seeker, 0xaaaa, 0xa5)); |
| VerifyOrQuit(Contains(seeker, 0xaaaa, 0xa3)); |
| VerifyOrQuit(Contains(seeker, 0xbbbb, 0xb1)); |
| VerifyOrQuit(Contains(seeker, 0xbbbb, 0xb3)); |
| VerifyOrQuit(Contains(seeker, 0xcccc, 0xc1)); |
| VerifyOrQuit(Contains(seeker, 0xdddd, 0xd1)); |
| VerifyOrQuit(Contains(seeker, 0xeeee, 0xe1)); |
| |
| printf("Try adding new entry 0xc2 for 0xcccc with better RSSI but not preferred -> should be ignored\n"); |
| |
| SaveCandidate(seeker, 0xcccc, 0xc2, -40, false); |
| LogCandidates(seeker); |
| |
| VerifyOrQuit(seeker.mCandidates.GetLength() == 8); |
| VerifyOrQuit(seeker.mCandidates.IsFull()); |
| |
| VerifyOrQuit(Contains(seeker, 0xaaaa, 0xa1)); |
| VerifyOrQuit(Contains(seeker, 0xaaaa, 0xa5)); |
| VerifyOrQuit(Contains(seeker, 0xaaaa, 0xa3)); |
| VerifyOrQuit(Contains(seeker, 0xbbbb, 0xb1)); |
| VerifyOrQuit(Contains(seeker, 0xbbbb, 0xb3)); |
| VerifyOrQuit(Contains(seeker, 0xcccc, 0xc1)); |
| VerifyOrQuit(Contains(seeker, 0xdddd, 0xd1)); |
| VerifyOrQuit(Contains(seeker, 0xeeee, 0xe1)); |
| |
| printf("Try adding new entry 0xc3 for 0xcccc with better RSSI and preferred -> should replace 0xc1\n"); |
| |
| SaveCandidate(seeker, 0xcccc, 0xc3, -40, true); |
| LogCandidates(seeker); |
| |
| VerifyOrQuit(seeker.mCandidates.GetLength() == 8); |
| VerifyOrQuit(seeker.mCandidates.IsFull()); |
| |
| VerifyOrQuit(Contains(seeker, 0xcccc, 0xc3)); |
| VerifyOrQuit(!Contains(seeker, 0xcccc, 0xc1)); |
| |
| VerifyOrQuit(Contains(seeker, 0xaaaa, 0xa1)); |
| VerifyOrQuit(Contains(seeker, 0xaaaa, 0xa5)); |
| VerifyOrQuit(Contains(seeker, 0xaaaa, 0xa3)); |
| VerifyOrQuit(Contains(seeker, 0xbbbb, 0xb1)); |
| VerifyOrQuit(Contains(seeker, 0xbbbb, 0xb3)); |
| VerifyOrQuit(Contains(seeker, 0xdddd, 0xd1)); |
| VerifyOrQuit(Contains(seeker, 0xeeee, 0xe1)); |
| |
| printf("Try adding new entry 0xe2 for 0xeeee with worse RSSI but preferred -> should replace 0xe1\n"); |
| |
| SaveCandidate(seeker, 0xeeee, 0xe2, -99, true); |
| LogCandidates(seeker); |
| |
| VerifyOrQuit(seeker.mCandidates.GetLength() == 8); |
| VerifyOrQuit(seeker.mCandidates.IsFull()); |
| |
| VerifyOrQuit(!Contains(seeker, 0xeeee, 0xe1)); |
| VerifyOrQuit(Contains(seeker, 0xeeee, 0xe2)); |
| |
| VerifyOrQuit(Contains(seeker, 0xaaaa, 0xa1)); |
| VerifyOrQuit(Contains(seeker, 0xaaaa, 0xa5)); |
| VerifyOrQuit(Contains(seeker, 0xaaaa, 0xa3)); |
| VerifyOrQuit(Contains(seeker, 0xbbbb, 0xb1)); |
| VerifyOrQuit(Contains(seeker, 0xbbbb, 0xb3)); |
| VerifyOrQuit(Contains(seeker, 0xcccc, 0xc3)); |
| VerifyOrQuit(Contains(seeker, 0xdddd, 0xd1)); |
| |
| printf("Try adding new network, 0xf1 for 0xffff -> should evict 0xa3\n"); |
| |
| SaveCandidate(seeker, 0xffff, 0xf1, -65, false); |
| LogCandidates(seeker); |
| |
| VerifyOrQuit(seeker.mCandidates.GetLength() == 8); |
| VerifyOrQuit(seeker.mCandidates.IsFull()); |
| |
| VerifyOrQuit(!Contains(seeker, 0xaaaa, 0xa3)); |
| |
| VerifyOrQuit(Contains(seeker, 0xaaaa, 0xa1)); |
| VerifyOrQuit(Contains(seeker, 0xaaaa, 0xa5)); |
| VerifyOrQuit(Contains(seeker, 0xbbbb, 0xb1)); |
| VerifyOrQuit(Contains(seeker, 0xbbbb, 0xb3)); |
| VerifyOrQuit(Contains(seeker, 0xcccc, 0xc3)); |
| VerifyOrQuit(Contains(seeker, 0xdddd, 0xd1)); |
| VerifyOrQuit(Contains(seeker, 0xeeee, 0xe2)); |
| VerifyOrQuit(Contains(seeker, 0xffff, 0xf1)); |
| |
| printf("Adding two new entries for new network -> should evict 0xa1 and 0xb1\n"); |
| |
| SaveCandidate(seeker, 0x1234, 0x01, -80, false); |
| SaveCandidate(seeker, 0x5678, 0x02, -70, false); |
| LogCandidates(seeker); |
| |
| VerifyOrQuit(seeker.mCandidates.GetLength() == 8); |
| VerifyOrQuit(seeker.mCandidates.IsFull()); |
| |
| VerifyOrQuit(!Contains(seeker, 0xaaaa, 0xa1)); |
| VerifyOrQuit(!Contains(seeker, 0xbbbb, 0xb1)); |
| |
| VerifyOrQuit(Contains(seeker, 0xaaaa, 0xa5)); |
| VerifyOrQuit(Contains(seeker, 0xbbbb, 0xb3)); |
| VerifyOrQuit(Contains(seeker, 0xcccc, 0xc3)); |
| VerifyOrQuit(Contains(seeker, 0xdddd, 0xd1)); |
| VerifyOrQuit(Contains(seeker, 0xeeee, 0xe2)); |
| VerifyOrQuit(Contains(seeker, 0xffff, 0xf1)); |
| VerifyOrQuit(Contains(seeker, 0x1234, 0x01)); |
| VerifyOrQuit(Contains(seeker, 0x5678, 0x02)); |
| |
| printf("The candidates array is full and consists of distinct networks\n"); |
| printf("Try adding a new entry for yet another network -> should be dropped\n"); |
| |
| SaveCandidate(seeker, 0xabcd, 0x03, -80, true); |
| LogCandidates(seeker); |
| |
| VerifyOrQuit(seeker.mCandidates.GetLength() == 8); |
| VerifyOrQuit(seeker.mCandidates.IsFull()); |
| |
| VerifyOrQuit(Contains(seeker, 0xaaaa, 0xa5)); |
| VerifyOrQuit(Contains(seeker, 0xbbbb, 0xb3)); |
| VerifyOrQuit(Contains(seeker, 0xcccc, 0xc3)); |
| VerifyOrQuit(Contains(seeker, 0xdddd, 0xd1)); |
| VerifyOrQuit(Contains(seeker, 0xeeee, 0xe2)); |
| VerifyOrQuit(Contains(seeker, 0xffff, 0xf1)); |
| VerifyOrQuit(Contains(seeker, 0x1234, 0x01)); |
| VerifyOrQuit(Contains(seeker, 0x5678, 0x02)); |
| |
| selectionOrder.Clear(); |
| SuccessOrQuit(selectionOrder.PushBack(0xc3)); |
| SuccessOrQuit(selectionOrder.PushBack(0xb3)); |
| SuccessOrQuit(selectionOrder.PushBack(0xe2)); |
| SuccessOrQuit(selectionOrder.PushBack(0xa5)); |
| SuccessOrQuit(selectionOrder.PushBack(0xd1)); |
| SuccessOrQuit(selectionOrder.PushBack(0xf1)); |
| SuccessOrQuit(selectionOrder.PushBack(0x02)); |
| SuccessOrQuit(selectionOrder.PushBack(0x01)); |
| |
| CheckSelection(seeker, selectionOrder); |
| |
| printf("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n"); |
| printf("Selection strategy\n\n"); |
| |
| seeker.Stop(); |
| |
| SaveCandidate(seeker, 0xdddd, 0xd1, -30, false); |
| SaveCandidate(seeker, 0xaaaa, 0xa1, -60, false); |
| SaveCandidate(seeker, 0xeeee, 0xe1, -30, true); |
| SaveCandidate(seeker, 0xbbbb, 0xb1, -65, true); |
| SaveCandidate(seeker, 0xaaaa, 0xa2, -40, false); |
| SaveCandidate(seeker, 0xcccc, 0xc1, -90, true); |
| SaveCandidate(seeker, 0xaaaa, 0xa3, -70, false); |
| SaveCandidate(seeker, 0xcccc, 0xc2, -40, false); |
| LogCandidates(seeker); |
| |
| VerifyOrQuit(seeker.mCandidates.GetLength() == 8); |
| |
| // First we should go through all distinct networks, starting |
| // with most favored over all. Then go through the extra |
| // backup candidates. |
| // |
| // For `0xaaaa`, we have 3 candidates: |
| // ext-addr:a2, ext-panid:aaaa, rssi:-40, prf:0, conn-attempted:0 |
| // ext-addr:a1, ext-panid:aaaa, rssi:-60, prf:0, conn-attempted:0 |
| // ext-addr:a3, ext-panid:aaaa, rssi:-70, prf:0, conn-attempted:0 |
| // |
| // For `0xbbbb`, only one candidate: |
| // ext-addr:b1, ext-panid:bbbb, rssi:-65, prf:1, conn-attempted:0 |
| // |
| // For `0xcccc`, we have two: |
| // ext-addr:c1, ext-panid:cccc, rssi:-90, prf:1, conn-attempted:0 |
| // ext-addr:c2, ext-panid:cccc, rssi:-40, prf:0, conn-attempted:0 |
| // |
| // For `0xdddd`, we have one: |
| // ext-addr:d1, ext-panid:dddd, rssi:-30, prf:0, conn-attempted:0 |
| // |
| // For `0xeeee`, we have one: |
| // ext-addr:e1, ext-panid:eeee, rssi:-30, prf:1, conn-attempted:0 |
| // |
| // We go through networks first |
| // - e1 has highest RSSI and also preferred |
| // - b1 is preferred with high RSSI |
| // - c1 is also preferred even though it has low RSSI |
| // - d1 has best RSSI among non-preferred |
| // - a2 would be next among all `0xaaaa` candidates |
| // |
| // Next we go through remaining candidates |
| // - c2, a1 and a3 |
| |
| selectionOrder.Clear(); |
| SuccessOrQuit(selectionOrder.PushBack(0xe1)); |
| SuccessOrQuit(selectionOrder.PushBack(0xb1)); |
| SuccessOrQuit(selectionOrder.PushBack(0xc1)); |
| SuccessOrQuit(selectionOrder.PushBack(0xd1)); |
| SuccessOrQuit(selectionOrder.PushBack(0xa2)); |
| SuccessOrQuit(selectionOrder.PushBack(0xc2)); |
| SuccessOrQuit(selectionOrder.PushBack(0xa1)); |
| SuccessOrQuit(selectionOrder.PushBack(0xa3)); |
| |
| CheckSelection(seeker, selectionOrder); |
| |
| seeker.Stop(); |
| |
| // Adding two candidates for 3 networks (total 6) |
| |
| SaveCandidate(seeker, 0xcccc, 0xc2, -92, true); |
| SaveCandidate(seeker, 0xaaaa, 0xa2, -76, true); |
| SaveCandidate(seeker, 0xbbbb, 0xb2, -56, false); |
| SaveCandidate(seeker, 0xbbbb, 0xb1, -55, false); |
| SaveCandidate(seeker, 0xcccc, 0xc1, -90, true); |
| SaveCandidate(seeker, 0xaaaa, 0xa1, -75, true); |
| LogCandidates(seeker); |
| |
| VerifyOrQuit(seeker.mCandidates.GetLength() == 6); |
| |
| selectionOrder.Clear(); |
| SuccessOrQuit(selectionOrder.PushBack(0xa1)); |
| SuccessOrQuit(selectionOrder.PushBack(0xc1)); |
| SuccessOrQuit(selectionOrder.PushBack(0xb1)); |
| SuccessOrQuit(selectionOrder.PushBack(0xa2)); |
| SuccessOrQuit(selectionOrder.PushBack(0xc2)); |
| SuccessOrQuit(selectionOrder.PushBack(0xb2)); |
| |
| CheckSelection(seeker, selectionOrder); |
| |
| printf("\nTestSeekerCandidates() passed\n\n"); |
| |
| testFreeInstance(instance); |
| } |
| }; |
| |
| #endif // #if OPENTHREAD_CONFIG_SEEKER_ENABLE || OPENTHREAD_CONFIG_JOINER_ENABLE |
| |
| } // namespace ot |
| |
| int main(void) |
| { |
| #if OPENTHREAD_CONFIG_SEEKER_ENABLE || OPENTHREAD_CONFIG_JOINER_ENABLE |
| #if (OPENTHREAD_CONFIG_JOINER_MAX_CANDIDATES == 8) |
| ot::UnitTester::TestSeekerCandidates(); |
| printf("All tests passed\n"); |
| #else |
| printf("Skipping tests as the test expects `OPENTHREAD_CONFIG_JOINER_MAX_CANDIDATES` to be `8`\n"); |
| printf("This config is specifically set to 8 in `toranj-config` for this test\n"); |
| #endif |
| #else |
| printf("Seeker feature is disabled, skipping the test\n"); |
| #endif |
| |
| return 0; |
| } |