Skip to content

Commit 1367d49

Browse files
committed
Implemented InitializeContinuousScanMode method and modified affected classes.
1 parent 223c216 commit 1367d49

File tree

7 files changed

+80
-34
lines changed

7 files changed

+80
-34
lines changed

AntPlus.UnitTests/AntDeviceCollectionTests.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ public void TestInitialize()
3232

3333
private AntDeviceCollection CreateAntDeviceCollection()
3434
{
35+
IAntChannel[] mockChannels = new IAntChannel[8];
36+
Array.Fill(mockChannels, mockAntChannel.Object);
37+
mockAntRadio.Setup(r => r.InitializeContinuousScanMode()).Returns(mockChannels);
3538
return new AntDeviceCollection(
3639
mockAntRadio.Object,
3740
null,
@@ -42,7 +45,6 @@ private AntDeviceCollection CreateAntDeviceCollection()
4245
public void MultithreadedAdd_Collection_ExpectedCount()
4346
{
4447
// Arrange
45-
mockAntRadio.Setup(r => r.GetChannel(It.IsAny<int>())).Returns(mockAntChannel.Object);
4648
Mock<ILogger<UnknownDevice>> mockLogger = new();
4749
var antDeviceCollection = CreateAntDeviceCollection();
4850
int numberOfDevices = 16;
@@ -73,7 +75,6 @@ public void MultithreadedAdd_Collection_ExpectedCount()
7375
public void MultithreadedRemove_Collection_ExpectedCount()
7476
{
7577
// Arrange
76-
mockAntRadio.Setup(r => r.GetChannel(It.IsAny<int>())).Returns(mockAntChannel.Object);
7778
Mock<ILogger<UnknownDevice>> mockLogger = new();
7879
var antDeviceCollection = CreateAntDeviceCollection();
7980
int numberOfDevices = 16;
@@ -117,7 +118,6 @@ public void ChannelResponseEvent_Collection_ExpectedDeviceInCollection(byte devi
117118
// Arrange
118119
byte[] id = new byte[4] { 1, 0, deviceClass, 0 };
119120
ChannelId cid = new(BitConverter.ToUInt32(id));
120-
mockAntRadio.Setup(r => r.GetChannel(It.IsAny<int>())).Returns(mockAntChannel.Object);
121121
mockAntChannel.SetupAdd(m => m.ChannelResponse += It.IsAny<EventHandler<AntResponse>>());
122122
mockAntChannel.SetupRemove(m => m.ChannelResponse -= It.IsAny<EventHandler<AntResponse>>());
123123
var mockResponse = new MockResponse(cid, new byte[8]);

AntPlus.UnitTests/AntPlus.UnitTests.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@
1919
</ItemGroup>
2020

2121
<ItemGroup>
22-
<ProjectReference Include="..\AntPlus\AntPlus.csproj" />
22+
<Folder Include="DeviceProfiles\AssetTracker\" />
2323
</ItemGroup>
2424

2525
<ItemGroup>
26-
<Folder Include="DeviceProfiles\AssetTracker\" />
26+
<ProjectReference Include="..\AntPlus\AntPlus.csproj" />
2727
</ItemGroup>
2828

2929
</Project>

AntPlus/AntDeviceCollection.cs

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,16 @@ public class AntDeviceCollection : ObservableCollection<AntDevice>
2828
/// </remarks>
2929
public object CollectionLock = new object();
3030

31-
private readonly IAntRadio antRadio;
32-
private int channelNum = 0;
31+
private int channelNum = 1;
3332
private readonly ILoggerFactory _loggerFactory;
3433
private readonly ILogger<AntDeviceCollection> logger;
3534
private readonly ushort timeout;
35+
private readonly IAntChannel[] channels;
3636

37-
/// <summary>Initializes a new instance of the <see cref="AntDeviceCollection" /> class.</summary>
37+
/// <summary>
38+
/// Initializes a new instance of the <see cref="AntDeviceCollection" /> class. The ANT radio is configured
39+
/// for continuous scan mode.
40+
/// </summary>
3841
/// <param name="antRadio">The ANT radio interface.</param>
3942
/// <param name="loggerFactory">Logger factory to generate type specific ILogger from. Can be null.</param>
4043
/// <param name="antDeviceTimeout">ANT device timeout in milliseconds. The default is 2000 milliseconds.</param>
@@ -51,18 +54,12 @@ public class AntDeviceCollection : ObservableCollection<AntDevice>
5154
/// </remarks>
5255
public AntDeviceCollection(IAntRadio antRadio, ILoggerFactory loggerFactory, ushort antDeviceTimeout = 2000)
5356
{
54-
this.antRadio = antRadio;
5557
_loggerFactory = loggerFactory ?? NullLoggerFactory.Instance;
5658
logger = _loggerFactory.CreateLogger<AntDeviceCollection>();
5759
logger.LogInformation("Created AntDeviceCollection");
5860
timeout = antDeviceTimeout;
59-
antRadio.GetChannel(0).ChannelResponse += Channel_ChannelResponse;
60-
61-
// assign channels for devices to use for sending messages
62-
for (int i = 1; i < antRadio.NumChannels; i++)
63-
{
64-
_ = antRadio.GetChannel(i).AssignChannel(ChannelType.BaseSlaveReceive, 0, 500);
65-
}
61+
channels = antRadio.InitializeContinuousScanMode();
62+
channels[0].ChannelResponse += Channel_ChannelResponse;
6663
}
6764

6865
private void Channel_ChannelResponse(object sender, AntResponse e)
@@ -114,8 +111,8 @@ private void DeviceOffline(object sender, EventArgs e)
114111

115112
private AntDevice CreateAntDevice(ChannelId channelId)
116113
{
117-
if (++channelNum == antRadio.NumChannels) channelNum = 1;
118-
IAntChannel channel = antRadio.GetChannel(channelNum);
114+
IAntChannel channel = channels[channelNum++];
115+
if (channelNum == channels.Length) { channelNum = 1; }
119116

120117
switch (channelId.DeviceType)
121118
{

AntRadioInterface/IAntRadio.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,40 @@ public interface IAntRadio
138138
{
139139
/// <summary>Occurs when radio response has been received.</summary>
140140
event EventHandler<AntResponse> RadioResponse;
141+
142+
/// <summary>Initializes the ANT radio for continuous scan mode.</summary>
143+
/// <returns>
144+
/// Returns an array of ANT channels. The first element of the array (ANT channel 0) is used for continuous
145+
/// scan mode to receive broadcast messages from ANT master devices. The remaining channels
146+
/// should be configured so messages may be sent to ANT master devices.
147+
/// </returns>
148+
/// <remarks>
149+
/// Implementors typically would perform the following setup -
150+
/// <code>
151+
/// public IAntChannel[] InitializeContinuousScanMode()
152+
/// {
153+
/// IAntChannel[] channels = new IAntChannel[NumChannels];
154+
///
155+
/// // configure channel 0 for continuous scan mode
156+
/// SetNetworkKey(0, new byte[] { 0xB9, 0xA5, 0x21, 0xFB, 0xBD, 0x72, 0xC3, 0x45 });
157+
/// EnableRxExtendedMessages(true);
158+
/// channels[0] = GetChannel(0);
159+
/// channels[0].AssignChannel(ChannelType.BaseSlaveReceive, 0, 500);
160+
/// channels[0].SetChannelID(new ChannelId(0), 500);
161+
/// channels[0].SetChannelFreq(57, 500);
162+
/// OpenRxScanMode();
163+
///
164+
/// // assign channels for devices to use for sending messages
165+
/// for (int i = 1; i &lt; NumChannels; i++)
166+
/// {
167+
/// channels[i] = GetChannel(i);
168+
/// _ = channels[i].AssignChannel(ChannelType.BaseSlaveReceive, 0, 500);
169+
/// }
170+
/// return channels;
171+
/// }
172+
/// </code>
173+
/// </remarks>
174+
IAntChannel[] InitializeContinuousScanMode();
141175
/// <summary>Cancels the transfers.</summary>
142176
/// <param name="cancelWaitTime">The cancel wait time.</param>
143177
void CancelTransfers(int cancelWaitTime);

Examples/AntMulticastServer/Program.cs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
// See https://aka.ms/new-console-template for more information
22
using Microsoft.Extensions.DependencyInjection;
33
using Microsoft.Extensions.Hosting;
4+
using Serilog;
45
using SmallEarthTech.AntRadioInterface;
56
using SmallEarthTech.AntUsbStick;
6-
using System.Diagnostics;
77
using System.Net;
88
using System.Net.Sockets;
99
using System.Reflection;
@@ -14,8 +14,16 @@
1414
Console.WriteLine(string.Format("ANT Multicast Server - Version {0}.", Assembly.GetExecutingAssembly().GetName().Version?.ToString(3)));
1515
Console.WriteLine("Copyright 2023 Stephen Hidem.");
1616

17+
// Initialize early, without access to configuration or services
18+
Log.Logger = new LoggerConfiguration()
19+
.WriteTo.Debug(outputTemplate:
20+
"[{Timestamp:HH:mm:ss.fff} {Level:u3}] {Message:lj}{NewLine}{Exception}") // + file or centralized logging
21+
.MinimumLevel.Debug()
22+
.CreateLogger();
23+
1724
// dependency services
1825
IHost host = Host.CreateDefaultBuilder(Environment.GetCommandLineArgs()).
26+
UseSerilog().
1927
ConfigureServices(s =>
2028
{
2129
s.AddSingleton<IAntRadio, AntRadio>();
@@ -32,8 +40,8 @@
3240
// create and configure ANT radio
3341
Console.WriteLine("Configuring ANT radio (uses the first USB stick found).");
3442
AntRadio antRadio = (AntRadio)host.Services.GetRequiredService<IAntRadio>();
35-
IAntChannel channel = antRadio.InitializeContinuousScanMode();
36-
channel.ChannelResponse += Channel_ChannelResponse;
43+
IAntChannel[] channel = antRadio.InitializeContinuousScanMode();
44+
channel[0].ChannelResponse += Channel_ChannelResponse;
3745

3846
// create background task to receive UDP directed to this server from any clients
3947
_ = Task.Run(async () =>
@@ -42,7 +50,7 @@
4250
while (true)
4351
{
4452
UdpReceiveResult result = await udpServer.ReceiveAsync();
45-
Debug.WriteLine(BitConverter.ToString(result.Buffer));
53+
Log.Debug(BitConverter.ToString(result.Buffer));
4654
ChannelId channelId = new(BitConverter.ToUInt32(result.Buffer, 0));
4755
byte[] msg = result.Buffer.Skip(4).Take(8).ToArray();
4856
uint ackWaitTime = BitConverter.ToUInt32(result.Buffer, 12);
@@ -57,7 +65,7 @@
5765
Console.ReadLine();
5866

5967
// clean up
60-
channel.ChannelResponse -= Channel_ChannelResponse;
68+
channel[0].ChannelResponse -= Channel_ChannelResponse;
6169

6270
void Channel_ChannelResponse(object? sender, AntResponse e)
6371
{

Examples/AntUsbStick/AntRadio.cs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,18 +47,28 @@ private void AntDevice_deviceResponse(ANT_Response response)
4747
RadioResponse?.Invoke(this, new UsbAntResponse(response));
4848
}
4949

50-
/// <summary>Initializes the ANT radio for continuous scan mode.</summary>
51-
/// <returns>Returns the ANT channel used for continuous scan mode. Typically used to receive broadcast messages from ANT master devices.</returns>
52-
public IAntChannel InitializeContinuousScanMode()
50+
/// <inheritdoc/>
51+
public IAntChannel[] InitializeContinuousScanMode()
5352
{
53+
IAntChannel[] channels = new IAntChannel[NumChannels];
54+
55+
// configure channel 0 for continuous scan mode
5456
SetNetworkKey(0, new byte[] { 0xB9, 0xA5, 0x21, 0xFB, 0xBD, 0x72, 0xC3, 0x45 });
5557
EnableRxExtendedMessages(true);
56-
IAntChannel antChannel = GetChannel(0);
57-
antChannel.AssignChannel(ChannelType.BaseSlaveReceive, 0, 500);
58-
antChannel.SetChannelID(new ChannelId(0), 500);
59-
antChannel.SetChannelFreq(57, 500);
58+
channels[0] = GetChannel(0);
59+
channels[0].AssignChannel(ChannelType.BaseSlaveReceive, 0, 500);
60+
channels[0].SetChannelID(new ChannelId(0), 500);
61+
channels[0].SetChannelFreq(57, 500);
6062
OpenRxScanMode();
61-
return antChannel;
63+
64+
// assign channels for devices to use for sending messages
65+
for (int i = 1; i < NumChannels; i++)
66+
{
67+
channels[i] = GetChannel(i);
68+
_ = channels[i].AssignChannel(ChannelType.BaseSlaveReceive, 0, 500);
69+
}
70+
71+
return channels;
6272
}
6373

6474
/// <inheritdoc/>

Examples/WpfUsbStickApp/MainWindowViewModel.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,6 @@ public MainWindowViewModel()
5050
AntResponse rsp = UsbAntRadio.RequestMessageAndResponse(RequestMessageID.Version, 500);
5151
HostVersion = Encoding.Default.GetString(rsp.Payload).TrimEnd('\0');
5252

53-
// initialize continuous scan mode
54-
_ = UsbAntRadio.InitializeContinuousScanMode();
55-
5653
// log app info
5754
var antAssemblies = Assembly.GetExecutingAssembly().GetReferencedAssemblies().Where(asm => asm.Name!.StartsWith("Ant"));
5855
var logger = _host.Services.GetRequiredService<ILogger<App>>();

0 commit comments

Comments
 (0)