Example #1
0
        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));
        }
Example #3
0
        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);
        }
Example #4
0
        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)
Example #10
0
 public ushort CalculateContentLength(LegoWirelessMessage message)
 => CalculateMessageLength(message as HubPropertyMessage ?? throw new ArgumentException(nameof(message)));
 public ushort CalculateContentLength(LegoWirelessMessage message)
 => throw new NotImplementedException();
Example #12
0
    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));
    }
Example #13
0
 public ushort CalculateContentLength(LegoWirelessMessage message)
 => (ushort)(message switch
Example #14
0
    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);