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.