MangoAutomation / BACnet4J

BACnet/IP stack written in Java. Forked from http://sourceforge.net/projects/bacnet4j/
GNU General Public License v3.0
187 stars 111 forks source link

Unable to update NotificationClass priority #85

Open envas opened 1 year ago

envas commented 1 year ago

There is a bug in the class NotificationClassObject.validateProperty. When updating the property priority, the following error occurs:

java.lang.ClassCastException: com.serotonin.bacnet4j.type.constructed.SequenceOf cannot be cast to com.serotonin.bacnet4j.type.constructed.BACnetArray
    at com.serotonin.bacnet4j.obj.NotificationClassObject.validateProperty(NotificationClassObject.java:117)
    at com.serotonin.bacnet4j.obj.BACnetObject.writeProperty(BACnetObject.java:486)
    at com.serotonin.bacnet4j.service.confirmed.WritePropertyRequest.handle(WritePropertyRequest.java:102)
    at com.serotonin.bacnet4j.transport.DefaultTransport.handleConfirmedRequest(DefaultTransport.java:870)
    at com.serotonin.bacnet4j.transport.DefaultTransport.incomingConfirmedRequest(DefaultTransport.java:827)
    at com.serotonin.bacnet4j.transport.DefaultTransport.receiveAPDU(DefaultTransport.java:640)
    at com.serotonin.bacnet4j.transport.DefaultTransport.receiveImpl(DefaultTransport.java:578)
    at com.serotonin.bacnet4j.transport.DefaultTransport.run(DefaultTransport.java:498)
    at java.lang.Thread.run(Thread.java:750)

In the source code, BACnetArray must be changed to SequenceOf

protected boolean validateProperty(final ValueSource valueSource, final PropertyValue value)
            throws BACnetServiceException {
        if (PropertyIdentifier.priority.equals(value.getPropertyIdentifier())) {
            final BACnetArray<UnsignedInteger> priority = value.getValue();  // <- type must be changed to SequenceOf
            if (priority.getCount() != 3)
                throw new BACnetServiceException(ErrorClass.property, ErrorCode.valueOutOfRange);
        }

        return false;
    }

The updated/extended test unit for the Notification class shows that the comparison must always be done as SequenceOf, even if the BACnetArray was written.

// Neopsis - update priority remotely:
        RequestUtils.writeProperty(d2, rd1, nc.getId(), PropertyIdentifier.priority,
                new BACnetArray<UnsignedInteger>( new UnsignedInteger(10),
                                                  new UnsignedInteger(20),
                                                  new UnsignedInteger(30)));
        Encodable ret = RequestUtils.getProperty(d2, rd1, nc.getId(), PropertyIdentifier.priority);
        assertEquals(ret, new SequenceOf<UnsignedInteger>(new UnsignedInteger(10),
                new UnsignedInteger(20), new UnsignedInteger(30)));

// Neopsis - update priority locally:
        nc.writePropertyInternal(PropertyIdentifier.priority,
                new BACnetArray<UnsignedInteger>( new UnsignedInteger(10),
                        new UnsignedInteger(20),
                        new UnsignedInteger(30)));
        ret = RequestUtils.getProperty(d2, rd1, nc.getId(), PropertyIdentifier.priority);
        assertEquals(ret, new SequenceOf<UnsignedInteger>(new UnsignedInteger(10),
                new UnsignedInteger(20), new UnsignedInteger(30)));
kishorevenki commented 7 months ago

The error is because Priority prooperty NC Object is of BACnetArray Data type whereas BACnet4J assigned its datatype as Sequence of. Sequence data type is typically used for List Data type in BACnet.