private void UpdateKnowledge(byte[] data, LegoWirelessMessage message) { var knowledge = _protocol.Knowledge; var applicableMessage = KnowledgeManager.ApplyStaticProtocolKnowledge(message, knowledge); if (message is PortInformationForModeInfoMessage msg) { var port = knowledge.Port(_hubId, msg.PortId); _ = RequestPortModePropertiesAsync(port); // discard the task to supress the await error } if (applicableMessage) { ReceivedMessagesData.Add(data); lock (lockObject) { ReceivedMessages++; } _logger?.LogInformation($"Stage: {_stageTwoCount}/{_stageTwoExpected}, Messages: {ReceivedMessages}/{SentMessages} "); CheckEndOfDiscovery(); } }
private void PortOutputCommandEncoder_Encode(string expectedDataAsString, LegoWirelessMessage message) { // act var data = MessageEncoder.Encode(message, null); // assert Assert.Equal(expectedDataAsString, BytesStringUtil.DataToString(data)); }
private static string MessageToString(LegoWirelessMessage message) { var result = message.ToString(); if (result.Contains(message.GetType().Name)) { result = $"{message.MessageType} in {message} (not yet formatted)"; } return(result); }
public static byte[] Encode(LegoWirelessMessage message, ProtocolKnowledge knowledge) { var messageType = message switch { HubPropertyMessage msg => MessageType.HubProperties, HubActionMessage msg => MessageType.HubActions, HubAlertMessage msg => MessageType.HubAlerts, HubAttachedIOMessage msg => MessageType.HubAttachedIO, GenericErrorMessage msg => MessageType.GenericErrorMessages, PortInformationRequestMessage msg => MessageType.PortInformationRequest, PortModeInformationRequestMessage msg => MessageType.PortModeInformationRequest, PortInputFormatSetupSingleMessage msg => MessageType.PortInputFormatSetupSingle, PortInputFormatSetupCombinedModeMessage msg => MessageType.PortInputFormatSetupCombinedMode, PortInformationMessage msg => MessageType.PortInformation, PortModeInformationMessage msg => MessageType.PortModeInformation, PortValueSingleMessage msg => MessageType.PortValueSingle, PortValueCombinedModeMessage msg => MessageType.PortValueCombinedMode, PortInputFormatSingleMessage msg => MessageType.PortInputFormatSingle, PortInputFormatCombinedModeMessage msg => MessageType.PortInputFormatCombinedMode, VirtualPortSetupMessage msg => MessageType.VirtualPortSetup, PortOutputCommandMessage msg => MessageType.PortOutputCommand, PortOutputCommandFeedbackMessage msg => MessageType.PortOutputCommandFeedback, _ => throw new NotImplementedException(), }; var encoder = CreateEncoder(messageType, knowledge); var contentLength = encoder.CalculateContentLength(message); var commonHeaderLength = (contentLength + 3 > 127) ? 4 : 3; byte[] data = new byte[commonHeaderLength + contentLength]; CommonMessageHeaderEncoder.Encode(contentLength, message.HubId, messageType, data.AsSpan().Slice(0, commonHeaderLength)); encoder.Encode(message, data.AsSpan().Slice(commonHeaderLength)); return(data); }
public static Task ApplyDynamicProtocolKnowledge(LegoWirelessMessage message, ProtocolKnowledge knowledge, IDeviceFactory deviceFactory) { HubInfo hub; PortInfo port; PortModeInfo mode; switch (message) { case HubPropertyMessage <SystemType> msg when msg.Property == HubProperty.SystemTypeId: hub = knowledge.Hub(msg.HubId); hub.SystemType = msg.Payload; break; case HubAttachedIOForAttachedDeviceMessage msg: hub = knowledge.Hub(msg.HubId); port = knowledge.Port(msg.HubId, msg.PortId); ResetProtocolKnowledgeForPort(msg.HubId, port.PortId, knowledge); port.IsDeviceConnected = true; port.IOTypeId = msg.IOTypeId; port.HardwareRevision = msg.HardwareRevision; port.SoftwareRevision = msg.SoftwareRevision; AddCachePortAndPortModeInformation(msg.IOTypeId, msg.HardwareRevision, msg.SoftwareRevision, hub, port, knowledge, deviceFactory); break; case HubAttachedIOForDetachedDeviceMessage msg: port = knowledge.Port(msg.HubId, msg.PortId); ResetProtocolKnowledgeForPort(msg.HubId, port.PortId, knowledge); port.IsDeviceConnected = false; break; case HubAttachedIOForAttachedVirtualDeviceMessage msg: hub = knowledge.Hub(msg.HubId); port = knowledge.Port(msg.HubId, msg.PortId); var partOfVirtual = knowledge.Port(msg.HubId, msg.PortAId); ResetProtocolKnowledgeForPort(msg.HubId, port.PortId, knowledge); port.IsDeviceConnected = true; port.IOTypeId = msg.IOTypeId; port.HardwareRevision = partOfVirtual.HardwareRevision; port.SoftwareRevision = partOfVirtual.SoftwareRevision; AddCachePortAndPortModeInformation(msg.IOTypeId, partOfVirtual.HardwareRevision, partOfVirtual.SoftwareRevision, hub, port, knowledge, deviceFactory); port.IsVirtual = true; port.PortAId = msg.PortAId; port.PortBId = msg.PortBId; break; case PortInputFormatSingleMessage msg: port = knowledge.Port(msg.HubId, msg.PortId); mode = knowledge.PortMode(msg.HubId, msg.PortId, msg.ModeIndex); port.LastFormattedPortMode = msg.ModeIndex; mode.DeltaInterval = msg.DeltaInterval; mode.NotificationEnabled = msg.NotificationEnabled; break; case PortInputFormatSetupCombinedModeForSetModeDataSetMessage msg: port = knowledge.Port(msg.HubId, msg.PortId); port.RequestedCombinedModeDataSets = msg.ModeDataSets; break; case PortInputFormatCombinedModeMessage msg: port = knowledge.Port(msg.HubId, msg.PortId); port.UsedCombinationIndex = msg.UsedCombinationIndex; port.MultiUpdateEnabled = msg.MultiUpdateEnabled; port.ConfiguredModeDataSetIndex = msg.ConfiguredModeDataSetIndex; break; } return(Task.CompletedTask); }
public static bool ApplyStaticProtocolKnowledge(LegoWirelessMessage message, ProtocolKnowledge knowledge) { var applicableMessage = true; PortInfo port; PortModeInfo mode; switch (message) { case PortInformationForModeInfoMessage msg: port = knowledge.Port(msg.HubId, msg.PortId); port.OutputCapability = msg.OutputCapability; port.InputCapability = msg.InputCapability; port.LogicalCombinableCapability = msg.LogicalCombinableCapability; port.LogicalSynchronizableCapability = msg.LogicalSynchronizableCapability; foreach (var modeInfo in Enumerable.Range(0, msg.TotalModeCount).Select(modeIndex => new PortModeInfo() { HubId = port.HubId, PortId = msg.PortId, ModeIndex = (byte)modeIndex, IsInput = ((1 << modeIndex) & msg.InputModes) > 0, IsOutput = ((1 << modeIndex) & msg.OutputModes) > 0 })) { port.Modes.TryAdd(modeInfo.ModeIndex, modeInfo); } break; case PortInformationForPossibleModeCombinationsMessage msg: port = knowledge.Port(msg.HubId, msg.PortId); port.ModeCombinations = msg.ModeCombinations; break; case PortModeInformationForNameMessage msg: mode = knowledge.PortMode(msg.HubId, msg.PortId, msg.Mode); mode.Name = msg.Name; break; case PortModeInformationForRawMessage msg: mode = knowledge.PortMode(msg.HubId, msg.PortId, msg.Mode); mode.RawMin = msg.RawMin; mode.RawMax = msg.RawMax; break; case PortModeInformationForPctMessage msg: mode = knowledge.PortMode(msg.HubId, msg.PortId, msg.Mode); mode.PctMin = msg.PctMin; mode.PctMax = msg.PctMax; break; case PortModeInformationForSIMessage msg: mode = knowledge.PortMode(msg.HubId, msg.PortId, msg.Mode); mode.SIMin = msg.SIMin; mode.SIMax = msg.SIMax; break; case PortModeInformationForSymbolMessage msg: mode = knowledge.PortMode(msg.HubId, msg.PortId, msg.Mode); mode.Symbol = msg.Symbol; break; case PortModeInformationForMappingMessage msg: mode = knowledge.PortMode(msg.HubId, msg.PortId, msg.Mode); mode.InputSupportsNull = msg.InputSupportsNull; mode.InputSupportFunctionalMapping20 = msg.InputSupportFunctionalMapping20; mode.InputAbsolute = msg.InputAbsolute; mode.InputRelative = msg.InputRelative; mode.InputDiscrete = msg.InputDiscrete; mode.OutputSupportsNull = msg.OutputSupportsNull; mode.OutputSupportFunctionalMapping20 = msg.OutputSupportFunctionalMapping20; mode.OutputAbsolute = msg.OutputAbsolute; mode.OutputRelative = msg.OutputRelative; mode.OutputDiscrete = msg.OutputDiscrete; break; case PortModeInformationForValueFormatMessage msg: mode = knowledge.PortMode(msg.HubId, msg.PortId, msg.Mode); mode.NumberOfDatasets = msg.NumberOfDatasets; mode.DatasetType = msg.DatasetType; mode.TotalFigures = msg.TotalFigures; mode.Decimals = msg.Decimals; break; default: applicableMessage = false; break; } return(applicableMessage); }
public Task WriteUpstreamAsync(LegoWirelessMessage message) => WriteUpstreamAsync(MessageEncoder.Encode(message, null));
public ushort CalculateContentLength(LegoWirelessMessage message) => 7;
public void Encode(LegoWirelessMessage message, in Span <byte> data)
public ushort CalculateContentLength(LegoWirelessMessage message) => CalculateMessageLength(message as HubPropertyMessage ?? throw new ArgumentException(nameof(message)));
public ushort CalculateContentLength(LegoWirelessMessage message) => throw new NotImplementedException();
public ushort CalculateContentLength(LegoWirelessMessage message) { var hubAlertMessage = message as HubAlertMessage ?? throw new ArgumentException("message is null or not HubAlertMessage", nameof(message)); return((ushort)(hubAlertMessage.Operation == HubAlertOperation.Update ? 3 : 2)); }
public ushort CalculateContentLength(LegoWirelessMessage message) => (ushort)(message switch
public static async Task <TResultMessage> SendMessageReceiveResultAsync <TResultMessage>(this ILegoWirelessProtocol self, LegoWirelessMessage message, Func <TResultMessage, bool> filter = default) { var awaitable = self.UpstreamMessages .OfType <TResultMessage>() .Where(resultMessage => filter is null || filter(resultMessage)) .FirstAsync() .GetAwaiter(); // make sure the subscription is present at the moment the message is sent. await self.SendMessageAsync(message); var result = await awaitable; return(result); }
public ushort CalculateContentLength(LegoWirelessMessage message) => (ushort)(message is PortInputFormatSetupCombinedModeForSetModeDataSetMessage setMessage ? 3 + setMessage.ModeDataSets.Length : 2);