package art.servers.etdserver.controller; import art.library.model.devices.DeviceStatus; import art.library.model.devices.etd.Etd; import art.library.model.devices.etd.EtdInformation; import art.library.interop.serialization.Serialization; import art.library.model.devices.Device; import art.library.model.devices.etd.status.EtdStatusVehicle; import art.library.model.transactions.traces.Trace; import art.library.utils.synchro.Mutex; import art.servers.ServerException; import art.servers.etdserver.Shared; import art.servers.etdserver.protocols.diamond.Diamond_Message; import art.servers.etdserver.protocols.diamond.Diamond_ProtocolAnalyser; import art.servers.etdserver.protocols.diamond.Diamond_ProtocolConstructor; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import static java.lang.Thread.sleep; import java.net.Socket; import java.net.SocketTimeoutException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; public class ControllerDiamondRaw extends ControllerEtd { private SimpleDateFormat sdh = new SimpleDateFormat("HH:mm"); private boolean connected = false; private Socket socket = null; private InputStream is = null; private OutputStream os = null; private int status = DeviceStatus.STATUS_ALARM; private boolean firstTime = true; private long lastVehicle = System.currentTimeMillis(); private long MAX_TIME_WITHOUT_VEHICLE_DETECTION = 30L*60000L; private int MAX_VEHICLES = 100; private Mutex mutexList = new Mutex(); private List lvehicle = new ArrayList(); private ControllerDataIntegration controllerDataIntegration = null; private long diftime = 0; public ControllerDiamondRaw(Etd etd) { super(etd); this.device = etd; this.name = Shared.getMessage("Controller etd") + " " + etd.information.name; } public void run() { controllerDataIntegration = new ControllerDataIntegration((ControllerEtd)this); controllerDataIntegration.start(); // art.servers.Shared.println(Trace.getTraceInformation(art.servers.Shared.getApplicationName(), name, art.servers.Shared.getMessage("Starting"), art.servers.Shared.getMessage("Success")), true); // status = DeviceStatus.STATUS_ONLINE; while ((isInterrupted() == false) && (exit == false)) { long startTimestamp = System.currentTimeMillis(); try { if (art.servers.Shared.isServerEnabled() == true) { if (connected == false) { connect(); } update(); } } catch (Exception e) { e.printStackTrace(); } if (startTimestamp > System.currentTimeMillis()) { startTimestamp = System.currentTimeMillis(); } long stopTimestamp = startTimestamp + (device.getDeviceInformation().polling * 1000); while ((System.currentTimeMillis() < stopTimestamp) && (exit == false)) { try { sleep(50); } catch (Exception e) { } } if (art.servers.Shared.model.existsDevice(device.getIdentifier()) == false) { art.servers.Shared.println(name, art.servers.Shared.getMessage("Device no longer exists")); exit = true; } } // art.servers.Shared.println(Trace.getTraceInformation(art.servers.Shared.getApplicationName(), name, art.servers.Shared.getMessage("Finishing"), art.servers.Shared.getMessage("Success")), true); // } /* Private controller functions */ private void update() throws Exception { Etd etdclone = (Etd)Serialization.clone(device); try { EtdInformation etdInformation = (EtdInformation)etdclone.getDeviceInformation(); startMonitorTrafficData(etdclone); // TODO // How to maintain traffic counter in time? while (true) { try { // Have a timeout, which if exceeded close connection and re-activate monitoring // EtdRealtime realtime = (EtdRealtime)etd.getDeviceRealtime(); Diamond_Message response = read(new byte[0]); List list = Diamond_ProtocolAnalyser.analyseVehicleResponse(etdclone, response.getResponseString()); if (list.size() > 0) lastVehicle = System.currentTimeMillis(); if (list.size() == 1) { EtdStatusVehicle vehicle = list.get(0); diftime = System.currentTimeMillis()-vehicle.timestamp; } try { for (EtdStatusVehicle vehicle : list) { mutexList.lockWrite(5000); try { vehicle.timestamp = vehicle.timestamp + diftime; logVehicle(etdclone, vehicle); lvehicle.add(vehicle); checkListSize(); } catch (Exception e) { } mutexList.releaseWrite(); } } catch (Exception e) { } if ((System.currentTimeMillis()-lastVehicle) > MAX_TIME_WITHOUT_VEHICLE_DETECTION) { lastVehicle = System.currentTimeMillis(); try{disconnect();} catch (Exception ex){}; return; } } catch (SocketTimeoutException e) { if ((System.currentTimeMillis()-lastVehicle) > MAX_TIME_WITHOUT_VEHICLE_DETECTION) { e.printStackTrace(); lastVehicle = System.currentTimeMillis(); try{disconnect();} catch (Exception ex){}; return; } } catch (ServerException e) { e.printStackTrace(); throw e; } catch (Exception e) { e.printStackTrace(); throw e; } } } catch (Exception exception) { if ((etdclone.alarms.alarm_offline <= 0) || (firstTime == true)) { firstTime = false; String message = art.servers.Shared.getMessage("Etd offline"); art.servers.Shared.println(name, exception); } try{disconnect();} catch (Exception ex){}; } } public List getVehicles (long timestamp) { List lresult = new ArrayList(); try { mutexList.lockRead(); for (EtdStatusVehicle vehicle : lvehicle) { if (vehicle.timestamp > timestamp) { lresult.add(vehicle); } } return(lresult); } catch (Exception e) { } finally { mutexList.releaseRead(); } return(lresult); } public List getVehiclesPeriod (long timestamp1, long timestamp2) { List lresult = new ArrayList(); try { mutexList.lockRead(); for (EtdStatusVehicle vehicle : lvehicle) { if ((vehicle.timestamp >= timestamp1) && (vehicle.timestamp <= timestamp2)) { lresult.add(vehicle); } } return(lresult); } catch (Exception e) { } finally { mutexList.releaseRead(); } return(lresult); } private void startMonitorTrafficData (Etd etdclone) throws Exception { try { byte[] command = Diamond_ProtocolConstructor.CR(); Diamond_Message response = read(command); response.checkError(); } catch (Exception e) { } try { byte[] command = Diamond_ProtocolConstructor.RESETCOMMS(); Diamond_Message response = read(command); response.checkError(); } catch (Exception e) { } int retries = 0; while (retries < 5) { try { byte[] command = Diamond_ProtocolConstructor.CR(); Diamond_Message response = read(command); response.checkError(); if ((response.getResponseString().toUpperCase().indexOf("PHO") > -1) || (response.getResponseString().toUpperCase().indexOf("UN") > -1)) { int index = response.getResponseString().indexOf("PHO#"); if (index < 0) { index = response.getResponseString().indexOf("UNI#"); } if (index > -1) { String sversion = response.getResponseString().substring(index+4, index+7); int version = Integer.parseInt(sversion); float f = (float)(((float)version) / 100f); if ((etdclone.getDeviceInformation().firmwareVersion == null) || (etdclone.getDeviceInformation().firmwareVersion.length() == 0)) etdclone.getDeviceInformation().firmwareVersion = "" + f; } retries = 5; } } catch (Exception e) { } retries++; } // Check datetime before starting monitor traffic data checkDatetime(etdclone); boolean error = true; retries = 0; while (error == true) { try { byte[] command = Diamond_ProtocolConstructor.startMonitorTrafficData(); Diamond_Message response = read(command); response.checkError(); Diamond_ProtocolAnalyser.analyseStartMonitorTrafficDataResponse(response); error = false; } catch (Exception e) { retries++; if (retries == 3) throw e; } } } private void startCollecting (Etd etdclone) { try { byte[] command = Diamond_ProtocolConstructor.startCollecting(); Diamond_Message response = read(command); response.checkError(); response.checkCommand(response.getResponseString().getBytes(), command); } catch (Exception e) { } } private void stopCollecting () { try { byte[] command = Diamond_ProtocolConstructor.stopCollecting(); Diamond_Message response = read(command); response.checkError(); response.checkCommand(response.getResponseString().getBytes(), command); } catch (Exception e) { } } private void checkDatetime (Etd etdclone) { try { byte[] command = Diamond_ProtocolConstructor.getSystemStatusCounter(); Diamond_Message response = read(command); long timestamp = System.currentTimeMillis(); response.checkError(); response.checkCommand(response.getResponseString().getBytes(), command); Diamond_Message message = new Diamond_Message(); message.setData(response.getDataByte(), command); long timeDifference = 0; long currenttime = 0; boolean collecting = false; if (etdclone.getDeviceInformation().firmwareVersion.indexOf("5.") > -1) { message.get6X(); message.get2X(); message.get2X(); message.get2X(); message.get4X(); message.get4X(); message.get4X(); message.get6X(); message.get6X(); message.get1X(); collecting = (message.get1X() == 0x01); int hour = message.get2X(); int minute = message.get2X(); int seconds = message.get2X(); int mseconds = message.get2X(); int month = message.get2X(); int date = message.get2X(); int year = message.get2X(); int dayOfWeek = message.get2X(); Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.HOUR_OF_DAY, hour); calendar.set(Calendar.MINUTE, minute); calendar.set(Calendar.SECOND, seconds); calendar.set(Calendar.MILLISECOND, mseconds); calendar.set(Calendar.YEAR, year+2000); calendar.set(Calendar.MONTH, month-1); calendar.set(Calendar.DATE, date); currenttime = calendar.getTimeInMillis(); timeDifference = Math.abs((currenttime-timestamp)); } else { message.get6X(); message.get2X(); message.get2X(); message.get4X(); message.get4X(); message.get6X(); message.get6X(); message.get1X(); collecting = (message.get1X() == 0x01); int hour = message.get2X(); int minute = message.get2X(); int seconds = message.get2X(); int mseconds = message.get2X(); int month = message.get2X(); int date = message.get2X(); int year = message.get2X(); int dayOfWeek = message.get2X(); Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.HOUR_OF_DAY, hour); calendar.set(Calendar.MINUTE, minute); calendar.set(Calendar.SECOND, seconds); calendar.set(Calendar.MILLISECOND, mseconds); calendar.set(Calendar.YEAR, year+2000); calendar.set(Calendar.MONTH, month-1); calendar.set(Calendar.DATE, date); currenttime = calendar.getTimeInMillis(); timeDifference = Math.abs((currenttime-timestamp)); } if (timeDifference >= 10000) { Shared.println(device.information.name, "Datetime incorrect: " + new Date(timestamp).toString() + " - " + new Date(currenttime).toString() + " - DIF: " + timeDifference + " - Collecting?: " + collecting); if (collecting == true) { // Stop collecting before set datetime stopCollecting(); } updateDatetimeCounter(etdclone); startCollecting(etdclone); } } catch (Exception e) { } } private void updateDatetimeCounter (Etd etdclone) { try { byte[] command = Diamond_ProtocolConstructor.sendDatetimeCounter(); Diamond_Message response = read(command); response.checkError(); response.checkCommand(response.getResponseString().getBytes(), command); Shared.println(device.information.name, "Datetime updated OK"); } catch (Exception e) { e.printStackTrace(); Shared.println(device.information.name, e); } } private void updateVersion (Etd etdclone, String connectionString) { try { int index = connectionString.indexOf("PHO#"); if (index < 0) { index = connectionString.indexOf("UNI#"); } if (index > -1) { String sversion = connectionString.substring(index+4, index+7); int version = Integer.parseInt(sversion); float f = (float)(((float)version) / 100f); if ((etdclone.getDeviceInformation().firmwareVersion == null) || (etdclone.getDeviceInformation().firmwareVersion.length() == 0)) etdclone.getDeviceInformation().firmwareVersion = "" + f; } } catch (Exception e) { } } public boolean isConnected () { return(this.connected); } private void connect() { try { if (this.socket != null) { if (this.connected == true) { return; } } this.socket = new Socket(this.device.getDeviceInformation().connection.address, this.device.getDeviceInformation().connection.port); this.socket.setSoTimeout(this.device.getDeviceInformation().connection.timeout); this.is = this.socket.getInputStream(); this.os = this.socket.getOutputStream(); this.connected = true; if (status != DeviceStatus.STATUS_ONLINE) { String message = Shared.getMessage("Connected, address = %1, port = %2, timeout = %3"); message = message.replace("%1", device.getDeviceInformation().connection.address); message = message.replace("%2", "" +device.getDeviceInformation().connection.port); message = message.replace("%3", "" + device.getDeviceInformation().connection.timeout); Shared.println(device.information.name, message); status = DeviceStatus.STATUS_ONLINE; } } catch (Exception e) { try{disconnect();} catch (Exception ex){}; } } private void disconnect() throws Exception { try { is.close(); }catch (Exception e) {} try { os.close(); }catch (Exception e) {} try { socket.close(); }catch (Exception e) {} is = null; os = null; socket = null; this.connected = false; } private Diamond_Message read(byte[] command) throws Exception { try { if (command.length > 0) send(command); return receive(); } catch (Exception e) { throw e; } } private void send(byte[] command) throws Exception { socket.getOutputStream().write(command); socket.getOutputStream().flush(); } private Diamond_Message receive() throws Exception { boolean salir = false; int res = 0; byte[] trama = null; int longitud = 0; int apuntador = 0; try { while ((res = is.read()) == 0){sleep(10);}; trama = new byte[65535]; trama[apuntador] = (byte)res; apuntador++; res = is.read(); while (true) { trama[apuntador] = (byte)res; apuntador++; res = is.read(); } } catch (SocketTimeoutException e) { if (apuntador > 0) { longitud = apuntador; } else throw e; } catch (Exception e) { throw e; } byte[] resultado = new byte[longitud]; System.arraycopy(trama, 0, resultado, 0, longitud); Diamond_Message message = new Diamond_Message(); message.setData(resultado); return(message); } private void checkListSize() { if (lvehicle.size() > MAX_VEHICLES) { int number = lvehicle.size() - MAX_VEHICLES; for (int i=0; i