示例#1
0
        private void PortValueSingleEncoder_Decode <T>(string dataAsString, byte expectedPortId, PortModeInformationDataType expectedDataType, T[] expectedData)
        {
            var knowledge = new ProtocolKnowledge();

            var serviceProvider = new ServiceCollection()
                                  .AddPoweredUp()
                                  .BuildServiceProvider();


            KnowledgeManager.ApplyDynamicProtocolKnowledge(new HubAttachedIOForAttachedDeviceMessage(0x63, DeviceType.TechnicMediumHubTiltSensor, new Version("0.0.0.1"), new Version("0.0.0.1"))
            {
                HubId = 0
            }, knowledge, serviceProvider.GetService <IDeviceFactory>());

            // arrange
            var data = BytesStringUtil.StringToData(dataAsString);

            // act
            var message = MessageEncoder.Decode(data, knowledge) as PortValueSingleMessage;

            // assert
            Assert.Collection(message.Data,
                              d =>
            {
                Assert.Equal(d.PortId, expectedPortId);
                Assert.Equal(d.DataType, expectedDataType);

                if (d is PortValueData <T> actual)
                {
                    Assert.Collection(actual.InputValues, expectedData.Cast <T>().Select <T, Action <T> >(expected => actual => Assert.Equal(expected, actual)).ToArray());
                }
            }
                              );
        }
        public void PortValueCombinedModeEncoder_Decode(string dataAsString, byte expectedPortId, byte[] expectedModes, PortModeInformationDataType[] expectedDataType, int[] expectedData)
        {
            var knowledge = new ProtocolKnowledge();

            var serviceProvider = new ServiceCollection()
                                  .AddPoweredUp()
                                  .BuildServiceProvider();

            KnowledgeManager.ApplyDynamicProtocolKnowledge(new HubAttachedIOForAttachedDeviceMessage(0x00, DeviceType.TechnicLargeLinearMotor, new Version("0.0.0.1"), new Version("0.0.0.1"))
            {
                HubId = 0
            }, knowledge, serviceProvider.GetService <IDeviceFactory>());
            KnowledgeManager.ApplyDynamicProtocolKnowledge(new PortInputFormatSetupCombinedModeForSetModeDataSetMessage(
                                                               PortId: 0x00,
                                                               CombinationIndex: 0, // should refer 0b0000_0000_0000_1110 => SPEED POS APOS
                                                               ModeDataSets: new PortInputFormatSetupCombinedModeModeDataSet[] {
                new PortInputFormatSetupCombinedModeModeDataSet(0x01, 0),
                new PortInputFormatSetupCombinedModeModeDataSet(0x02, 0),
                new PortInputFormatSetupCombinedModeModeDataSet(0x03, 0),
            }
                                                               ), knowledge, serviceProvider.GetService <IDeviceFactory>());

            // arrange
            var data = BytesStringUtil.StringToData(dataAsString);

            // act
            var message = MessageEncoder.Decode(data, knowledge) as PortValueCombinedModeMessage;

            // assert
            Assert.Equal(expectedPortId, message.PortId);
            Assert.Collection(message.Data, Enumerable.Range(0, expectedModes.Length).Select <int, Action <PortValueData> >(pos => portValueData =>
            {
                Assert.Equal(expectedPortId, portValueData.PortId);
                Assert.Equal(expectedDataType[pos], portValueData.DataType);
                Assert.Equal(expectedDataType[pos], portValueData.DataType);

                if (portValueData is PortValueData <sbyte> actual)
                {
                    Assert.Equal(expectedData[pos], actual.InputValues[0]);
                }
                if (portValueData is PortValueData <short> actual2)
                {
                    Assert.Equal(expectedData[pos], actual2.InputValues[0]);
                }
                if (portValueData is PortValueData <int> actual3)
                {
                    Assert.Equal(expectedData[pos], actual3.InputValues[0]);
                }
            }).ToArray());
        }
示例#3
0
        public static void PrettyPrintKnowledge(TextWriter writer, ProtocolKnowledge portKnowledge, bool showConfiguration = true)
        {
            string Intent(int depth) => "                        ".Substring(0, depth * 2);

            string MinMaxDescription(float rawMin, float rawMax, float min, float max)
            {
                bool isPassThrough = (rawMax == max) && (rawMin == min);
                bool isTranslation = (rawMax - rawMin) == (max - min);
                bool isScaling     = !((rawMax == max) && (rawMin == min));

                return((isPassThrough, isTranslation, isScaling) switch
                {
                    (true, _, _) => " (pass-through)",
                    (false, false, false) => string.Empty,
                    (false, false, true) => " (scaling)",
                    (false, true, false) => " (translation)",
                    (false, true, true) => " (scaling, translation)",
                });
            }
示例#4
0
    private static void ResetProtocolKnowledgeForPort(byte hubId, byte portId, ProtocolKnowledge knowledge)
    {
        var port = knowledge.Port(hubId, portId);

        port.IsDeviceConnected = false;
        port.IOTypeId          = DeviceType.Unknown;
        port.HardwareRevision  = new Version("0.0.0.0");
        port.SoftwareRevision  = new Version("0.0.0.0");

        port.OutputCapability                = false;
        port.InputCapability                 = false;
        port.LogicalCombinableCapability     = false;
        port.LogicalSynchronizableCapability = false;
        port.Modes.Clear();

        port.ModeCombinations = Array.Empty <ushort>();

        port.UsedCombinationIndex       = 0;
        port.MultiUpdateEnabled         = false;
        port.ConfiguredModeDataSetIndex = Array.Empty <int>();
    }
示例#5
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 PortValueSingleEncoder(ProtocolKnowledge knowledge)
 {
     _knowledge = knowledge;
 }
示例#7
0
 private static IMessageContentEncoder CreateEncoder(MessageType messageType, ProtocolKnowledge knowledge)
 => messageType switch
 {
示例#8
0
 public PortValueCombinedModeEncoder(ProtocolKnowledge knowledge)
 {
     _knowledge = knowledge;
 }
示例#9
0
    private static void AddCachePortAndPortModeInformation(DeviceType type, Version hardwareRevision, Version softwareRevision, HubInfo hub, PortInfo port, ProtocolKnowledge knowledge, IDeviceFactory deviceFactory)
    {
        var device = deviceFactory.Create(type);

        if (device is not null)
        {
            foreach (var message in device.GetStaticPortInfoMessages(hardwareRevision, softwareRevision, hub.SystemType).Select(b => MessageEncoder.Decode(b, null)))
            {
                var messageToProcess = message;
                switch (messageToProcess)
                {
                case PortModeInformationMessage pmim:
                    messageToProcess = pmim with
                    {
                        HubId  = port.HubId,
                        PortId = port.PortId,
                    };
                    break;

                case PortInformationMessage pim:
                    messageToProcess = pim with
                    {
                        HubId  = port.HubId,
                        PortId = port.PortId,
                    };
                    break;
                }

                ApplyStaticProtocolKnowledge(messageToProcess, knowledge);

                if (messageToProcess is PortModeInformationMessage pmim2 && pmim2.InformationType == PortModeInformationType.Name)
                {
                    device.ExtendPortMode(knowledge.PortMode(pmim2.HubId, pmim2.PortId, pmim2.Mode));
                }
            }
        }
    }
示例#10
0
    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);
    }
示例#11
0
    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);
    }
示例#12
0
        private static void PrettyPrintKnowledge(TextWriter writer, ProtocolKnowledge portKnowledge)
        {
            string Intent(int depth) => "                        ".Substring(0, depth * 2);

            foreach (var hub in portKnowledge.Hubs.OrderBy(h => h.HubId))
            {
                Console.WriteLine($"{Intent(0)}Hub: {hub.HubId}");
                foreach (var port in hub.Ports.Values.OrderBy(p => p.PortId))
                {
                    writer.WriteLine($"{Intent(1)}Port: {port.PortId}");
                    writer.WriteLine($"{Intent(2)}IOTypeId: {port.IOTypeId}");
                    writer.WriteLine($"{Intent(2)}HardwareRevision: {port.HardwareRevision}");
                    writer.WriteLine($"{Intent(2)}SoftwareRevision: {port.SoftwareRevision}");

                    writer.WriteLine($"{Intent(2)}OutputCapability: {port.OutputCapability}");
                    writer.WriteLine($"{Intent(2)}InputCapability: {port.InputCapability}");
                    writer.WriteLine($"{Intent(2)}LogicalCombinableCapability: {port.LogicalCombinableCapability}");
                    writer.WriteLine($"{Intent(2)}LogicalSynchronizableCapability: {port.LogicalSynchronizableCapability}");

                    // PortInformationForPossibleModeCombinationsMessage
                    writer.WriteLine($"{Intent(2)}ModeCombinations: [{string.Join(", ", port.ModeCombinations.Select(x => BytesStringUtil.ToBitString(x)))}]");

                    writer.WriteLine($"{Intent(2)}UsedCombinationIndex: {port.UsedCombinationIndex}");
                    writer.WriteLine($"{Intent(2)}MultiUpdateEnabled: {port.MultiUpdateEnabled}");
                    writer.WriteLine($"{Intent(2)}ConfiguredModeDataSetIndex: [{string.Join(",", port.ConfiguredModeDataSetIndex)}]");

                    foreach (var mode in port.Modes.Values.OrderBy(m => m.ModeIndex))
                    {
                        writer.WriteLine($"{Intent(2)}Mode: {mode.ModeIndex}");
                        writer.WriteLine($"{Intent(3)}Name: {mode.Name}");
                        writer.WriteLine($"{Intent(3)}IsInput: {mode.IsInput}");
                        writer.WriteLine($"{Intent(3)}IsOutput: {mode.IsOutput}");

                        writer.WriteLine($"{Intent(3)}RawMin: {mode.RawMin}");
                        writer.WriteLine($"{Intent(3)}RawMax: {mode.RawMax}");

                        // PortModeInformationForPctMessage
                        writer.WriteLine($"{Intent(3)}PctMin: {mode.PctMin}");
                        writer.WriteLine($"{Intent(3)}PctMax: {mode.PctMax}");

                        // PortModeInformationForSIMessage
                        writer.WriteLine($"{Intent(3)}SIMin: {mode.SIMin}");
                        writer.WriteLine($"{Intent(3)}SIMax: {mode.SIMax}");

                        // PortModeInformationForSymbolMessage
                        writer.WriteLine($"{Intent(3)}Symbol: {mode.Symbol}");

                        // PortModeInformationForMappingMessage
                        writer.WriteLine($"{Intent(3)}InputSupportsNull: {mode.InputSupportsNull}");
                        writer.WriteLine($"{Intent(3)}InputSupportFunctionalMapping20: {mode.InputSupportFunctionalMapping20}");
                        writer.WriteLine($"{Intent(3)}InputAbsolute: {mode.InputAbsolute}");
                        writer.WriteLine($"{Intent(3)}InputRelative: {mode.InputRelative}");
                        writer.WriteLine($"{Intent(3)}InputDiscrete: {mode.InputDiscrete}");

                        writer.WriteLine($"{Intent(3)}OutputSupportsNull: {mode.OutputSupportsNull}");
                        writer.WriteLine($"{Intent(3)}OutputSupportFunctionalMapping20: {mode.OutputSupportFunctionalMapping20}");
                        writer.WriteLine($"{Intent(3)}OutputAbsolute: {mode.OutputAbsolute}");
                        writer.WriteLine($"{Intent(3)}OutputRelative: {mode.OutputRelative}");
                        writer.WriteLine($"{Intent(3)}OutputDiscrete: {mode.OutputDiscrete}");

                        // PortModeInformationForValueFormatMessage
                        writer.WriteLine($"{Intent(3)}NumberOfDatasets: {mode.NumberOfDatasets}");
                        writer.WriteLine($"{Intent(3)}DatasetType: {mode.DatasetType}");
                        writer.WriteLine($"{Intent(3)}TotalFigures: {mode.TotalFigures}");
                        writer.WriteLine($"{Intent(3)}Decimals: {mode.Decimals}");

                        // PortInputFormatSingleMessage
                        writer.WriteLine($"{Intent(3)}DeltaInterval: {mode.DeltaInterval}");
                        writer.WriteLine($"{Intent(3)}NotificationEnabled: {mode.NotificationEnabled}");
                    }
                }
            }
        }