/**
* Controller
*
* Connects to PLCs and read/write data.
*
* @author pquiring
*/
package javaforce.controls;
import java.io.*;
import java.net.*;
import java.util.*;
import javaforce.controls.s7.*;
import javaforce.controls.mod.*;
import javaforce.controls.ab.*;
import javaforce.controls.ni.*;
public class Controller {
private boolean connected;
private Socket socket;
private InputStream is;
private OutputStream os;
private types plc;
private DAQmx daq;
private Object lock = new Object(); //read/write lock
private static Object s7_connect_lock = new Object();
private ABContext ab_context;
public static double rate; //sample rate for all controllers (set before connecting to any controllers)
public Exception lastException;
public static enum types {
S7, AB, MB, NI
};
public static enum sizes {
bit, int8, int16, int32, float32, float64
}
public void setRate(float rate) {
this.rate = rate;
}
/** Connects to a PLC:
*
* url = "S7:host"
* url = "MODBUS:host"
* url = "AB:host"
* url = "NI:device/options"
*
*/
public boolean connect(String url) {
System.out.println("Info:" + System.currentTimeMillis() + ":Controller.connect():" + url);
connected = false;
if (url.startsWith("S7:")) {
plc = types.S7;
String host = url.substring(3);
synchronized(s7_connect_lock) {
try {
socket = new Socket(host, 102);
socket.setSoTimeout(3000);
os = socket.getOutputStream();
is = socket.getInputStream();
//connect1
{
byte packet[] = S7Packet.makeConnectPacket1();
os.write(packet);
byte reply[] = new byte[1500];
int replySize = 0;
do {
int read = is.read(reply, replySize, 1500 - replySize);
if (read == -1) throw new Exception("bad read");
replySize += read;
} while (!S7Packet.isPacketComplete(Arrays.copyOf(reply, replySize)));
}
//connect2
{
byte packet[] = S7Packet.makeConnectPacket2();
os.write(packet);
byte reply[] = new byte[1500];
int replySize = 0;
do {
int read = is.read(reply, replySize, 1500 - replySize);
if (read == -1) throw new Exception("bad read");
replySize += read;
} while (!S7Packet.isPacketComplete(Arrays.copyOf(reply, replySize)));
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
connected = true;
return true;
}
if (url.startsWith("MODBUS:")) {
plc = types.MB;
String host = url.substring(7);
try {
socket = new Socket(host, 502);
socket.setSoTimeout(3000);
os = socket.getOutputStream();
is = socket.getInputStream();
} catch (Exception e) {
e.printStackTrace();
return false;
}
connected = true;
return true;
}
if (url.startsWith("AB:")) {
ab_context = new ABContext();
plc = types.AB;
String host = url.substring(3);
try {
socket = new Socket(host, 44818);
socket.setSoTimeout(3000);
os = socket.getOutputStream();
is = socket.getInputStream();
//connect1
{
byte packet[] = ABPacket.makeConnectPacket(ab_context);
os.write(packet);
byte reply[] = new byte[1500];
int replySize = 0;
do {
int read = is.read(reply, replySize, 1500 - replySize);
if (read == -1) throw new Exception("bad read");
replySize += read;
} while (!ABPacket.isPacketComplete(Arrays.copyOf(reply, replySize)));
ENIP ip = new ENIP();
ip.read(reply, 0);
ab_context.session = ip.session;
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
connected = true;
return true;
}
if (url.startsWith("NI:")) {
plc = types.NI;
daq = new DAQmx();
connected = daq.connect(url.substring(3));
if (!connected) {
daq.close();
daq = null;
}
return connected;
}
return false;
}
/** Disconnects from PLC. */
public boolean disconnect() {
if (!connected) return false;
switch (plc) {
case S7:
case MB:
case AB:
try {
if (socket != null) {
socket.close();
socket = null;
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
break;
case NI:
if (daq != null) {
daq.close();
daq = null;
}
break;
}
connected = false;
return true;
}
/** Data types for write() function. Only AB protocol requires these. */
public enum datatype {
ANY, INTEGER16, INTEGER32, FLOAT, BOOLEAN
}
/** Writes data to PLC. */
public boolean write(String addr, byte data[]) {
return write(addr, data, datatype.ANY);
}
/** Writes data to PLC.
*
* datatype is required for AB controllers.
*/
public boolean write(String addr, byte data[], datatype type) {
synchronized(lock) {
if (!connected) return false;
switch (plc) {
case S7: {
S7Data s7 = S7Packet.decodeAddress(addr);
s7.data = data;
byte packet[] = S7Packet.makeWritePacket(s7);
try {
os.write(packet);
} catch (Exception e) {
lastException = e;
return false;
}
return true;
}
case MB: {
ModAddr ma = ModPacket.decodeAddress(addr);
ma.state = data[0] != 0;
byte packet[] = ModPacket.makeWritePacket(ma);
try {
os.write(packet);
} catch (Exception e) {
lastException = e;
return false;
}
byte reply[] = new byte[1500];
int replySize = 0;
try {
do {
int read = is.read(reply, replySize, 1500 - replySize);
if (read == -1) throw new Exception("bad read");
replySize += read;
} while (!ModPacket.isPacketComplete(Arrays.copyOf(reply, replySize)));
} catch (Exception e) {
lastException = e;
return false;
}
return true;
}
case AB: {
if (type == datatype.ANY) return false;
byte packet[] = ABPacket.makeWritePacket(addr, ABPacket.getType(type), data, ab_context);
try {
os.write(packet);
} catch (Exception e) {
lastException = e;
return false;
}
byte reply[] = new byte[1500];
int replySize = 0;
try {
do {
int read = is.read(reply, replySize, 1500 - replySize);
if (read == -1) throw new Exception("bad read");
replySize += read;
} while (!ABPacket.isPacketComplete(Arrays.copyOf(reply, replySize)));
} catch (Exception e) {
lastException = e;
return false;
}
return true;
}
case NI: {
System.out.println("NI write() not implemented");
return false;
}
}
return false;
}
}
/** Reads data from PLC. */
public byte[] read(String addr) {
synchronized(lock) {
if (!connected) return null;
switch (plc) {
case S7: {
S7Data s7 = S7Packet.decodeAddress(addr);
byte packet[] = S7Packet.makeReadPacket(s7);
try {
os.write(packet);
} catch (Exception e) {
lastException = e;
return null;
}
byte reply[] = new byte[1500];
int replySize = 0;
try {
do {
int read = is.read(reply, replySize, 1500 - replySize);
if (read == -1) throw new Exception("bad read");
replySize += read;
} while (!S7Packet.isPacketComplete(Arrays.copyOf(reply, replySize)));
} catch (Exception e) {
lastException = e;
return null;
}
s7 = S7Packet.decodePacket(Arrays.copyOf(reply, replySize));
return s7.data;
}
case MB: {
ModAddr ma = ModPacket.decodeAddress(addr);
byte packet[] = ModPacket.makeReadPacket(ma);
try {
os.write(packet);
} catch (Exception e) {
lastException = e;
return null;
}
byte reply[] = new byte[1500];
int replySize = 0;
try {
do {
int read = is.read(reply, replySize, 1500 - replySize);
if (read == -1) throw new Exception("bad read");
replySize += read;
} while (!ModPacket.isPacketComplete(Arrays.copyOf(reply, replySize)));
} catch (Exception e) {
lastException = e;
return null;
}
ModData data = ModPacket.decodePacket(Arrays.copyOf(reply, replySize));
return data.data;
}
case AB: {
byte packet[] = ABPacket.makeReadPacket(addr, ab_context);
try {
os.write(packet);
} catch (Exception e) {
lastException = e;
return null;
}
byte reply[] = new byte[1500];
int replySize = 0;
try {
do {
int read = is.read(reply, replySize, 1500 - replySize);
if (read == -1) throw new Exception("bad read");
replySize += read;
} while (!ABPacket.isPacketComplete(Arrays.copyOf(reply, replySize)));
return ABPacket.decodePacket(reply);
} catch (Exception e) {
lastException = e;
return null;
}
}
case NI: {
return daq.read();
}
}
return null;
}
}
/** Reads multiple data tags from PLC. (only S7 is currently supported) */
public byte[][] read(String addr[]) {
if (!connected) return null;
switch (plc) {
case S7: {
S7Data s7[] = new S7Data[addr.length];
for(int a=0;a<addr.length;a++) {
s7[a] = S7Packet.decodeAddress(addr[a]);
}
byte packet[] = S7Packet.makeReadPacket(s7);
try {
os.write(packet);
} catch (Exception e) {
lastException = e;
return null;
}
byte reply[] = new byte[1500];
int replySize = 0;
try {
do {
int read = is.read(reply, replySize, 1500 - replySize);
if (read == -1) throw new Exception("bad read");
replySize += read;
} while (!S7Packet.isPacketComplete(Arrays.copyOf(reply, replySize)));
} catch (Exception e) {
lastException = e;
return null;
}
s7 = S7Packet.decodeMultiPacket(Arrays.copyOf(reply, replySize), addr.length);
byte ret[][] = new byte[addr.length][];
for(int a=0;a<addr.length;a++) {
ret[a] = s7[a].data;
}
return ret;
}
/*
case MODBUS: {
ModAddr ma = ModPacket.decodeAddress(addr);
byte packet[] = ModPacket.makeReadPacket(ma);
try {
os.write(packet);
} catch (Exception e) {
lastException = e;
return null;
}
byte reply[] = new byte[1500];
int replySize = 0;
try {
do {
int read = is.read(reply, replySize, 1500 - replySize);
if (read == -1) throw new Exception("bad read");
replySize += read;
} while (!ModPacket.isPacketComplete(Arrays.copyOf(reply, replySize)));
} catch (Exception e) {
lastException = e;
return null;
}
ModData data = ModPacket.decodePacket(Arrays.copyOf(reply, replySize));
return data.data;
}
case AB: {
byte packet[] = ABPacket.makeReadPacket(addr, ab_context);
try {
os.write(packet);
} catch (Exception e) {
lastException = e;
return null;
}
byte reply[] = new byte[1500];
int replySize = 0;
try {
do {
int read = is.read(reply, replySize, 1500 - replySize);
if (read == -1) throw new Exception("bad read");
replySize += read;
} while (!ABPacket.isPacketComplete(Arrays.copyOf(reply, replySize)));
return ABPacket.decodePacket(reply);
} catch (Exception e) {
lastException = e;
return null;
}
}
*/
}
return null;
}
public boolean isConnected() {
if (plc == null) return false;
try {
switch (plc) {
case S7:
case AB:
case MB:
return socket.isConnected();
case NI:
default:
return connected;
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}