package com.serotonin.bacnet4j.npdu.mstp;
import com.serotonin.bacnet4j.apdu.APDU;
import com.serotonin.bacnet4j.enums.MaxApduLength;
import com.serotonin.bacnet4j.exception.BACnetException;
import com.serotonin.bacnet4j.npdu.IncomingRequestParser;
import com.serotonin.bacnet4j.npdu.MessageValidationAssertionException;
import com.serotonin.bacnet4j.npdu.Network;
import com.serotonin.bacnet4j.npdu.NetworkIdentifier;
import com.serotonin.bacnet4j.transport.Transport;
import com.serotonin.bacnet4j.type.constructed.Address;
import com.serotonin.bacnet4j.type.primitive.OctetString;
import org.free.bacnet4j.util.ByteQueue;
public class MstpNetwork extends Network {
private final MstpNode node;
public MstpNetwork(MstpNode node) {
this(node, 0);
}
public MstpNetwork(MstpNode node, int localNetworkNumber) {
super(localNetworkNumber);
this.node = node;
node.setNetwork(this);
}
@Override
public MaxApduLength getMaxApduLength() {
return MaxApduLength.UP_TO_480;
}
@Override
public void initialize(Transport transport) throws Exception {
super.initialize(transport);
node.initialize();
}
@Override
public void terminate() {
node.terminate();
}
@Override
public NetworkIdentifier getNetworkIdentifier() {
return new MstpNetworkIdentifier(node.getCommPortId());
}
@Override
public Address getLocalBroadcastAddress() {
return new Address(getLocalNetworkNumber(), (byte) 0xFF);
}
@Override
public Address[] getAllLocalAddresses() {
return new Address[] { new Address(getLocalNetworkNumber(), node.getThisStation()) };
}
@Override
public void checkSendThread() {
if (Thread.currentThread() == node.thread)
throw new IllegalStateException("Cannot send a request in the socket listener thread.");
}
@Override
public void sendAPDU(Address recipient, OctetString link, APDU apdu, boolean broadcast) throws BACnetException {
ByteQueue queue = new ByteQueue();
// NPCI
writeNpci(queue, recipient, link, apdu);
// APDU
apdu.write(queue);
byte[] data = queue.popAll();
byte mstpAddress;
if (recipient.isGlobal())
mstpAddress = getLocalBroadcastAddress().getMacAddress().getMstpAddress();
else if (link != null)
mstpAddress = link.getMstpAddress();
else
mstpAddress = recipient.getMacAddress().getMstpAddress();
if (apdu.expectsReply()) {
if (node instanceof SlaveNode)
throw new RuntimeException("Cannot originate a request from a slave node");
((MasterNode) node).queueFrame(FrameType.bacnetDataExpectingReply, mstpAddress, data);
}
else
node.setReplyFrame(FrameType.bacnetDataNotExpectingReply, mstpAddress, data);
}
public void sendTestRequest(byte destination) {
if (!(node instanceof MasterNode))
throw new RuntimeException("Only master nodes can send test requests");
((MasterNode) node).queueFrame(FrameType.testRequest, destination, null);
}
//
//
//
// Incoming frames
//
void receivedFrame(Frame frame) {
new IncomingFrameHandler(this, frame).run();
}
class IncomingFrameHandler extends IncomingRequestParser {
public IncomingFrameHandler(Network network, Frame frame) {
super(network, new ByteQueue(frame.getData()), new OctetString(frame.getSourceAddress()));
}
@Override
protected void parseFrame() throws MessageValidationAssertionException {
// no op. The frame has already been parsed.
}
}
//
//
// Convenience methods
//
public Address getAddress(byte station) {
return new Address(getLocalNetworkNumber(), station);
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((node == null) ? 0 : node.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
MstpNetwork other = (MstpNetwork) obj;
if (node == null) {
if (other.node != null)
return false;
}
else if (!node.equals(other.node))
return false;
return true;
}
}