Skip to content

Commit 5ed9be2

Browse files
authored
Merge pull request #51 from StephenHidem/47-handle-ant-radio-device-error
47 handle ant radio device error
2 parents 823af36 + 9700aee commit 5ed9be2

File tree

12 files changed

+173
-87
lines changed

12 files changed

+173
-87
lines changed

AntPlus.Extensions.Hosting/AntCollection.cs

+47-17
Original file line numberDiff line numberDiff line change
@@ -69,27 +69,56 @@ public async Task StartScanning()
6969
private void MessageHandler(object? sender, AntResponse e)
7070
{
7171
_logger.LogAntResponse(LogLevel.Trace, e);
72-
if (e.ChannelId != null && e.Payload != null)
72+
73+
// check for a valid payload
74+
if (e.Payload == null || e.Payload.Length < 3)
7375
{
74-
// see if the device is in the collection
75-
AntDevice device = this.FirstOrDefault(ant => ant.ChannelId.Id == e.ChannelId.Id);
76+
_logger.LogUnhandledAntResponse(e);
77+
return;
78+
}
7679

77-
// create the device if not in the collection
78-
if (device == null)
79-
{
80-
// create an ANT device from the AntResponse parameter
81-
device = CreateAntDevice(e);
80+
// switch on the response id
81+
switch (e.ResponseId)
82+
{
83+
case MessageId.ChannelEventOrResponse:
84+
// check for a RF event on channel 0, channel closed event
85+
if (e.Payload[0] != 0 || e.Payload[1] != 1 || (EventMsgId)e.Payload[2] != EventMsgId.ChannelClosed)
86+
{
87+
_logger.LogUnhandledAntResponse(e);
88+
return;
89+
}
8290

83-
Add(device);
84-
device.DeviceWentOffline += DeviceOffline;
85-
}
91+
// re-open the channel in scan mode
92+
_ = ((IAntControl)_antRadio).OpenRxScanMode();
93+
break;
94+
case MessageId.BroadcastData:
95+
case MessageId.ExtBroadcastData:
96+
// check for a valid channel id and payload length
97+
if (e.ChannelId == null || e.Payload.Length != 8)
98+
{
99+
_logger.LogUnhandledAntResponse(e);
100+
return;
101+
}
86102

87-
// dispatch the message to the device
88-
device.Parse(e.Payload);
89-
}
90-
else
91-
{
92-
_logger.LogUnhandledAntResponse(e);
103+
// see if the device is in the collection
104+
AntDevice device = this.FirstOrDefault(ant => ant.ChannelId.Id == e.ChannelId!.Id);
105+
106+
// create the device if not in the collection
107+
if (device == null)
108+
{
109+
// create an ANT device from the AntResponse parameter
110+
device = CreateAntDevice(e);
111+
112+
Add(device);
113+
device.DeviceWentOffline += DeviceOffline;
114+
}
115+
116+
// dispatch the message to the device
117+
device.Parse(e.Payload!);
118+
break;
119+
default:
120+
_logger.LogUnhandledAntResponse(e);
121+
break;
93122
}
94123
}
95124

@@ -99,6 +128,7 @@ private void DeviceOffline(object? sender, EventArgs e)
99128
device.DeviceWentOffline -= DeviceOffline;
100129
_ = Remove(device);
101130
}
131+
102132
/// <summary>Adds the specified <see cref="AntDevice"/> to the end of the collection.</summary>
103133
/// <param name="item">The <see cref="AntDevice"/>.</param>
104134
public new void Add(AntDevice item)

AntPlus.Extensions.Hosting/Hosting.csproj

+3-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
<EmbedUntrackedSources>true</EmbedUntrackedSources>
1717
<PackageIcon>PackageLogo.png</PackageIcon>
1818
<PackageReadmeFile>readme.md</PackageReadmeFile>
19-
<PackageReleaseNotes>Updated logging ANT+ logging extensions.</PackageReleaseNotes>
19+
<PackageReleaseNotes>
20+
1. Updated ANT+ logging with ANT+ logging extensions. 2. The scanning channel is re-opened if a close RF event is received.
21+
</PackageReleaseNotes>
2022
<PackageLicenseExpression>MIT</PackageLicenseExpression>
2123
<IncludeSymbols>True</IncludeSymbols>
2224
<SymbolPackageFormat>snupkg</SymbolPackageFormat>

AntPlus.UnitTests/AntDeviceCollectionTests.cs

+16-14
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public AntDeviceCollectionTests()
3131
_mockAntRadio = _mockRepository.Create<IAntRadio>();
3232
_mockAntChannel = _mockRepository.Create<IAntChannel>();
3333
_mockLogger = _mockRepository.Create<ILogger>();
34+
_mockLogger.Setup(l => l.IsEnabled(It.IsAny<LogLevel>())).Returns(true);
3435
var mockLoggerFactory = _mockRepository.Create<ILoggerFactory>();
3536
mockLoggerFactory.Setup(m => m.CreateLogger(It.IsAny<string>())).Returns(_mockLogger.Object);
3637

@@ -113,7 +114,7 @@ public async Task ChannelResponseEvent_Collection_ExpectedDeviceInCollection(byt
113114
ChannelId cid = new(BitConverter.ToUInt32(id));
114115
_mockAntChannel.SetupAdd(m => m.ChannelResponse += It.IsAny<EventHandler<AntResponse>>());
115116
_mockAntChannel.SetupRemove(m => m.ChannelResponse -= It.IsAny<EventHandler<AntResponse>>());
116-
var mockResponse = new MockResponse(cid, new byte[8]);
117+
var mockResponse = new MockResponse(MessageId.BroadcastData, cid, new byte[8]);
117118
await _antDevices.StartScanning();
118119

119120
// Act
@@ -125,52 +126,53 @@ public async Task ChannelResponseEvent_Collection_ExpectedDeviceInCollection(byt
125126

126127
class MockResponse : AntResponse
127128
{
128-
public MockResponse(ChannelId channelId, byte[] payload)
129+
public MockResponse(MessageId responseId, ChannelId channelId, byte[] payload)
129130
{
131+
ResponseId = responseId;
130132
ChannelId = channelId;
131133
Payload = payload;
132134
}
133135
}
134136

135137
[Fact]
136-
public async Task MessageHandler_NullChannelId_LogsCritical()
138+
public async Task MessageHandler_NullChannelId_LogsWarning()
137139
{
138140
// Arrange
139141
await _antDevices.StartScanning();
140-
var response = new MockResponse(null, new byte[8]);
142+
var response = new MockResponse(MessageId.BroadcastData, null, new byte[8]);
141143

142144
// Act
143145
_mockAntChannel.Raise(m => m.ChannelResponse += null, _mockAntChannel.Object, response);
144146

145147
// Assert
146148
_mockLogger.Verify(
147149
x => x.Log(
148-
LogLevel.Critical,
150+
LogLevel.Warning,
149151
It.IsAny<EventId>(),
150-
It.Is<It.IsAnyType>((v, t) => v.ToString().Contains("ChannelId or Payload is null")),
151-
It.IsAny<Exception>(),
152-
It.Is<Func<It.IsAnyType, Exception, string>>((v, t) => true)),
152+
It.Is<It.IsAnyType>((v, t) => v.ToString().Contains("Unhandled ANT response.")),
153+
null,
154+
It.IsAny<Func<It.IsAnyType, Exception, string>>()),
153155
Times.Once);
154156
}
155157

156158
[Fact]
157-
public async Task MessageHandler_NullPayload_LogsCritical()
159+
public async Task MessageHandler_NullPayload_LogsWarning()
158160
{
159161
// Arrange
160162
await _antDevices.StartScanning();
161-
var response = new MockResponse(new ChannelId(1), null);
163+
var response = new MockResponse(MessageId.BroadcastData, new ChannelId(1), null);
162164

163165
// Act
164166
_mockAntChannel.Raise(m => m.ChannelResponse += null, _mockAntChannel.Object, response);
165167

166168
// Assert
167169
_mockLogger.Verify(
168170
x => x.Log(
169-
LogLevel.Critical,
171+
LogLevel.Warning,
170172
It.IsAny<EventId>(),
171-
It.Is<It.IsAnyType>((v, t) => v.ToString().Contains("ChannelId or Payload is null")),
172-
It.IsAny<Exception>(),
173-
It.Is<Func<It.IsAnyType, Exception, string>>((v, t) => true)),
173+
It.Is<It.IsAnyType>((v, t) => v.ToString().Contains("Unhandled ANT response.")),
174+
null,
175+
It.IsAny<Func<It.IsAnyType, Exception, string>>()),
174176
Times.Once);
175177
}
176178
}

AntPlus.UnitTests/CommonDataPagesTests.cs

+5-4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public class CommonDataPagesTests
1616
public CommonDataPagesTests()
1717
{
1818
_mockLogger = new Mock<ILogger>();
19+
_mockLogger.Setup(l => l.IsEnabled(It.IsAny<LogLevel>())).Returns(true);
1920
_commonDataPages = new(_mockLogger.Object);
2021
}
2122

@@ -174,10 +175,10 @@ public void ParseSubfieldDataPage_InvalidSubPage_LogsError(byte[] dataPage)
174175
// Assert
175176
_mockLogger.Verify(
176177
x => x.Log(
177-
LogLevel.Error,
178+
LogLevel.Warning,
178179
It.IsAny<EventId>(),
179-
It.Is<It.IsAnyType>((v, t) => v.ToString().Contains("Invalid subfield data page")),
180-
It.Is<ArgumentOutOfRangeException>(ex => ex.Message.Contains("Invalid subpage")),
180+
It.Is<It.IsAnyType>((v, t) => v.ToString().Contains("is not defined in SubPage")),
181+
null,
181182
It.IsAny<Func<It.IsAnyType, Exception, string>>()),
182183
Times.Once);
183184
}
@@ -211,7 +212,7 @@ public void ParsePairedDevicesPage_LogsWarning()
211212
x => x.Log(
212213
LogLevel.Warning,
213214
It.IsAny<EventId>(),
214-
It.Is<It.IsAnyType>((v, t) => v.ToString().Contains("Paired devices data page not implemented")),
215+
It.Is<It.IsAnyType>((v, t) => v.ToString().Contains("Ignoring page type PairedDevices")),
215216
null,
216217
It.IsAny<Func<It.IsAnyType, Exception, string>>()),
217218
Times.Once);

AntPlus.UnitTests/DeviceProfiles/BicyclePower/CrankTorqueFrequencySensorTests.cs

+10-10
Original file line numberDiff line numberDiff line change
@@ -135,11 +135,11 @@ public void ParseCTFMessage_SameUpdateEventCountAndTorqueTicks_NoCalculations()
135135
}
136136

137137
[Theory]
138-
[InlineData(new byte[] { 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x11, 0x22 }, 3001)]
139-
[InlineData(new byte[] { 0x01, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0x11, 0x22 }, 3001)]
140-
[InlineData(new byte[] { 0x01, 0x10, 0xAC, 0xFF, 0xFF, 0xFF, 0x11, 0x22 }, 3001)]
141-
[InlineData(new byte[] { 0x02, 0x10, 0xAC, 0xFF, 0xFF, 0xFF, 0x11, 0x22 }, 3000)]
142-
public void ParseUnknownCTFDefinedId_LogsWarning(byte[] dataPage, int eventId)
138+
[InlineData(new byte[] { 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x11, 0x22 })]
139+
[InlineData(new byte[] { 0x01, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0x11, 0x22 })]
140+
[InlineData(new byte[] { 0x01, 0x10, 0xAC, 0xFF, 0xFF, 0xFF, 0x11, 0x22 })]
141+
[InlineData(new byte[] { 0x02, 0x10, 0xAC, 0xFF, 0xFF, 0xFF, 0x11, 0x22 })]
142+
public void ParseUnknownCTFDefinedId_LogsWarning(byte[] dataPage)
143143
{
144144
// Arrange
145145

@@ -150,25 +150,25 @@ public void ParseUnknownCTFDefinedId_LogsWarning(byte[] dataPage, int eventId)
150150
_mockLogger.Verify(
151151
m => m.Log(
152152
LogLevel.Warning,
153-
It.Is<EventId>(v => v.Id == eventId),
153+
It.IsAny<EventId>(),
154154
It.Is<It.IsAnyType>((v, t) => v.ToString().Contains("Unknown data page")),
155155
null,
156156
It.IsAny<Func<It.IsAnyType, Exception, string>>()),
157157
Times.Once);
158158
}
159159

160160
[Theory]
161-
[InlineData(new byte[] { 0x01, 0x10, 0xAC, 0x02, 0xFF, 0xFF, 0xFF, 0xFF }, "Slope saved to flash.")]
162-
[InlineData(new byte[] { 0x01, 0x10, 0xAC, 0x03, 0xFF, 0xFF, 0xFF, 0xFF }, "Serial number saved to flash.")]
163-
public void ParseAcknowledgeMessage_LogsInformation(byte[] dataPage, string message)
161+
[InlineData(new byte[] { 0x01, 0x10, 0xAC, 0x02, 0xFF, 0xFF, 0xFF, 0xFF }, "Data page type Slope")]
162+
[InlineData(new byte[] { 0x01, 0x10, 0xAC, 0x03, 0xFF, 0xFF, 0xFF, 0xFF }, "Data page type SerialNumber")]
163+
public void ParseAcknowledgeMessage_LogsDebugMessage(byte[] dataPage, string message)
164164
{
165165
// Arrange
166166
// Act
167167
_crankTorqueFrequencySensor.Parse(dataPage);
168168
// Assert
169169
_mockLogger.Verify(
170170
m => m.Log(
171-
LogLevel.Information,
171+
LogLevel.Debug,
172172
It.IsAny<EventId>(),
173173
It.Is<It.IsAnyType>((v, t) => v.ToString().Contains(message)),
174174
null,

AntPlus.UnitTests/SendMessageChannelTests.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public void AllMethods_ThrowNotImplementedException()
8080
public async Task SendExtAcknowledgedDataAsync_InvokesMethodMultipleTimesAndReturnsPass()
8181
{
8282
var channelId = new ChannelId(0);
83-
var data = Array.Empty<byte>();
83+
var data = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 };
8484
var messagingReturnCode = MessagingReturnCode.Pass;
8585

8686
_mockChannel.Setup(c => c.SendExtAcknowledgedDataAsync(channelId, data, It.IsAny<uint>()))
@@ -114,7 +114,7 @@ public async Task SendExtAcknowledgedDataAsync_InvokesMethodMultipleTimesAndRetu
114114
public async Task SendExtAcknowledgedDataAsync_InvokesMethodAndReturnsTimeout()
115115
{
116116
var channelId = new ChannelId(0);
117-
var data = Array.Empty<byte>();
117+
var data = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 };
118118
var messagingReturnCode = MessagingReturnCode.Timeout;
119119
_mockChannel.Setup(c => c.SendExtAcknowledgedDataAsync(channelId, data, It.IsAny<uint>()))
120120
.ReturnsAsync(messagingReturnCode);

0 commit comments

Comments
 (0)