From e73ef1f39fb3448e39d95b985225f50bdef87d99 Mon Sep 17 00:00:00 2001 From: baardl Date: Tue, 20 Apr 2021 12:16:56 +0200 Subject: [PATCH] #9 Read single properyt service. --- .../property/ReadSinglePropertyResult.java | 84 +++++++++++++++++++ .../ReadSinglePropertyResultParser.java | 59 +++++++++++++ .../internal/services/ServiceParser.java | 9 ++ .../bacnet/property/ReadPropertyService.java | 16 ++++ .../no/entra/bacnet/services/ServiceType.java | 4 + .../bacnet/services/ServicesSupported.java | 28 +++++++ .../ReadSinglePropertyResultParserTest.java | 27 ++++++ 7 files changed, 227 insertions(+) create mode 100644 src/main/java/no/entra/bacnet/internal/property/ReadSinglePropertyResult.java create mode 100644 src/main/java/no/entra/bacnet/internal/property/ReadSinglePropertyResultParser.java create mode 100644 src/main/java/no/entra/bacnet/property/ReadPropertyService.java create mode 100644 src/main/java/no/entra/bacnet/services/ServiceType.java create mode 100644 src/main/java/no/entra/bacnet/services/ServicesSupported.java create mode 100644 src/test/java/no/entra/bacnet/internal/property/ReadSinglePropertyResultParserTest.java diff --git a/src/main/java/no/entra/bacnet/internal/property/ReadSinglePropertyResult.java b/src/main/java/no/entra/bacnet/internal/property/ReadSinglePropertyResult.java new file mode 100644 index 0000000..846006a --- /dev/null +++ b/src/main/java/no/entra/bacnet/internal/property/ReadSinglePropertyResult.java @@ -0,0 +1,84 @@ +package no.entra.bacnet.internal.property; + +import no.entra.bacnet.internal.properties.PropertyIdentifier; +import no.entra.bacnet.objects.ObjectId; + +import java.util.Objects; + +public class ReadSinglePropertyResult { + private ObjectId objectId; + private PropertyIdentifier propertyIdentifier; + private Object value; + private Integer arrayIndexNumber = null; + + public ReadSinglePropertyResult() { + } + + public ReadSinglePropertyResult(ObjectId objectId, PropertyIdentifier propertyIdentifier, Object value) { + this.objectId = objectId; + this.propertyIdentifier = propertyIdentifier; + this.value = value; + } + + public ObjectId getObjectId() { + return objectId; + } + + public void setObjectId(ObjectId objectId) { + this.objectId = objectId; + } + + public PropertyIdentifier getPropertyIdentifier() { + return propertyIdentifier; + } + + public void setPropertyIdentifier(PropertyIdentifier propertyIdentifier) { + this.propertyIdentifier = propertyIdentifier; + } + + public Object getValue() { + return value; + } + + public void setValue(Object value) { + this.value = value; + } + + public Integer getArrayIndexNumber() { + return arrayIndexNumber; + } + + public void setArrayIndexNumber(Integer arrayIndexNumber) { + this.arrayIndexNumber = arrayIndexNumber; + } + + public boolean isValid() { + return objectId != null && propertyIdentifier != null && value != null; + } + + @Override + public String toString() { + return "ReadSinglePropertyResult{" + + "objectId=" + objectId + + ", propertyIdentifier=" + propertyIdentifier + + ", value=" + value + + ", arrayIndexNumber=" + arrayIndexNumber + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ReadSinglePropertyResult that = (ReadSinglePropertyResult) o; + return Objects.equals(getObjectId(), that.getObjectId()) && + getPropertyIdentifier() == that.getPropertyIdentifier() && + Objects.equals(getValue(), that.getValue()) && + Objects.equals(getArrayIndexNumber(), that.getArrayIndexNumber()); + } + + @Override + public int hashCode() { + return Objects.hash(getObjectId(), getPropertyIdentifier(), getValue(), getArrayIndexNumber()); + } +} diff --git a/src/main/java/no/entra/bacnet/internal/property/ReadSinglePropertyResultParser.java b/src/main/java/no/entra/bacnet/internal/property/ReadSinglePropertyResultParser.java new file mode 100644 index 0000000..3e01001 --- /dev/null +++ b/src/main/java/no/entra/bacnet/internal/property/ReadSinglePropertyResultParser.java @@ -0,0 +1,59 @@ +package no.entra.bacnet.internal.property; + +import no.entra.bacnet.internal.apdu.SDContextTag; +import no.entra.bacnet.internal.objects.ObjectIdMapper; +import no.entra.bacnet.internal.octet.OctetReader; +import no.entra.bacnet.internal.parseandmap.ParserResult; +import no.entra.bacnet.internal.properties.PropertyIdentifier; +import no.entra.bacnet.objects.ObjectId; +import no.entra.bacnet.octet.Octet; +import no.entra.bacnet.services.BacnetParserException; +import org.slf4j.Logger; + +import static org.slf4j.LoggerFactory.getLogger; + +public class ReadSinglePropertyResultParser { + private static final Logger log = getLogger(ReadSinglePropertyResultParser.class); + + public static ParserResult parse(String hexString) throws BacnetParserException { + ParserResult parserResult = new ParserResult(); + parserResult.setInitialHexString(hexString); + OctetReader propertyReader = new OctetReader(hexString); + + ReadSinglePropertyResult propertyResult = new ReadSinglePropertyResult(); + //1 Read ObjectId + Octet sdContextTag0 = propertyReader.next(); + if (!sdContextTag0.equals(SDContextTag.TAG0LENGTH4)) { + parserResult.setUnparsedHexString(propertyReader.unprocessedHexString()); + parserResult.setErrorMessage("PropertyResult must start with SD-ContextTag 0. Value is: " + sdContextTag0); + parserResult.setParsedOk(false); + throw new BacnetParserException("PropertyResult must start with SD-ContextTag 0. Value is: " + sdContextTag0, parserResult); + } + String objectIdHexString = propertyReader.next(4); + ParserResult objectIdResult = ObjectIdMapper.parse(objectIdHexString); + if (!objectIdResult.isParsedOk()) { + parserResult.setUnparsedHexString(propertyReader.unprocessedHexString()); + parserResult.setErrorMessage("Could not parse required parameter ObjectId from :" + objectIdHexString); + parserResult.setParsedOk(false); + throw new BacnetParserException("Could not parse required parameter ObjectId.", parserResult); + } else { + propertyResult.setObjectId(objectIdResult.getParsedObject()); + } + + //2 Read Property Identifier + Octet sdContextTag1 = propertyReader.next(); + if (!sdContextTag1.equals(SDContextTag.TAG1LENGTH1)) { + parserResult.setUnparsedHexString(propertyReader.unprocessedHexString()); + parserResult.setErrorMessage("PropertyResult must have SD-ContextTag 1. Value is: " + sdContextTag1); + parserResult.setParsedOk(false); + throw new BacnetParserException("PropertyResult must have with SD-ContextTag 1. Value is: " + sdContextTag1, parserResult); + } + final Octet propertyIdentifierOctet = propertyReader.next(); + PropertyIdentifier propertyIdentifier = PropertyIdentifier.fromOctet(propertyIdentifierOctet); + propertyResult.setPropertyIdentifier(propertyIdentifier); + parserResult.setParsedObject(propertyResult); + return parserResult; + + } +} + diff --git a/src/main/java/no/entra/bacnet/internal/services/ServiceParser.java b/src/main/java/no/entra/bacnet/internal/services/ServiceParser.java index a295943..356aa7b 100644 --- a/src/main/java/no/entra/bacnet/internal/services/ServiceParser.java +++ b/src/main/java/no/entra/bacnet/internal/services/ServiceParser.java @@ -3,9 +3,12 @@ import no.entra.bacnet.internal.parseandmap.ParserResult; import no.entra.bacnet.internal.properties.ReadObjectPropertiesResult; import no.entra.bacnet.internal.properties.ReadObjectPropertiesResultParser; +import no.entra.bacnet.internal.property.ReadSinglePropertyResult; +import no.entra.bacnet.internal.property.ReadSinglePropertyResultParser; import no.entra.bacnet.objects.ObjectId; import no.entra.bacnet.properties.ReadPropertyMultipleResponse; import no.entra.bacnet.properties.ReadPropertyMultipleService; +import no.entra.bacnet.property.ReadPropertyService; import no.entra.bacnet.services.*; import org.slf4j.Logger; @@ -80,6 +83,10 @@ protected static ParserResult parseServiceExpectingReply(ConfirmedServi try { switch (serviceChoice) { + case ReadProperty: + ParserResult readSinglePropertyResult = ReadSinglePropertyResultParser.parse(hexString); + ReadPropertyService readPropertyService = new ReadPropertyService(); + break; case ReadPropertyMultiple: ParserResult readPropertyMultipleResult = ReadObjectPropertiesResultParser.parse(hexString); if (readPropertyMultipleResult.isParsedOk()) { @@ -99,6 +106,8 @@ protected static ParserResult parseServiceExpectingReply(ConfirmedServi readPropertyMultipleService.setReadPropertyMultipleResponse(response); parserResult.setParsedObject(readPropertyMultipleService); parserResult.setParsedOk(true); + } else { + log.trace("Failed to parse ReadProperty or ReadPropertyMultiple. Result is {}. ServiceChoice: {}", readPropertyMultipleResult, serviceChoice); } break; default: diff --git a/src/main/java/no/entra/bacnet/property/ReadPropertyService.java b/src/main/java/no/entra/bacnet/property/ReadPropertyService.java new file mode 100644 index 0000000..e32b5ec --- /dev/null +++ b/src/main/java/no/entra/bacnet/property/ReadPropertyService.java @@ -0,0 +1,16 @@ +package no.entra.bacnet.property; + +import no.entra.bacnet.BacnetRequest; +import no.entra.bacnet.services.Service; + +public class ReadPropertyService extends BacnetRequest implements Service { + @Override + public String buildHexString() { + return null; + } + + @Override + public boolean expectReply() { + return false; + } +} diff --git a/src/main/java/no/entra/bacnet/services/ServiceType.java b/src/main/java/no/entra/bacnet/services/ServiceType.java new file mode 100644 index 0000000..f122330 --- /dev/null +++ b/src/main/java/no/entra/bacnet/services/ServiceType.java @@ -0,0 +1,4 @@ +package no.entra.bacnet.services; + +public enum ServiceType { +} diff --git a/src/main/java/no/entra/bacnet/services/ServicesSupported.java b/src/main/java/no/entra/bacnet/services/ServicesSupported.java new file mode 100644 index 0000000..f188a86 --- /dev/null +++ b/src/main/java/no/entra/bacnet/services/ServicesSupported.java @@ -0,0 +1,28 @@ +package no.entra.bacnet.services; + +import java.util.ArrayList; +import java.util.List; + +public class ServicesSupported { + + private final List supportedServices; + + public ServicesSupported() { + supportedServices = new ArrayList<>(); + } + + public ServicesSupported(List supportedServices) { + this.supportedServices = supportedServices; + } + public void addSupportedService(ServiceType serviceType) { + supportedServices.add(serviceType); + } + public void removeSupportedService(ServiceType serviceType) { + if (isServiceSupported(serviceType)) { + supportedServices.remove(serviceType); + } + } + public boolean isServiceSupported(ServiceType serviceType) { + return supportedServices.contains(serviceType); + } +} diff --git a/src/test/java/no/entra/bacnet/internal/property/ReadSinglePropertyResultParserTest.java b/src/test/java/no/entra/bacnet/internal/property/ReadSinglePropertyResultParserTest.java new file mode 100644 index 0000000..80763e4 --- /dev/null +++ b/src/test/java/no/entra/bacnet/internal/property/ReadSinglePropertyResultParserTest.java @@ -0,0 +1,27 @@ +package no.entra.bacnet.internal.property; + +import no.entra.bacnet.device.DeviceId; +import no.entra.bacnet.internal.parseandmap.ParserResult; +import no.entra.bacnet.internal.properties.PropertyIdentifier; +import no.entra.bacnet.services.BacnetParserException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +class ReadSinglePropertyResultParserTest { + + @BeforeEach + void setUp() { + } + + @Test + void parseSupportedServices() throws BacnetParserException { + String hexString = "0c0200000819613e850707000bc000f8003f"; + ParserResult parserResult = ReadSinglePropertyResultParser.parse(hexString); + assertNotNull(parserResult); + assertEquals(new DeviceId(8),parserResult.getParsedObject().getObjectId()); + assertEquals(PropertyIdentifier.ProtocolServicesSupported, parserResult.getParsedObject().getPropertyIdentifier()); + } +} \ No newline at end of file