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

  • Firstly, great job with the library!

    I have managed to figure out how to send a ReadRangeRequest to get trendlog logbuffer data from a trendlog (, however I'm stuck trying to figure out how to handle the response.

    Can anyone help me or point me in the right direction? I know I need to handle a ComplexACK somehow, I just can't seem to be able to figure out where orhow to do it in BACnet4J


  • Hi,

    Let me know if I can help. I have extensive experience with BACnet. Please send/post the code that you are trying to use and a Wireshark capture of the traffic on the wire. http://www.wireshark.org/

    Regards,
    Dave

    http://www.linkedin.com/in/davidcwilson


  • Help would be much appreciated. I'm not sure how to proceed in BACnet4J after I've sent the ReadRangeRequest.

    package com.serotonin.bacnet4j.test;
    
    import java.util.ArrayList;
    
    import com.serotonin.bacnet4j.LocalDevice;
    import com.serotonin.bacnet4j.RemoteDevice;
    import com.serotonin.bacnet4j.base.BACnetUtils;
    import com.serotonin.bacnet4j.event.DefaultDeviceEventListener;
    import com.serotonin.bacnet4j.service.confirmed.ReadRangeRequest;
    import com.serotonin.bacnet4j.service.confirmed.ReadRangeRequest.BySequenceNumber;
    import com.serotonin.bacnet4j.type.constructed.Address;
    import com.serotonin.bacnet4j.type.enumerated.ObjectType;
    import com.serotonin.bacnet4j.type.enumerated.PropertyIdentifier;
    import com.serotonin.bacnet4j.type.primitive.ObjectIdentifier;
    import com.serotonin.bacnet4j.type.primitive.SignedInteger;
    import com.serotonin.bacnet4j.type.primitive.UnsignedInteger;
    import com.serotonin.bacnet4j.util.PropertyReferences;
    import com.serotonin.bacnet4j.util.PropertyValues;
    
    public class readTrendlogData
    {
    	public static void main(String[] args) throws Exception
    	{
    		LocalDevice ld = new LocalDevice(1122, "192.168.3.255");
    		try
    		{
    			ld.initialize();
    			Handler h = new Handler();
    			ld.getEventHandler().addListener(h);
    			ld.sendBroadcast(47808, ld.getIAm());
    			
    			RemoteDevice dev3400 = null;
    
    			Address address = new Address(null, BACnetUtils.dottedStringToBytes("192.168.3.50"), 0xBAC0);
    			dev3400 = ld.findRemoteDevice(address, null, 3400);
    			
    			ObjectType obj = ObjectType.trendLog;
    			int ins = 0;
    
    			ArrayList<PropertyIdentifier>pis = new ArrayList<PropertyIdentifier>();
    			pis.add(PropertyIdentifier.totalRecordCount);
    			pis.add(PropertyIdentifier.recordCount);
    			ObjectIdentifier oid = new ObjectIdentifier(obj, ins);
    			PropertyReferences refs = new PropertyReferences();
    			for (PropertyIdentifier pi : pis)
    			{
    				refs.add(oid, pi);
    			}
    			PropertyValues pvs = ld.readProperties(dev3400, refs);
    			UnsignedInteger totalRecordCount = null;
    			SignedInteger count = null;
    			for (PropertyIdentifier pi : pis)
    			{
    				if (pi == PropertyIdentifier.totalRecordCount)
    				{
    					totalRecordCount = (UnsignedInteger) pvs.get(oid, pi);
    					System.out.println("Total record count: " + totalRecordCount);
    				}
    				else if (pi == PropertyIdentifier.recordCount)
    				{
    					UnsignedInteger ui = (UnsignedInteger) pvs.get(oid, pi);
    					count = new SignedInteger(ui.bigIntegerValue());
    					System.out.println("Record count: " + count);
    				}
    				//else
    				{
    					System.out.println(pi + " - " + pvs.getString(oid, pi));
    				}
    			}
    			
    			UnsignedInteger referenceIndex = new UnsignedInteger(totalRecordCount.longValue() - count.longValue() - 1);
    			ReadRangeRequest rrr = new ReadRangeRequest(new ObjectIdentifier(obj, ins), PropertyIdentifier.logBuffer, null, new BySequenceNumber(referenceIndex, count));
    			ld.send(dev3400, rrr);
    		}
    		finally
    		{
    			ld.terminate();
    		}
    	}
    
    	static class Handler extends DefaultDeviceEventListener
    	{
    		private ArrayList<RemoteDevice> devices;
    		public Handler()
    		{
    			devices = new ArrayList<RemoteDevice>();
    		}
    
    		@Override
    		public void iAmReceived(RemoteDevice d)
    		{
    			System.out.println("Heard from " + d.getInstanceNumber());
    			devices.add(d);
    		}
    
    		/**
    		 * @return the devices
    		 */
    		public ArrayList<RemoteDevice> getDevices()
    		{
    			return devices;
    		}
    	}
    }
    

    Attachment: download link


  • The simple answer is to cast the result from "ld.send(dev3400, rrr);" to a ReadRangeAck.


  • Thanks Matt, that was the exact info I needed.

    However, either I'm doing something wrong, or I think I've found a bug. I attempt to get the BaseType for the log record (which is a Real), and it throws the following Exception:

    Exception in thread "main" java.lang.ClassCastException: com.serotonin.bacnet4j.type.primitive.Real cannot be cast to com.serotonin.bacnet4j.type.constructed.BaseType
    	at com.serotonin.bacnet4j.type.constructed.LogRecord.getBaseType(LogRecord.java:170)
    	at com.serotonin.bacnet4j.test.readTrendlogData.main(readTrendlogData.java:88)
    ```Since the exception occurs in BACnet4J, I suspect it is probably a bug.
    

    package com.serotonin.bacnet4j.test;

    import java.util.ArrayList;
    import java.util.Iterator;

    import com.serotonin.bacnet4j.LocalDevice;
    import com.serotonin.bacnet4j.RemoteDevice;
    import com.serotonin.bacnet4j.base.BACnetUtils;
    import com.serotonin.bacnet4j.event.DefaultDeviceEventListener;
    import com.serotonin.bacnet4j.service.acknowledgement.ReadRangeAck;
    import com.serotonin.bacnet4j.service.confirmed.ReadRangeRequest;
    import com.serotonin.bacnet4j.service.confirmed.ReadRangeRequest.BySequenceNumber;
    import com.serotonin.bacnet4j.type.Encodable;
    import com.serotonin.bacnet4j.type.constructed.Address;
    import com.serotonin.bacnet4j.type.constructed.LogRecord;
    import com.serotonin.bacnet4j.type.enumerated.ObjectType;
    import com.serotonin.bacnet4j.type.enumerated.PropertyIdentifier;
    import com.serotonin.bacnet4j.type.primitive.ObjectIdentifier;
    import com.serotonin.bacnet4j.type.primitive.SignedInteger;
    import com.serotonin.bacnet4j.type.primitive.UnsignedInteger;
    import com.serotonin.bacnet4j.util.PropertyReferences;
    import com.serotonin.bacnet4j.util.PropertyValues;

    public class readTrendlogData
    {
    public static void main(String[] args) throws Exception
    {
    LocalDevice ld = new LocalDevice(1122, "192.168.3.255");
    try
    {
    ld.initialize();
    Handler h = new Handler();
    ld.getEventHandler().addListener(h);
    ld.sendBroadcast(47808, ld.getIAm());

    		RemoteDevice dev3400 = null;
    
    		Address address = new Address(null, BACnetUtils.dottedStringToBytes("192.168.3.50"), 0xBAC0);
    		dev3400 = ld.findRemoteDevice(address, null, 3400);
    		
    		ObjectType obj = ObjectType.trendLog;
    		int ins = 11;
    
    		ArrayList<PropertyIdentifier>pis = new ArrayList<PropertyIdentifier>();
    		pis.add(PropertyIdentifier.totalRecordCount);
    		pis.add(PropertyIdentifier.recordCount);
    		ObjectIdentifier oid = new ObjectIdentifier(obj, ins);
    		PropertyReferences refs = new PropertyReferences();
    		for (PropertyIdentifier pi : pis)
    		{
    			refs.add(oid, pi);
    		}
    		PropertyValues pvs = ld.readProperties(dev3400, refs);
    		UnsignedInteger totalRecordCount = null;
    		SignedInteger count = null;
    		for (PropertyIdentifier pi : pis)
    		{
    			if (pi == PropertyIdentifier.totalRecordCount)
    			{
    				totalRecordCount = (UnsignedInteger) pvs.get(oid, pi);
    				System.out.println("Total record count: " + totalRecordCount);
    			}
    			else if (pi == PropertyIdentifier.recordCount)
    			{
    				UnsignedInteger ui = (UnsignedInteger) pvs.get(oid, pi);
    				count = new SignedInteger(ui.bigIntegerValue());
    				System.out.println("Record count: " + count);
    			}
    			//else
    			{
    				System.out.println(pi + " - " + pvs.getString(oid, pi));
    			}
    		}
    		
    		UnsignedInteger referenceIndex = new UnsignedInteger(totalRecordCount.longValue() - count.longValue() - 1);
    		ReadRangeRequest rrr = new ReadRangeRequest(new ObjectIdentifier(obj, ins), PropertyIdentifier.logBuffer, null, new BySequenceNumber(referenceIndex, count));
    		ReadRangeAck rra = (ReadRangeAck)ld.send(dev3400, rrr);
    		System.out.println(rra.getItemCount());
    		System.out.println(rra.getFirstSequenceNumber());
    		System.out.println(rra.getItemData());
    		Iterator<?> it = (Iterator<?>)rra.getItemData().iterator();
    		while (it.hasNext())
    		{
    			Encodable e = (Encodable)it.next();
    			if (e instanceof LogRecord)
    			{
    				LogRecord lr = (LogRecord)e;
    				System.out.println(lr.getBaseType());
    				System.out.println(lr.getChoiceType());
    			}
    		}
    		
    	}
    	finally
    	{
    		ld.terminate();
    	}
    }
    
    static class Handler extends DefaultDeviceEventListener
    {
    	private ArrayList<RemoteDevice> devices;
    	public Handler()
    	{
    		devices = new ArrayList<RemoteDevice>();
    	}
    
    	@Override
    	public void iAmReceived(RemoteDevice d)
    	{
    		System.out.println("Heard from " + d.getInstanceNumber());
    		devices.add(d);
    	}
    
    	/**
    	 * @return the devices
    	 */
    	public ArrayList<RemoteDevice> getDevices()
    	{
    		return devices;
    	}
    }
    

    }

    
    I could call getChoiceType() to determine the type of data in the LogRecord and call the correct getXXX() accordingly, but there doesn't seem to be a set of constants (that I could find) defined to allow one to determine the datatype (yes, I could define them in my class, but it would be better to have it in BACnet4J).
    
    However, I think the ideal solution would be to add a function which allows one to call the appropriate getXXX() function in a strongly typed way (perhaps add a getData() function to LogRecord which returns Encodable).

  • Since the exception occurs in BACnet4J, I suspect it is probably a bug.

    Not impossible, but in this case i don't think so. This line:

    System.out.println(lr.getBaseType());
    
    

    ... tells the code to try and cast the datum to a base type. For this record you should call getReal() (funny name for a method, i know) instead. You will know which method to call by first calling getChoiceType() and picking the appropriate datum method based upon that.

    In any case, because the classes field actually lists Encodable and not BaseType, i've changed the method to be getEncodable instead, which will solve your casting problem should you choose to remain more general. Change has been checked into CVS.


  • Awesome stuff Matt. Cheers :D


  • HI can any one please help me on this ....

    package com.lnt.TestApp;

    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;

    import com.serotonin.bacnet4j.LocalDevice;
    import com.serotonin.bacnet4j.RemoteDevice;
    import com.serotonin.bacnet4j.enums.MaxApduLength;
    import com.serotonin.bacnet4j.exception.BACnetException;
    import com.serotonin.bacnet4j.npdu.ip.IpNetwork;
    import com.serotonin.bacnet4j.service.acknowledgement.AcknowledgementService;
    import com.serotonin.bacnet4j.service.acknowledgement.ReadPropertyAck;
    import com.serotonin.bacnet4j.service.acknowledgement.ReadRangeAck;
    import com.serotonin.bacnet4j.service.confirmed.ConfirmedRequestService;
    import com.serotonin.bacnet4j.service.confirmed.ReadPropertyRequest;
    import com.serotonin.bacnet4j.service.confirmed.ReadRangeRequest;
    import com.serotonin.bacnet4j.service.confirmed.ReadRangeRequest.BySequenceNumber;
    import com.serotonin.bacnet4j.service.unconfirmed.WhoIsRequest;
    import com.serotonin.bacnet4j.transport.Transport;
    import com.serotonin.bacnet4j.type.Encodable;
    import com.serotonin.bacnet4j.type.constructed.Address;
    import com.serotonin.bacnet4j.type.constructed.LogRecord;
    import com.serotonin.bacnet4j.type.constructed.SequenceOf;
    import com.serotonin.bacnet4j.type.enumerated.ObjectType;
    import com.serotonin.bacnet4j.type.enumerated.PropertyIdentifier;
    import com.serotonin.bacnet4j.type.enumerated.Segmentation;
    import com.serotonin.bacnet4j.type.primitive.ObjectIdentifier;
    import com.serotonin.bacnet4j.type.primitive.OctetString;
    import com.serotonin.bacnet4j.type.primitive.SignedInteger;
    import com.serotonin.bacnet4j.type.primitive.UnsignedInteger;
    import com.serotonin.bacnet4j.util.PropertyReferences;
    import com.serotonin.bacnet4j.util.PropertyValues;
    import com.serotonin.bacnet4j.util.RequestUtils;

    public class Test {
    static LocalDevice lDevice;
    static Address addr = new Address(0, "172.28.14.100");

    public Test() {
    }
    
    public static void main(String args[]) {
    	initializeDevice();
    }
    
    public static void initializeDevice() {
    	try {
    		System.out.println("Initializing...");
    		IpNetwork ipNetwork = new IpNetwork("172.28.14.255", 47808,
    				"172.28.14.63");
    		Transport transport = new Transport(ipNetwork);
    		lDevice = new LocalDevice(9899, transport);
    		lDevice.initialize();
    		lDevice.getEventHandler().addListener(new Listener());
    		lDevice.sendGlobalBroadcast(new WhoIsRequest());
    		Thread.sleep(500);
    
    		getObjectList(lDevice, "172.28.14.100", 47808, 0);
    	} catch (Exception e) {
    		System.out.println("Error : " + e.getMessage());
    	} finally {
    		closeDevice();
    	}
    }
    
    public static AcknowledgementService send(LocalDevice d,
    		ConfirmedRequestService s) throws Exception {
    	// Address a = new Address(InetAddrCache.get("localhost", 0xbac1));
    	return d.send(addr, null, MaxApduLength.UP_TO_1476,
    			Segmentation.segmentedBoth, s);
    }
    
    public static void closeDevice() {
    	try {
    		lDevice.terminate();
    	} catch (Exception e) {
    		System.out.println(e.getMessage());
    	}
    }
    
    private static void getObjectList(LocalDevice localDevice, String ip,
    		int port, int deviceId) {
    	RemoteDevice fileDev = null;
    	ObjectIdentifier file = null;
    	ReadPropertyRequest readPropertyRequest;
    	ReadPropertyAck reaPropertyAck;
    	UnsignedInteger referenceIndex = null;
    	SignedInteger signedInteger = null;
    	Address address[] = lDevice.getAllLocalAddresses();
    	OctetString octetString = new OctetString("172.28.14.63", 47808);
    	RemoteDevice dev3400 = null;
    	
    	//try {
    		//dev3400 = lDevice.findRemoteDevice(address[0], octetString, 0);
    	  dev3400 = lDevice.getRemoteDevice(address[0]);
    	//} catch (BACnetException e1) {
    		// TODO Auto-generated catch block
    	//	e1.printStackTrace();
    	//}
    
    	
    	for (RemoteDevice d : localDevice.getRemoteDevices()) {
    		// ObjectIdentifier oid = d.getObjectIdentifier();
    
    		RemoteDevice rd = new RemoteDevice(123,	localDevice.getAllLocalAddresses()[0], octetString);
    
    		@SuppressWarnings("unchecked")
    		List<ObjectIdentifier> oids;
    		try {
    			oids = ((SequenceOf<ObjectIdentifier>) RequestUtils	.sendReadPropertyAllowNull(localDevice, d,	d.getObjectIdentifier(),
    							PropertyIdentifier.objectList)).getValues();
    
    			for (ObjectIdentifier oid : oids) {
    				readPropertyRequest = new ReadPropertyRequest(oid, PropertyIdentifier.objectName);
    				reaPropertyAck = (ReadPropertyAck) localDevice.send(d,readPropertyRequest);
    				System.out.println("Value: " + reaPropertyAck.getValue());
    
    				
    				if (oid.getObjectType().equals(ObjectType.trendLog)) {
    
    					readPropertyRequest = new ReadPropertyRequest(oid,	PropertyIdentifier.objectName);
    					reaPropertyAck = (ReadPropertyAck) localDevice.send(d,	readPropertyRequest);
    
    					System.out.println("ObjectName: "+ reaPropertyAck.getValue());
    
    					readPropertyRequest = new ReadPropertyRequest(oid,PropertyIdentifier.bufferSize);
    					reaPropertyAck = (ReadPropertyAck) localDevice.send(d,readPropertyRequest);
    					System.out.println("BufferSize: "+ reaPropertyAck.getValue());
    
    					readPropertyRequest = new ReadPropertyRequest(oid,	PropertyIdentifier.totalRecordCount);
    					reaPropertyAck = (ReadPropertyAck) localDevice.send(d, readPropertyRequest);
    					System.out.println("totalRecordCount: "	+ reaPropertyAck.getValue());
    					// Encodable totalRecordCount =	// reaPropertyAck.getValue();
    
    					readPropertyRequest = new ReadPropertyRequest(oid, PropertyIdentifier.recordCount);
    					reaPropertyAck = (ReadPropertyAck) localDevice.send(d, readPropertyRequest);
    					System.out.println("RecordCount: "+ reaPropertyAck.getValue());
    					// Encodable recordCount = reaPropertyAck.getValue();
    
    					readPropertyRequest = new ReadPropertyRequest(oid, PropertyIdentifier.eventState);
    					reaPropertyAck = (ReadPropertyAck) localDevice.send(d, readPropertyRequest);
    					System.out.println("eventState: " + reaPropertyAck.getValue());
    
    					readPropertyRequest = new ReadPropertyRequest(oid,PropertyIdentifier.totalRecordCount);
    					reaPropertyAck = (ReadPropertyAck) lDevice.send(d,readPropertyRequest);
    					System.out.println("TotalRecordCount: "+ reaPropertyAck.getValue());
    					UnsignedInteger totalRecordCount = (UnsignedInteger) reaPropertyAck.getValue();
    
    					readPropertyRequest = new ReadPropertyRequest(oid, PropertyIdentifier.recordCount);
    					reaPropertyAck = (ReadPropertyAck) lDevice.send(d, readPropertyRequest);
    					System.out.println("RecordCount: "+ reaPropertyAck.getValue());
    					UnsignedInteger recordCount = (UnsignedInteger) reaPropertyAck.getValue();
    					signedInteger = new SignedInteger(recordCount.bigIntegerValue());
    
    					referenceIndex = new UnsignedInteger(totalRecordCount.longValue() - signedInteger.longValue() - 1);
    					
    					ReadRangeRequest rrr = new ReadRangeRequest(new ObjectIdentifier(ObjectType.trendLogMultiple, 11),
    							PropertyIdentifier.logBuffer, null,	new BySequenceNumber(referenceIndex,signedInteger));
    					//lDevice.send(d, rrr);
    					ReadRangeAck rra = (ReadRangeAck)lDevice.send(d, rrr);  
    
    					System.out.println(rra.getItemCount());   
    				    System.out.println(rra.getFirstSequenceNumber());   
    		            System.out.println(rra.getItemData());   
    		            Iterator<?> it = (Iterator<?>)rra.getItemData().iterator();   
    		            while (it.hasNext())   
    					{   
    			                Encodable e = (Encodable)it.next();   
    			                if (e instanceof LogRecord)   
    			                {   
    			                    LogRecord lr = (LogRecord)e;   
    			                    //System.out.println(lr.getBaseType());   
    			                    System.out.println(lr.getChoiceType());   
    			                }   
    			        }  
    				}
    			
    			}
    		} catch (BACnetException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    	}
    }
    

    }
    I am able to read bacnet objets, but i want to read trendlog contentes in my code when the flo comes ReadRangeRequest and ReadRangeAc am getting bacnet timeout exception can u please see the code and guid me on this...