-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
180 additions
and
3 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
49 changes: 49 additions & 0 deletions
49
ZWaveDotNet/CommandClassReports/MultiChannelAssociationReport.cs
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
| ||
|
||
using System.Data; | ||
using ZWaveDotNet.Entities; | ||
using ZWaveDotNet.Util; | ||
|
||
namespace ZWaveDotNet.CommandClassReports | ||
{ | ||
public class MultiChannelAssociationReport : ICommandClassReport | ||
{ | ||
private const byte MULTI_CHANNEL_ASSOCIATION_SET_MARKER = 0x0; | ||
|
||
public readonly byte GroupID; | ||
|
||
public readonly byte MaxNodesSupported; | ||
|
||
public readonly byte ReportsToFollow; | ||
|
||
public readonly ushort[] Nodes; | ||
|
||
public readonly NodeEndpoint[] Endpoints; | ||
|
||
internal MultiChannelAssociationReport(Memory<byte> payload) | ||
{ | ||
if (payload.Length < 3) | ||
throw new DataException($"The Multi Channel Association Report was not in the expected format. Payload: {MemoryUtil.Print(payload)}"); | ||
|
||
GroupID = payload.Span[0]; | ||
MaxNodesSupported = payload.Span[1]; | ||
ReportsToFollow = payload.Span[2]; | ||
|
||
bool nodeMode = true; | ||
List<ushort> nodes = new List<ushort>(); | ||
List<NodeEndpoint> eps = new List<NodeEndpoint>(); | ||
|
||
for (int p = 3; p < payload.Length - 1; p++) | ||
{ | ||
if (payload.Span[p] == MULTI_CHANNEL_ASSOCIATION_SET_MARKER) | ||
nodeMode = false; | ||
else if (nodeMode) | ||
nodes.Add(payload.Span[p]); //FIXME: The spec is undefined for 16-bit NodeIDs | ||
else | ||
eps.Add(new NodeEndpoint(payload.Span[p++], payload.Span[p])); | ||
} | ||
Nodes = nodes.ToArray(); | ||
Endpoints = eps.ToArray(); | ||
} | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
// ZWaveDotNet Copyright (C) 2024 | ||
// | ||
// This program is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU Affero General Public License as published by | ||
// the Free Software Foundation, either version 3 of the License, or any later version. | ||
// This program is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY, without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
// See the GNU Affero General Public License for more details. | ||
// You should have received a copy of the GNU Affero General Public License | ||
// along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
using ZWaveDotNet.CommandClassReports; | ||
using ZWaveDotNet.CommandClassReports.Enums; | ||
using ZWaveDotNet.Entities; | ||
using ZWaveDotNet.Enums; | ||
using ZWaveDotNet.SerialAPI; | ||
|
||
namespace ZWaveDotNet.CommandClasses | ||
{ | ||
[CCVersion(CommandClass.MultiChannelAssociation, 2, 5)] | ||
public class MultiChannelAssociation : CommandClassBase | ||
{ | ||
public event CommandClassEvent<MultiChannelAssociationReport>? AssociationUpdate; | ||
|
||
public enum MultiChannelAssociationCommand | ||
{ | ||
Set = 0x1, | ||
Get = 0x2, | ||
Report = 0x3, | ||
Remove = 0x4, | ||
GroupingsGet = 0x5, | ||
GroupingsReport = 0x6 | ||
} | ||
public MultiChannelAssociation(Node node, byte endpoint) : base(node, endpoint, CommandClass.MultiChannelAssociation) { } | ||
|
||
public async Task<MultiChannelAssociationReport> Get(byte groupId, CancellationToken cancellationToken = default) | ||
{ | ||
if (node.ID == Node.BROADCAST_ID) | ||
throw new MethodAccessException("GET methods may not be called on broadcast nodes"); | ||
ReportMessage response = await SendReceive(MultiChannelAssociationCommand.Get, MultiChannelAssociationCommand.Report, cancellationToken, groupId); | ||
return new MultiChannelAssociationReport(response.Payload); | ||
} | ||
|
||
public async Task Set(byte groupId, ushort[] nodeIds, NodeEndpoint[] endPoints, CancellationToken cancellationToken = default) | ||
{ | ||
if (node.ID == Node.BROADCAST_ID) | ||
throw new MethodAccessException("Multi channel commands may not be called on broadcast nodes"); | ||
await AdjustMembership(MultiChannelAssociationCommand.Set, groupId, nodeIds, endPoints, cancellationToken); | ||
} | ||
|
||
public async Task Remove(byte groupId, ushort[] nodeIds, NodeEndpoint[] endPoints, CancellationToken cancellationToken = default) | ||
{ | ||
if (node.ID == Node.BROADCAST_ID) | ||
throw new MethodAccessException("Multi channel commands may not be called on broadcast nodes"); | ||
await AdjustMembership(MultiChannelAssociationCommand.Remove, groupId, nodeIds, endPoints, cancellationToken); | ||
} | ||
|
||
public async Task<byte> GetSupportedGroupCount(CancellationToken cancellationToken = default) | ||
{ | ||
if (node.ID == Node.BROADCAST_ID) | ||
throw new MethodAccessException("GET methods may not be called on broadcast nodes"); | ||
ReportMessage response = await SendReceive(MultiChannelAssociationCommand.Get, MultiChannelAssociationCommand.GroupingsReport, cancellationToken); | ||
return response.Payload.Span[0]; | ||
} | ||
|
||
private async Task AdjustMembership(MultiChannelAssociationCommand command, byte groupId, ushort[] nodeIds, NodeEndpoint[] endPoints, CancellationToken cancellationToken) | ||
{ | ||
byte[] payload = new byte[nodeIds.Length + ((endPoints.Length > 0) ? 2 : 1) + endPoints.Length]; | ||
int i = 0; | ||
payload[i++] = groupId; | ||
for (; i < nodeIds.Length; i++) | ||
payload[i] = (byte)nodeIds[i]; | ||
if (endPoints.Length > 0) | ||
i++; | ||
i++; | ||
foreach (var ep in endPoints) | ||
{ | ||
payload[i++] = (byte)ep.NodeID; | ||
payload[i] = ep.EndpointID; | ||
if (ep.BitmaskEndpoint) | ||
payload[i++] |= 0x80; | ||
else | ||
i++; | ||
} | ||
await SendCommand(command, cancellationToken, payload); | ||
} | ||
|
||
protected override async Task<SupervisionStatus> Handle(ReportMessage message) | ||
{ | ||
if (message.Command == (byte)MultiChannelAssociationCommand.Report) | ||
{ | ||
MultiChannelAssociationReport report = new MultiChannelAssociationReport(message.Payload); | ||
await FireEvent(AssociationUpdate, report); | ||
return SupervisionStatus.Success; | ||
} | ||
return SupervisionStatus.NoSupport; | ||
} | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// ZWaveDotNet Copyright (C) 2024 | ||
// | ||
// This program is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU Affero General Public License as published by | ||
// the Free Software Foundation, either version 3 of the License, or any later version. | ||
// This program is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY, without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
// See the GNU Affero General Public License for more details. | ||
// You should have received a copy of the GNU Affero General Public License | ||
// along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
namespace ZWaveDotNet.Entities | ||
{ | ||
public struct NodeEndpoint | ||
{ | ||
public NodeEndpoint(ushort nodeId, byte endPoint) | ||
{ | ||
NodeID = nodeId; | ||
EndpointID = (byte)(endPoint & 0x7F); | ||
BitmaskEndpoint = ((endPoint & 0x80) == 0x80); | ||
} | ||
|
||
public ushort NodeID { get; set; } | ||
public byte EndpointID { get; set; } | ||
public bool BitmaskEndpoint { get; set; } | ||
} | ||
} |