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