OPCFoundation / UA-.NETStandard

OPC Unified Architecture .NET Standard
Other
1.89k stars 925 forks source link

KeyFrame is not sent if no changed values #2622

Open hzeng-tfs opened 1 month ago

hzeng-tfs commented 1 month ago

Type of issue

Current Behavior

I have a topic which includes a few data values. Most of time values are not changed. I set the KeyFrameCount to 5 to reduce number of messages.

However, the keyframe was sent only once if there is no value changes.

Expected Behavior

I expect: 0: message sent as key frame 1: not sent due to no changes 2: not sent due to no changes 3: not sent due to no changes 4: not sent due to no changes 5: message sent as key frame again (KeyFrame should be sent out even there are no changes. This is not happening) 5: not sent (This was actually happened.) 6: not sent due to no changes ...

Unless my understanding on how KeyFramCount works is incorrect. I have added the spec here: https://reference.opcfoundation.org/Core/Part14/v105/docs/6.2.4 The KeyFrameCount with DataType UInt32 is the multiplier of the PublishingInterval that defines the maximum number of times the PublishingInterval expires before a key frame message with values for all published Variables is sent. The delta frame DataSetMessages contains just the changed values. If no changes exist, the delta frame DataSetMessage shall not be sent. If the KeyFrameCount is set to 1, every message contains a key frame.

Steps To Reproduce

use project: https://github.com/OPCFoundation/UA-.NETStandard/blob/master/Applications/ConsoleReferencePublisher/README.md

comment out IncrementValue(variable, NamespaceIndexSimple) at UpdateValues(object state) on file PublishedValuesWrites.cs

                    foreach (FieldMetaData variable in m_simpleFields)
                    {
                        switch (variable.Name)
                        {
                            case "BoolToggle":
                                m_boolToogleCount++;
                                if (m_boolToogleCount >= BoolToogleLimit)
                                {
                                    m_boolToogleCount = 0;
                                    //IncrementValue(variable, NamespaceIndexSimple);
                                }
                                break;
                            case "Int32":
                                //IncrementValue(variable, NamespaceIndexSimple, SimpleInt32Limit);
                                break;
                            case "Int32Fast":
                                //IncrementValue(variable, NamespaceIndexSimple, SimpleInt32Limit, 100);
                                break;
                            case "DateTime":
                                //IncrementValue(variable, NamespaceIndexSimple);
                                break;
                        }
                    }

Environment

- OS:Windows 10
- Environment:
- Runtime:
- Nuget Version:
- Component:
- Server:
- Client:

Anything else?

I debug it a bit, it looks like state.MessageCount is increased on OnMessagePublished. So if the data values are not changed => OnMessagePublished is not called ==> MessageCount is not changed (remains 2 in my case), => IsDeltaFrame always returns true

public bool IsDeltaFrame(DataSetWriterDataType writer, out uint sequenceNumber)
{
    lock (m_dataSetStates)
    {
        DataSetState state = GetState(writer);
        sequenceNumber = state.MessageCount + 1;
        if (state.MessageCount % writer.KeyFrameCount != 0)
        {
            return true;
        }
    }
    return false;
}
hao-zeng-tfs commented 13 hours ago

Following up on this issue,

https://reference.opcfoundation.org/Core/Part14/v105/docs/6.2.4 The KeyFrameCount with DataType UInt32 is the multiplier of the PublishingInterval that defines the maximum number of times the PublishingInterval expires before a key frame message with values for all published Variables is sent. The delta frame DataSetMessages contains just the changed values. If no changes exist, the delta frame DataSetMessage shall not be sent. If the KeyFrameCount is set to 1, every message contains a key frame.

Can we have an option to send key frame, instead of delta frame when there are changes?

E.g. when the option is set to TRUE, the behaviours change from:

the first: key frame no changes: not sending no changes: not sending changes: delta frame no changes: not sending

To:

the first: key frame no changes: not sending no changes: not sending changes: key frame (not just changed values) no changes: not sending

I tried to override internal class MqttPubSubConnection : UaPubSubConnection, IMqttPubSubConnection, but it is defined as internal unfortunately.

Thanks.