Menu

Trendlog with AnotherStorageImplatation

2024-02-19
2024-03-12
  • Christopher Günther

    got some Problems reading trendlogs with ORCAview

    negativ count isn't supported in readrange in anotherstorageimplatation but standard says yes.
    why does BacnetMaxSegments.MAX_SEG0 "unspecified number of segments accepted" automatically mean no segments? (standard says unspecified! so could be anything?)

    even if I change MAX_SEG0 to MAX_SEG_SEG65 and allow negativ count ,HandleSegmentationResponse (transmit(segmentation)) allways throws an error indexoutofrangeexception;
    so response packet allways says Error code device error

     
  • Lance Tollenaar

    Lance Tollenaar - 2024-02-29

    Hi, I need some more information in order to debug. Maybe a wireshark log, an exception stack trace of any crashes, etc.

    Do you know exactly which line the exception is thrown?

    What do you mean by negative count? How can you have a negative count? Surely there are only three scenarios?
    MAX_SEG0 = "I don't support segmentation"
    MAX_SEG16, MAX_SEG32, etc. = "I only have enough memory to process up to 16/32/etc. segments"
    MAX_SEG_65 = "I have heaps of memory, send as many segments as you want"

     
  • Christopher Günther

    first problem still is that you cant ask for a negativ range, even Standard says yes.

    from standard:

    15.8.1.1.4.1.2 Count
    The absolute value of the 'Count' parameter specifies the number of records to be read. If 'Count' is positive, the record
    specified by 'Reference Index' shall be the first record read and returned; if 'Count' is negative the record specified by
    'Reference Index' shall be the last record. 'Count' may not be zero.
    15.8.1.1.4.1.3 Example - Positive Count
    Assume a device contains a list with 1000 items and is capable of returning 200 items in a ReadRange response. The
    ReadRange service request contains a ‘Reference Index’ = 800 and ‘Count’ = 300. The resulting ReadRange service
    response contains 200 items from Index 800 to 999 with FIRST_ITEM = FALSE, LAST_ITEM = FALSE, and
    MORE_ITEMS = TRUE. The ‘First Sequence Number’ parameter is not included in the response.

    15.8.1.1.4.1.4 Example - Negative Count
    Assume a device contains a list with 1000 items and is capable of returning 200 items in a ReadRange response. The
    ReadRange service request contains a ‘Reference Index’ = 1000 and ‘Count’ = -1000. The resulting ReadRange service
    response contains 200 items from Index 801 to 1000 with FIRST_ITEM = FALSE, LAST_ITEM = TRUE and
    MORE_ITEMS = TRUE. The ‘First Sequence Number’ shall not exist in the response.


    Trendlog.cs line 160
    public virtual byte[] GetEncodedTrends(uint start, int count, out BacnetResultFlags status)

    so maybe this can be fixed with (but should probably be added to BacnetActivity.cs handler_OnReadRange start becomes position)

    if(count<0)
    {
    start = (uint) (start + count);
    count = count * -1;
    }

    second problem is:

    and MAX_SEG0 doesnt mean "I dont support Segmentation" because this is defined by BACnetSegmentation which is conveid by IAM or is written in Device Object Type but isnt conveid by service-request! SO unspecified needs to know if BACnetSegmentation is supported and than can decide if it should send Segments. (this could probably be said for all responses which are segmented like readmultiple.......) or by type & BacnetPduTypes.SEGMENTED_RESPONSE_ACCEPTED even if MAX_SEG0

    from standard (mine is a bit older 2017 but i dont think this has changed)

    20.1.2.4 max-segments-accepted
    This parameter specifies the maximum number of segments that the device will accept. This parameter is included in the
    confirmed request so that the responding device may determine how to convey its response. The parameter shall be
    encoded as follows:

    B'000' Unspecified number of segments accepted.
    B'001' 2 segments accepted.
    B'010' 4 segments accepted.
    B'011' 8 segments accepted.
    B'100' 16 segments accepted.
    B'101' 32 segments accepted.
    B'110' 64 segments accepted.
    B'111' Greater than 64 segments accepted.

    also should HandleSegmentation not consider from the readrange.request which size a segmented response should have, based on MAX APDU Length Accepted in the request. ( In my example request I ask for 480 octets)

    B'0000' Up to MinimumMessageSize (50 octets)
    B'0001' Up to 128 octets
    B'0010' Up to 206 octets (fits in a LonTalk frame)
    B'0011' Up to 480 octets (fits in an ARCNET frame)
    B'0100' Up to 1024 octets
    B'0101' Up to 1476 octets (fits in an Ethernet frame)

    added a sample request which gets a error response from AnotherStorageImplatation (build with VTS)

     

    Last edit: Christopher Günther 2024-03-04
  • Christopher Günther

    So for all Servicerequests there should be an extra parameter saying max apdu length.
    because its possible to ask for different Maximum APDU Length but while using bacnet-ip yabe only uses one Maximum APDU Length(which our client defienied)

    bacnetclient.cs like:
    public delegate void ReadRangeHandler(BacnetClient sender, BacnetAddress adr, byte invoke_id, BacnetObjectId objectId, BacnetPropertyReference property, BacnetReadRangeRequestTypes requestType, uint position, DateTime time, int count, BacnetMaxSegments max_segments,BacnetMaxAdpu maxAdpu);

    ** but this would probably break a lot of programs**

    than there should probably be an extra line in

    protected void ProcessConfirmedServiceRequest(BacnetAddress adr, BacnetPduTypes type,
    BacnetConfirmedServices service, BacnetMaxSegments max_segments, BacnetMaxAdpu max_adpu, byte invoke_id, byte[] buffer, int offset, int length)

      //send segmented if MAX_SEG0 unspecified but segmented response accepted than asume you can send as many as you want!
                    if(max_segments == BacnetMaxSegments.MAX_SEG0)
                    {
                        if ((type & BacnetPduTypes.SEGMENTED_RESPONSE_ACCEPTED) > 0)
                            max_segments = BacnetMaxSegments.MAX_SEG65;
                    }
    

    than you would probaby need a new
    GetSegmentBuffer
    GetMaxApdu

    public Segmentation GetSegmentBuffer(BacnetMaxSegments max_segments, BacnetMaxAdpu maxAdpu)
            {
                if (max_segments == BacnetMaxSegments.MAX_SEG0) return null;
                Segmentation ret = new Segmentation();
                ret.buffer = new EncodeBuffer(new byte[GetMaxApdu(maxAdpu)], m_client.HeaderLength);
                ret.max_segments = GetSegmentsCount(max_segments);       
                ret.window_size = m_proposed_window_size;
                return ret;
            }
    
    public int GetMaxApdu(BacnetMaxAdpu MaxAdpuLength)
            {
                int max_apdu;
                switch (MaxAdpuLength)
                {
                    case BacnetMaxAdpu.MAX_APDU1476:
                        max_apdu = 1476;
                        break;
                    case BacnetMaxAdpu.MAX_APDU1024:
                        max_apdu = 1024;
                        break;
                    case BacnetMaxAdpu.MAX_APDU480:
                        max_apdu = 480;
                        break;
                    case BacnetMaxAdpu.MAX_APDU206:
                        max_apdu = 206;
                        break;
                    case BacnetMaxAdpu.MAX_APDU128:
                        max_apdu = 128;
                        break;
                    case BacnetMaxAdpu.MAX_APDU50:
                        max_apdu = 50;
                        break;
                    default:
                        throw new NotImplementedException();
                }
                //max udp payload IRL seems to differ from the expectations in BACnet
                //so we have to adjust it. (In order to fulfill the standard)
                const int max_npdu_header_length = 4;       //usually it's '2', but it can also be more than '4'. Beware!
                return Math.Min(max_apdu, m_client.MaxBufferLength - m_client.HeaderLength - max_npdu_header_length);
            }
    

    so you can write something in Bacnetactivity.cs like:

    sender.ReadRangeResponse(adr, invoke_id, sender.GetSegmentBuffer(max_segments, maxAdpu), objectId, property, status, (uint)count, application_data, requestType, position);

    but i still got some problems and in my exampe i only using readrange, but probaby needs also be used in all other service request which could send segmented responses in my thought process an its not finished yet.

    so this could really break a lot of programs so @fchaxel should probably look at it and say if my thought process is correct and if we should implent it?

    also not sure how ProposedWindowSize works.

    after all this i still get an error somewhere in HandleSegmentation
    but trace messages are to small and only give me "System.IndexOutOfRangeException"
    because messages are only "ex.Message" and not only "ex" because than you could see the line which had an error!

     

    Last edit: Christopher Günther 2024-03-04
  • Christopher Günther

    This could also be a problem using a mstp->ip router if mstp device asks for segmented message, but while we are using bacnet ip we ignore the max apdu lenght of 480 which the mstp device wants and answer with or predefiend lenght of 1476, so the mstp device isn't able to ask for segmented messages. also not sure if we upload a file we probably will be using 1476 instead of 480?

     

    Last edit: Christopher Günther 2024-03-12

Log in to post a comment.