Please Note This forum exists for community support for the Mango product family and the Radix IoT Platform. Although Radix IoT employees participate in this forum from time to time, there is no guarantee of a response to anything posted here, nor can Radix IoT, LLC guarantee the accuracy of any information expressed or conveyed. Specific project questions from customers with active support contracts are asked to send requests to support@radixiot.com.

Radix IoT Website Mango 3 Documentation Website Mango 4 Documentation Website

Statefull handling of the property services supported


  • the stack is willing to answer every service request and this is bad ;-)
    at startup we defined the implemented services via the service supported property.
    un- and confirmed requests will be handled by the following corrections:

        /**
         * statefull handling of the property services supported
         * 
         * @param services
         * @param type
         * @param queue
         * @return
         * @throws BACnetException
         */
        public static UnconfirmedRequestService createUnconfirmedRequestService(ServicesSupported services, byte type, ByteQueue queue)
                throws BACnetException {
            if (type == IAmRequest.TYPE_ID)
            {
            	if (services.isIAm())
            		return new IAmRequest(queue);
            	else
            		return null;
            }
            if (type == IHaveRequest.TYPE_ID)
            {
            	if (services.isIHave())
            		return new IHaveRequest(queue);
            	else
            		return null;
            }
            if (type == UnconfirmedCovNotificationRequest.TYPE_ID)
            {
            	if (services.isUnconfirmedCovNotification())
            		return new UnconfirmedCovNotificationRequest(queue);
            	else
            		return null;
            }
            if (type == UnconfirmedEventNotificationRequest.TYPE_ID)
            {
            	if (services.isUnconfirmedEventNotification())
            		return new UnconfirmedEventNotificationRequest(queue);
            	else
            		return null;
            }
            if (type == UnconfirmedPrivateTransferRequest.TYPE_ID)
            		if (services.isUnconfirmedPrivateTransfer())
            			return new UnconfirmedPrivateTransferRequest(queue);
            	else
            		return null;
            if (type == UnconfirmedTextMessageRequest.TYPE_ID)
            {
            	if (services.isUnconfirmedTextMessage())
            		return new UnconfirmedTextMessageRequest(queue);
            	else
            		return null;
            }
            if (type == TimeSynchronizationRequest.TYPE_ID)
            {
            	if ( services.isTimeSynchronization())
            		return new TimeSynchronizationRequest(queue);
            	else
            		return null;
            }
            if (type == WhoHasRequest.TYPE_ID)
            {
            	if (services.isWhoHas())
                return new WhoHasRequest(queue);
            	else
            		return null;
            }
            if (type == WhoIsRequest.TYPE_ID)
            {
            	if (services.isWhoIs())
            		return new WhoIsRequest(queue);
            	else
            		return null;
            }
            if (type == UTCTimeSynchronizationRequest.TYPE_ID)
            {
            	if (services.isUtcTimeSynchronization())
            		return new UTCTimeSynchronizationRequest(queue);
            	else
            		return null;
            }
    
            throw new BACnetException("Unsupported unconfirmed service: " + (type & 0xff));
        }
    
    

    we also need to mod the the class UnconfirmedRequest:

        public UnconfirmedRequest(ServicesSupported services, ByteQueue queue) throws BACnetException {
            queue.pop();
            byte choiceId = queue.pop();
            service = UnconfirmedRequestService.createUnconfirmedRequestService(services, choiceId, queue);
        }
    
    

    when the apdu will be created we need to take the upper mods into account and:

    abstract public class APDU {
        public static APDU createAPDU(ServicesSupported services, ByteQueue queue) throws BACnetException {
            // Get the first byte. The 4 high-order bits will tell us the type of PDU this is.
            byte type = queue.peek(0);
            type = (byte) ((type & 0xff) >> 4);
    
            if (type == ConfirmedRequest.TYPE_ID)
                return new ConfirmedRequest(services, queue);
            if (type == UnconfirmedRequest.TYPE_ID)
                return new UnconfirmedRequest(services, queue);
    
    

    unconfirmed request will not be answered when the service supported flag set to false.
    for confirmed service request it's a bit tricky.

        public static ConfirmedRequestService createConfirmedRequestService(ServicesSupported services, byte type, ByteQueue queue)
                throws BACnetException {
            if (type == AcknowledgeAlarmRequest.TYPE_ID) // 0
            {
            	if (services.isAcknowledgeAlarm())
            		return new AcknowledgeAlarmRequest(queue);
            }
            else if (type == ConfirmedCovNotificationRequest.TYPE_ID) // 1
            {
            	if (services.isConfirmedCovNotification())
            		return new ConfirmedCovNotificationRequest(queue);
            }
            else if (type == ConfirmedEventNotificationRequest.TYPE_ID) // 2
            {
            	if (services.isConfirmedEventNotification())
            		return new ConfirmedEventNotificationRequest(queue);
            }
            else if (type == GetAlarmSummaryRequest.TYPE_ID) // 3
            {
            	if (services.isGetAlarmSummary())
            		return new GetAlarmSummaryRequest(queue);
            }
            else if (type == GetEnrollmentSummaryRequest.TYPE_ID) // 4
            {
            	if (services.isGetEnrollmentSummary())
            		return new GetEnrollmentSummaryRequest(queue);
            	else
            		throw new BACnetRejectException(RejectReason.unrecognizedService);
            }
            else if (type == SubscribeCOVRequest.TYPE_ID) // 5
            {
            	if (services.isConfirmedCovNotification())
            		return new SubscribeCOVRequest(queue);
            }
            else if (type == AtomicReadFileRequest.TYPE_ID) // 6
            {
            	if (services.isAtomicReadFile())
            		return new AtomicReadFileRequest(queue);
            }
            else if (type == AtomicWriteFileRequest.TYPE_ID) // 7
            {
            	if (services.isAtomicWriteFile())
            		return new AtomicWriteFileRequest(queue);
            }
            else if (type == AddListElementRequest.TYPE_ID) // 8
            {
            	if (services.isAddListElement())
            		return new AddListElementRequest(queue);
            } 
            else if (type == RemoveListElementRequest.TYPE_ID) // 9
            {
            	if (services.isRemoveListElement())
            		return new RemoveListElementRequest(queue);
            }
            else if (type == CreateObjectRequest.TYPE_ID) // 10
            {
            	if (services.isCreateObject())
            		return new CreateObjectRequest(queue);
            }
            else if (type == DeleteObjectRequest.TYPE_ID) // 11
            {
            	if (services.isDeleteObject())
            		return new DeleteObjectRequest(queue);
            }
            else if (type == ReadPropertyRequest.TYPE_ID) // 12
            {
                return new ReadPropertyRequest(queue);
            }
            else if (type == ReadPropertyConditionalRequest.TYPE_ID) // 13
            {
            	if (services.isReadPropertyConditional())
            		return new ReadPropertyConditionalRequest(queue);
            }
            else if (type == ReadPropertyMultipleRequest.TYPE_ID) // 14
            {
            	if (services.isReadPropertyMultiple())
            		return new ReadPropertyMultipleRequest(queue);
            }
            else if (type == WritePropertyRequest.TYPE_ID) // 15
            {
            	if (services.isWritePropertyMultiple())
            		return new WritePropertyRequest(queue);
            }
            else if (type == WritePropertyMultipleRequest.TYPE_ID) // 16
            {
            	if (services.isWritePropertyMultiple())
            		return new WritePropertyMultipleRequest(queue);
            }
            else if (type == DeviceCommunicationControlRequest.TYPE_ID) // 17
            {
               	if (services.isDeviceCommunicationControl())
               		return new DeviceCommunicationControlRequest(queue);
            }
            else if (type == ConfirmedPrivateTransferRequest.TYPE_ID) // 18
            {
            	if (services.isConfirmedPrivateTransfer())
            		return new ConfirmedPrivateTransferRequest(queue);
            }
            else if (type == ConfirmedTextMessageRequest.TYPE_ID) // 19
            {
            	if (services.isConfirmedTextMessage())
            		return new ConfirmedTextMessageRequest(queue);
            }
            else if (type == ReinitializeDeviceRequest.TYPE_ID) // 20
            {
               	if (services.isReinitializeDevice())
               		return new ReinitializeDeviceRequest(queue);
            }
            else if (type == VtOpenRequest.TYPE_ID) // 21
            {
            	if (services.isVtOpen())
            		return new VtOpenRequest(queue);
            }
            else if (type == VtCloseRequest.TYPE_ID) // 22
            {
            	if (services.isVtClose())
            		return new VtCloseRequest(queue);
            }
            else if (type == VtDataRequest.TYPE_ID) // 23
            {
               	if (services.isVtData())
               		return new VtDataRequest(queue);
            }
            else if (type == AuthenticateRequest.TYPE_ID) // 24
            {
               	if (services.isAuthenticate())
               		return new AuthenticateRequest(queue);
            }
            else if (type == RequestKeyRequest.TYPE_ID) // 25
            {
            	if (services.isRequestKey())
            		return new RequestKeyRequest(queue);
            }
            else if (type == ReadRangeRequest.TYPE_ID) // 26
            {
            	if (services.isReadRange())
            		return new ReadRangeRequest(queue);
            }
            else if (type == LifeSafetyOperationRequest.TYPE_ID) // 27
            {
            	if (services.isLifeSafetyOperation())
                return new LifeSafetyOperationRequest(queue);
            }
            else if (type == SubscribeCOVPropertyRequest.TYPE_ID) // 28
            {
            	if (services.isSubscribeCovProperty())
            		return new SubscribeCOVPropertyRequest(queue);
            }
            else if (type == GetEventInformation.TYPE_ID) // 29
            {
            	if (services.isGetEventInformation())
            		return new GetEventInformation(queue);
           }
    
            throw new BACnetErrorException(ErrorClass.device, ErrorCode.serviceRequestDenied);
        }
    
    

    the mods for the class, added membervariable services:

    public class ConfirmedRequest extends APDU implements Segmentable {
        public static final byte TYPE_ID = 0;
        private ServicesSupported services;
    ...
    

    in the class ipmessagecontrol we make shure it matches:

                // Create the APDU.
                try {
                	ServicesSupported ss = (ServicesSupported) localDevice.getConfiguration().getProperty(PropertyIdentifier.protocolServicesSupported);
                    return APDU.createAPDU(ss, queue);
                }
    
    

    and now i am open for discussions :)

    robert


  • Hi Robert,

    This is all fine. There were a couple checks that weren't quite right, (e.g. SubscribeCOVRequest), but i think i found them all. Also, regarding confirmed requests i implemented in a way that i hope will work for you. Changes have been checked in.