/*---------------------------------------------------------------------------------------------------------------- * CupCarbon: OSM based Wireless Sensor Network design and simulation tool * www.cupcarbon.com * ---------------------------------------------------------------------------------------------------------------- * Copyright (C) 2013 Ahcene Bounceur * ---------------------------------------------------------------------------------------------------------------- * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. *----------------------------------------------------------------------------------------------------------------*/ package device; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.geom.Point2D; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.PrintStream; import java.util.LinkedList; import java.util.List; import java.util.Random; import org.jdesktop.swingx.mapviewer.GeoPosition; import battery.Battery; //import cupcarbon.RadioModuleWindow; import map.MapLayer; import natural_events.Meteo; import project.Project; import radio_module.RadioModule; import radio_module.RadioStandard; import senscript.SenScript; import senscript.SenScriptAddCommand; import sensorunit.SensorUnit; import utilities.MapCalc; import utilities.UColor; import wisen_simulation.SimLog; import wisen_simulation.WisenSimulation; /** * @author Ahcene Bounceur * @author Lounis Massinissa * @version 1.0 */ public abstract class SensorNode extends DeviceWithRadio { protected SensorUnit sensorUnit; protected boolean messageLost = false; protected boolean comEdgeDrawn = false; protected Random rnd = new Random(); protected double variation = rnd.nextGaussian(); // protected int bufferSize = 14096; protected int bufferIndex = 0 ; protected byte [] buffer = new byte [bufferSize]; protected boolean bufferReady = false; protected double drssi = 0; // rssi in distance (meter) /** * Constructor 1 Instanciate the sensor unit * Instanciate the battery */ public SensorNode() { super(); addRadioModule("radio1", RadioStandard.ZIGBEE_802_15_4); currentRadioModule = radioModuleList.get(0); //sensorUnit = new SensorUnit(this.longitude, this.latitude, this); battery = new Battery(this); withRadio = true; withSensor = true; calculateRadioSpace(); initBuffer(); } /** * Constructor 2 * * @param x * Latitude * @param y * Longitude * @param radius * Radius of the sensor (default value = 0 meters) * @param radioRadius * Radius (range) of the radio (in meter) */ public SensorNode(double x, double y, double z, double radius, double radioRadius, int id) { super(x, y, z, radius, radioRadius, id); addRadioModule("radio1", RadioStandard.ZIGBEE_802_15_4); currentRadioModule = radioModuleList.get(0); battery = new Battery(this); withRadio = true; withSensor = true; calculateRadioSpace(); initBuffer(); } /** * Constructor 3 * * @param x * Latitude * @param y * Longitude * @param radius * Radius of the sensor (default value = 0 meters) * @param radioRadius * Radius (range) of the radio (in meter) * @param suRadius * Radius of the sensor unit (default value = 10 meters) */ public SensorNode(double x, double y, double z, double radius, double radioRadius, double suRadius, int id) { super(x, y, z, radius, radioRadius, id); addRadioModule("radio1", RadioStandard.ZIGBEE_802_15_4); currentRadioModule = radioModuleList.get(0); //sensorUnit = new SensorUnit(this.longitude, this.latitude, suRadius, this); battery = new Battery(this); withRadio = true; withSensor = true; calculateRadioSpace(); initBuffer(); } /** * Constructor 5 the same as the Constructor 3 with "String" argument * instead of "double" * * @param x * Latitude * @param y * Longitude * @param radius * Radius of the sensor (default value = 0 meters) * @param radioRadius * Radius (range) of the radio (in meter) * @param suRadius * Radius of the sensor unit (default value = 10 meters) */ public SensorNode(String x, String y, String z, String radius, String radioRadius, String suRadius, int id) { super(Double.valueOf(x), Double.valueOf(y), Double.valueOf(z), Double.valueOf(radius), Double.valueOf(radioRadius), id); addRadioModule("radio1", RadioStandard.ZIGBEE_802_15_4); currentRadioModule = radioModuleList.get(0); //sensorUnit = new SensorUnit(this.longitude, this.latitude, Double.valueOf(suRadius), this); battery = new Battery(this); withRadio = true; withSensor = true; calculateRadioSpace(); initBuffer(); } public void addRadioModule(String name, String sStandard) { int standard = RadioModule.getStandardByName(sStandard); addRadioModule(name, standard); } public void addRadioModule(String name, int standard) { for(RadioModule radioModule : radioModuleList) { if(radioModule.getName().equals(name) || radioModule.getName().equals("")) return ; } RadioModule radioModule = RadioModule.newRadioModule(this, name, standard); radioModuleList.add(radioModule); } public void addRadioModule(RadioModule radioModule) { for(RadioModule rm : radioModuleList) { if(rm.getName().equals(radioModule.getName()) || rm.getName().equals("")) return ; } radioModuleList.add(radioModule); } public void calculateRadioSpace() { if(geoZoneList.isEmpty()) { nPoint = 20; deg = 2.*Math.PI/nPoint; polyX = new int [nPoint]; polyY = new int [nPoint]; int[] coord = MapCalc.geoToPixelMapA(latitude, longitude); int x = coord[0]; int y = coord[1]; int rayon = MapCalc.radiusInPixels(getCurrentRadioRangeRadius() * this.getCurrentRadioModule().getPl() / 100); double r2=0; double r3=0; double i=0.0; for(int k=0; k<nPoint; k++) { r2 = (rayon+variation)*Math.cos(i); r3 = (rayon+variation)*Math.sin(i); polyX[k]=(int)(x+r2); polyY[k]=(int)(y+r3); i+=deg; } } else { nPoint = 0; polyX = null; polyY = null; } } public void variateRadius() { variation = rnd.nextGaussian()/0.2; } /** * Draw the (line) detection link * * @param device * Device * @param g * Graphics */ public void drawDetectionLink(Device device, Graphics g) { int[] coord = MapCalc.geoToPixelMapA(latitude, longitude); int lx1 = coord[0]; int ly1 = coord[1]; coord = MapCalc.geoToPixelMapA(device.getLatitude(), device.getLongitude()); int lx2 = coord[0]; int ly2 = coord[1]; g.setColor(Color.RED); g.drawLine(lx1, ly1, lx2, ly2); } @Override public void drawRadioRange(Graphics g) { if (visible) { Graphics2D g2 = (Graphics2D) g; g2.setStroke(new BasicStroke(0.4f)); if(hide == 0 || hide==5) { geoZoneList.setSelected(selected); geoZoneList.draw(g); } initDraw(g); int[] coord = MapCalc.geoToPixelMapA(latitude, longitude); int x = coord[0]; int y = coord[1]; int rayon = 10; if (inside || selected) { g.setColor(Color.LIGHT_GRAY); if(selected) g.setColor(Color.GRAY); if(MapLayer.dark) g.setColor(Color.ORANGE); g.drawLine(x-rayon-3, y-rayon-3, x-rayon+2, y-rayon-3); g.drawLine(x-rayon-3, y-rayon-3, x-rayon-3, y-rayon+2); g.drawLine(x-rayon-3, y+rayon+3, x-rayon+2, y+rayon+3); g.drawLine(x-rayon-3, y+rayon+3, x-rayon-3, y+rayon-2); g.drawLine(x+rayon+3, y-rayon-3, x+rayon-2, y-rayon-3); g.drawLine(x+rayon+3, y-rayon-3, x+rayon+3, y-rayon+2); g.drawLine(x+rayon+3, y+rayon+3, x+rayon-2, y+rayon+3); g.drawLine(x+rayon+3, y+rayon+3, x+rayon+3, y+rayon-2); } if(!isDead()) { calculateRadioSpace(); if(hide == 0 || hide == 2 || hide == 3) { if (nPoint>0) { g.setColor(UColor.BLACK_TTRANSPARENT); if(MapLayer.dark == true) g.setColor(Color.GRAY); g.drawPolygon(polyX, polyY, nPoint); } } g.setColor(Color.DARK_GRAY); if(hide == 0 || hide==5) { if (inside) { g.setColor(currentRadioModule.getRadioRangeColor2()); } else { g.setColor(currentRadioModule.getRadioRangeColor1()); } if(nPoint>0) g.fillPolygon(polyX, polyY, nPoint); } } } } @Override public void draw(Graphics g2) { if (visible) { Graphics2D g = (Graphics2D) g2; g.setStroke(new BasicStroke(0.4f)); int[] coord = MapCalc.geoToPixelMapA(latitude, longitude); int x = coord[0]; int y = coord[1]; int rayon = MapCalc.radiusInPixels(currentRadioModule.getRadioRangeRadius()) ; int rayon2 = MapCalc.radiusInPixels(this.radius); if (selected) { g.setColor(Color.GRAY); if(nPoint == 0) g.drawOval(x - 2, y - 2, 4, 4); else g.drawOval(x - rayon - 6, y - rayon - 6, (rayon + 6) * 2, (rayon + 6) * 2); } drawRadius(x, y, rayon2, g); drawRadioRadius(x, y, rayon, g); drawTheCenter(g, x, y); if (drawBatteryLevel) { battery.draw(g, x, y); g.setColor(UColor.WHITE_LTRANSPARENT); g.fillRect(x-20, y-25, 6, 50); g.setColor(Color.DARK_GRAY); g.fillRect(x-20, y-(int)(bufferIndex*1.0/bufferSize*100./2.)+25, 6, (int)(bufferIndex*1.0/bufferSize*100./2.)); if(MapLayer.dark) g.setColor(Color.WHITE); g.drawRect(x-20, y-25, 6, 50); g.drawString("Buffer"+id+": " + bufferIndex+"/"+bufferSize, x-30, y+45); } drawId(x, y, g); } } public void drawTheCenter(Graphics g, int x, int y) { Graphics2D g2 = (Graphics2D) g; g2.setStroke(new BasicStroke(0.6f)); int r ; if(!getGPSFileName().equals("")) { r = 6; //g.setColor(UColor.WHITE_TRANSPARENT); g.setColor(Color.ORANGE); g.fillOval(x - r, y - r, r*2, r*2); g.setColor(UColor.BLACK_TTRANSPARENT); g.drawOval(x - r, y - r, r*2, r*2); } if (underSimulation) { g.setColor(new Color(38, 194, 27)); } else { g.setColor(UColor.ORANGE); if(getScript() != null) { if(getScript().isWaiting()) g.setColor(Color.RED); } } if(getScriptFileName().equals("")) g.setColor(Color.LIGHT_GRAY); if(isDead()) g.setColor(Color.DARK_GRAY); r = 3; g.fillOval(x - r, y - r, r*2, r*2); g.setColor(UColor.BLACK_TTRANSPARENT); g.drawOval(x - r, y - r, r*2, r*2); } /** * Set the battery * * @param battery */ public void setBattery(Battery battery) { this.battery = battery; } @Override public String getName() { return getIdFL() + id; } @Override public void loadScript() { script = new SenScript(this); String projectTmpScriptPath = Project.getProjectScriptPath() + File.separator + scriptFileName; String tmp = projectTmpScriptPath; try { BufferedReader br = new BufferedReader(new FileReader(tmp)); String s = ""; while ((s = br.readLine()) != null) { addCommand(s); } br.close(); } catch (Exception e) {e.printStackTrace();} } public void loadScript(String fileName) { script = new SenScript(this); String projectTmpScriptPath = Project.getProjectScriptPath() + File.separator + fileName; String tmp = projectTmpScriptPath; try { BufferedReader br = new BufferedReader(new FileReader(tmp)); String s = ""; while ((s = br.readLine()) != null) { addCommand(s); } br.close(); } catch (Exception e) {e.printStackTrace();} } public void addMessageToBuffer(String message) { try { for(int i=0; i< message.length(); i++) { buffer[bufferIndex] = (byte) message.charAt(i); bufferIndex++; if(bufferIndex >= bufferSize) System.err.println("S"+getId()+": ERROR FULL BUFFER!"); } buffer[bufferIndex] = '\r'; bufferIndex++; } catch(Exception e) { System.err.println("S"+getId()+" [EMPTY MESSAGE]"); } } public int readMessage(String var) { int i=0; String s =""; while(buffer[i]!='\r') { s += (char) buffer[i]; i++; } SimLog.add("S"+getId()+" is reading from its buffer \""+s+"\" and puts it in "+var); script.putVariable(var, s); int k = 0; for(int j=i+1;j<bufferSize; j++) { buffer[k] = buffer[j]; k++; } bufferIndex = bufferIndex - (i+1); if(bufferIndex < 0){ bufferIndex = 0; bufferReady = false ; } return i; } public int pickMessage(String var) { int i=0; String s =""; while(buffer[i]!='\r') { s += (char) buffer[i]; i++; } SimLog.add("S"+getId()+" pick from its buffer \""+s+"\" and put it in "+var); script.putVariable(var, s); return i; } public void initBuffer() { bufferIndex = 0 ; bufferReady = false; for(int i=0; i<bufferSize; i++) { buffer[i] = '\r'; } } public boolean dataAvailable() { verifyData(); return bufferReady; } public void verifyData() { if(buffer[0]!='\r') { bufferReady = true; } else { bufferReady = false ; } } public int getDataSize() { int i=0; while(buffer[i]!='\r') { i++; } return i; } /** * @return the sensor nodes having the same radio standard module */ public List<SensorNode> getSensorNodeNeighbors() { List<SensorNode> neighnodes = new LinkedList<SensorNode>(); for(SensorNode snode : DeviceList.sensors) { if(((radioDetect(snode))) && this!=snode && !this.isDead() && canCommunicateWith(snode)) { neighnodes.add(snode); } } return neighnodes; } public byte [] getBuffer() { return buffer; } public boolean isRadioDetecting() { for(DeviceWithRadio d : DeviceList.sensors) { if(radioDetect(d) && this!=d) return true; } return false ; } public void addCommand(String instStr) { SenScriptAddCommand.addCommand(instStr.trim(), this, script); } public boolean isComEdgeDrawn() { return comEdgeDrawn; } public void setComEdgeDrawn(boolean comEdgeDrawn) { this.comEdgeDrawn = comEdgeDrawn; } @Override public void initForSimulation() { super.initForSimulation(); message = ""; setMarked(false); setVisited(false); setLedColor(0); initBattery(); this.getCurrentRadioModule().setPl(100); radioLinkColor = new Color(221,0,0,190); driftTime = 1.0; initBuffer(); setDead(false); loadScript(); getScript().init(); setEvent(0); setEvent2(0); setEvent3(0); setAckReceived(false); setAckWaiting(false); this.setSending(false); this.setReceiving(false); } @Override public void init() { super.init(); setSending(false); setReceiving(false); if(getScript()!=null) getScript().setWaiting(false); getCurrentRadioModule().setPl(100); } public int getBufferIndex() { return this.bufferIndex ; } @Override public void execute() { if (event == 0) { boolean cont = true; while (cont) { script.executeCommand(); if (script.getEvent() == 0) { script.next(); } else cont = false; } WisenSimulation.consolPrint(event+" : "); event = script.getEvent(); WisenSimulation.consolPrint(event+" | "); } } public String getSensorValues() { String s = ""; boolean first = true; for(Device device : DeviceList.devices) { if(!device.getClass().equals(Meteo.class)) { if(detect(device)) { if (!first) { s += "#"; } s += device.getId()+"#"+device.getValue(); first = false; } } } return s ; } public int getBufferSize() { return bufferSize; } public double [] getIntPosition() { double [] position = new double [3]; int [] coord = MapCalc.geoToPixelMapA(latitude, longitude); position[0] = coord[0]; position[1] = coord[1]; position[2] = 10; return position; } public double [] getPosition() { double [] position = new double [3]; position[0] = latitude; position[1] = longitude; position[2] = elevation; return position; } public void setPosition(double d, double e, double z) { this.longitude = d ; this.latitude = e ; this.elevation = z ; } public boolean canSee(SensorNode sn) { GeoPosition gp1 = new GeoPosition(sn.getLatitude(), sn.getLongitude()); Point2D p = MapLayer.mapViewer.getTileFactory().geoToPixel(gp1, MapLayer.mapViewer.getZoom()); return geoZoneList.contains((Point) p); } public boolean isSensorDetecting() { for(Device d : DeviceList.devices) { if(!d.getClass().equals(Meteo.class)) if(detect(d) && this!=d) return true; } return false ; } public SensorUnit getSensorUnit() { return sensorUnit; } public void setSensorUnit(SensorUnit sensorUnit) { this.sensorUnit = sensorUnit; } public boolean detect(Device device) { return sensorUnit.detect(device); } public void setSensorUnitRadius(double radius) { getSensorUnit().setRadius(radius); } public abstract SensorNode createNewWithTheSameType() ; @Override public SensorNode duplicate() { selected = false; SensorNode nSensor = createNewWithTheSameType(); nSensor.setHide(hide); nSensor.setDrawBatteryLevel(drawBatteryLevel); nSensor.setSensorUnitRadius(sensorUnit.getRadius()); nSensor.getBattery().setEMax(getBattery().getEMax()); nSensor.setScriptFileName(scriptFileName); nSensor.setGPSFileName(gpsFileName); nSensor.getRadioModuleList().removeAll(nSensor.getRadioModuleList()); for(RadioModule radioModule : radioModuleList) { RadioModule nRadioModule = radioModule.duplicate(nSensor); nSensor.addRadioModule(nRadioModule); if (radioModule.getName().equals(getCurrentRadioModule().getName())) { nSensor.selectCurrentRadioModule(getCurrentRadioModule().getName()); } } nSensor.setSelected(true); return nSensor; } @Override public SensorNode duplicateWithShift(double sLongitude, double sLatitude, double sElevation) { SensorNode nSensor = duplicate(); nSensor.shift(sLongitude, sLatitude, sElevation); return nSensor; } @Override public int getStandard() { return getCurrentRadioModule().getStandard(); } public int getNumberOfNeighbors() { if(DeviceList.propagationsCalculated) return neighbors.size(); return 0; } public double getESensing() { return this.getSensorUnit().getESensing(); } public abstract boolean detectBuildings(); public abstract String getParamsStr(); public void setMessageLost(boolean messageLost) { this.messageLost = messageLost; } public boolean getMessageLost() { return messageLost; } public LinkedList<RadioModule> getRadioModuleList() { return radioModuleList; } public RadioModule getRadioModuleByName(String name) { for (RadioModule radioModule : radioModuleList) { if(radioModule.getName().equals(name)) return radioModule; } return null; } public void saveRadioModule(String fileName) { try { PrintStream fos = null; fos = new PrintStream(new FileOutputStream(fileName)); fos.println(" List of radio Modules for the Sensor"+getId()); fos.println("------------------------------------------"); for (RadioModule radioModule : getRadioModuleList()) { radioModule.save(fos, currentRadioModule); } fos.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } } public double getDrssi() { return drssi; } public void setDrssi(double drssi) { this.drssi = drssi; } }