Anexo A: Código Fuente José Ramón Fernández Acosta ANEXO A: CÓDIGO FUENTE A.1 Aplicación para la captura de muestras A.1.1 Código para Captura de muestras import import import import import org.placelab.core.BeaconMeasurement; org.placelab.core.WiFiReading; org.placelab.spotter.Spotter; org.placelab.spotter.SpotterException; org.placelab.spotter.WiFiSpotter; import java.io.*; import java.util.Timer; import java.util.TimerTask; /** * A sample that creates a WiFiSpotter and uses it to get measurements. * This will only return readings if a WiFi card is present. */ public class WiFiSpotterExample { int nrep = 0; static int interval = 200; String log ; static Spotter s = new WiFiSpotter(interval); PrintWriter write = null; public WiFiSpotterExample (String name, int num, int inter) { try{ log = name; interval = inter; File fichero = new File("C:/tmp/" + log); FileWriter fichwrite = new FileWriter(fichero); BufferedWriter datos = new BufferedWriter(fichwrite); write = new PrintWriter(datos); s.open(); Timer timer = new Timer(); timer.scheduleAtFixedRate (timerTask, 0, interval); while (nrep< num); timer.cancel(); write.close(); } catch (SpotterException ex) { ex.printStackTrace(); } catch (IOException e){ e.printStackTrace(); } } // Pad out a string to the passed length public static String pad(String str, int len) { StringBuffer sb = new StringBuffer(str); for (int i=str.length(); i < len; i++) { sb.append(" "); } return sb.toString(); } 86 Sistema de Localización en Interiores Basado en Redes WiFi Universidad de Sevilla TimerTask timerTask = new TimerTask(){ public void run(){ try{ BeaconMeasurement m = (BeaconMeasurement) s.getMeasurement(); write.println(m.numberOfReadings() + " APs were seen"); if (m.numberOfReadings() > 0) { write.println(pad("MAC Address", 20) + pad("SSID", 30) + pad("RSSI", 10)); // Iterate through the Vector and print the readings for (int i = 0; i < m.numberOfReadings(); i++) { WiFiReading r = (WiFiReading) m.getReading(i); write.println(pad(r.getId(), 20) + pad(r.getSsid(), 30) + pad("" + r.getRssi(), 10)); } write.println(); } nrep++; } catch (SpotterException ex) { ex.printStackTrace(); } } }; } A.1.2 Interfaz de la aplicación de captura de muestras import java.awt.*; // Clase que nos permite introducir un nombre de fichero, un numero de // medidas y un intervalo de medidas para hacer las mediciones de RSSI. public class Medidor extends Frame { static String fichero = new String ("0"); static int valorX = 0; static int valorZ = 0; TextField dTexto,xTexto,zTexto; public Medidor() { super( "Medidor RSSI" ); // Creamos la barra de menú, los botones de las bases y los // paneles que vamos a utilizar para posicionar los // Componentes MenuBar menub = new MenuBar(); Button Bin = new Button( "Tomar medidas" ); Panel p1 = new Panel(); Panel p2 = new Panel(); Panel p3 = new Panel(); Panel p4 = new Panel(); // Creamos el menú desplegable Menu menu = new Menu( "Aplicación" ); menu.add( new MenuItem( "Salir" ) ); menub.add( menu ); setMenuBar( menub ); // Incorporamos los botones a uno de los paneles p3.setLayout( new FlowLayout() ); p3.add( Bin ); // Creamos los dos campos de texto que vamos a utilizar, uno // para la introducción del número decimal que queremos // convertir y el otro para presentar el número convertido // Y asociamos cada uno de los campos, junto con su etiqueta // explicativa a uno de los paneles Label dEtiq = new Label( " Nombre del fichero:" ); Label xEtiq = new Label( "Número de medidas:" ); Label zEtiq = new Label("Intervalo de medidas:"); 87 Anexo A: Código Fuente José Ramón Fernández Acosta dTexto = new TextField( fichero,7 ); // 7 caracteres como máximo xTexto = new TextField( Integer.toString( valorX ),7 ); zTexto = new TextField( Integer.toString( valorZ ),7); p1.setLayout( new FlowLayout( FlowLayout.LEFT ) ); p2.setLayout( new FlowLayout( FlowLayout.LEFT ) ); p4.setLayout( new FlowLayout( FlowLayout.LEFT ) ); p1.add( dEtiq ); p1.add( dTexto ); p2.add( xEtiq ); p2.add( xTexto ); p4.add( zEtiq ); p4.add( zTexto ); // Incorporamos los paneles a la ventana add( "First",p1 ); add( "Center",p2 ); add( "South",p3 ); add( "After",p4 ); } // Fija el tamaño de la ventana y la presenta en pantalla public void start() { resize( 400,200 ); show(); } // Controlador de eventos, que hace caso solamente al evento de // destrucción de la ventana y a los eventos de los botones. // Efectúa operación de conversión que corresponde al botón que se // pulsa y llama al método que hace aparecer el nuevo valor en // el campo de texto del valor convertido public boolean handleEvent( Event evt ) { if( evt.target instanceof MenuItem ) { if( "Salir".equals( ( (MenuItem)evt.target).getLabel() ) ) { hide(); dispose(); System.exit( 0 ); return false; } return( true ); } else if( evt.target instanceof Button && evt.id == 1001) { String boton = ( (Button)evt.target).getLabel(); // Tomar medidas if( boton.equals( "Tomar medidas" ) ) { fichero = dTexto.getText(); valorX = Integer.parseInt( xTexto.getText() ); valorZ = Integer.parseInt( zTexto.getText() ); actualizaSpotter(); } return( true ); } return false; } public void actualizaSpotter() { new WiFiSpotterExample(fichero, valorX, valorZ); } 88 Sistema de Localización en Interiores Basado en Redes WiFi Universidad de Sevilla public static void main( String args[] ) { Medidor c = new Medidor(); c.start(); } } //--------------------------------------- Final del fichero Convertidor.java 89 Anexo A: Código Fuente José Ramón Fernández Acosta A.2 Cliente de localización A.2.1 Código cliente de localización import import import import import import import org.placelab.core.BeaconMeasurement; org.placelab.core.WiFiReading; org.placelab.spotter.Spotter; org.placelab.spotter.SpotterException; org.placelab.spotter.WiFiSpotter; java.util.Timer; java.util.TimerTask; public class WiFiSpotterCliente { int nrep = 0; private int interval = 200; private Spotter s = new WiFiSpotter(interval); boolean terminado = false; int rssi[]; int auxrssi[]=new int[20]; String mac[] = {"00:0a:52:7a:79:c1", "00:0b:85:80:af:98", "00:0b:85:80:af:9d", "00:0b:85:80:af:9e", "00:0b:85:80:b4:08", "00:0b:85:80:b4:0d", "00:0b:85:80:b4:0f", "00:0b:85:80:bc:58", "00:0b:85:80:bc:5e", "00:0b:85:80:bc:5f", "00:0b:85:80:bd:0e", "00:0b:85:80:bd:0f", "00:0b:85:81:6f:78", "00:0b:85:81:6f:7e", "00:0b:85:81:6f:7f", "00:0b:85:81:7b:68", "00:0b:85:81:7b:6e", "00:0b:85:81:7b:6f", "00:13:f7:7a:44:47", "00:1f:9d:21:fe:b0"}; public WiFiSpotterCliente (int vector[], int num, int inter) { try{ rssi= vector; interval = inter; s.open(); Timer timer = new Timer(); timer.scheduleAtFixedRate (timerTask, 0, interval); while (nrep< num); timer.cancel(); terminado = true; } catch (SpotterException ex) { ex.printStackTrace(); } } //Timer que muestrea las medidas de señal wifi cada intervalo de tiempo //y durante el numero de muestras que se quiere medir TimerTask timerTask = new TimerTask(){ public void run(){ try{ BeaconMeasurement m = (BeaconMeasurement) s.getMeasurement(); if (m.numberOfReadings() > 0) { // Itera a través del vector y muestra las medidas for (int i = 0; i < m.numberOfReadings(); i++) { WiFiReading r = (WiFiReading) m.getReading(i); rellena_vector_rssi(auxrssi, mac, r.getRssi(), r.getId()); } media_vector(rssi, auxrssi); } nrep++; } catch (SpotterException ex) { ex.printStackTrace(); } } }; 90 Sistema de Localización en Interiores Basado en Redes WiFi Universidad de Sevilla private void rellena_vector_rssi(int vectorssi[], String vectormac[], int rssi, String mac){ for (int i=0; i< vectormac.length; i++){ if(vectormac[i].equals(mac)){ vectorssi[i]=rssi; i= vectormac.length; } } } //Halla la media del vector rssi del numero de muestras medido private void media_vector(int vector1[], int vector2[]){ int n; for(int i=0; i<vector1.length; i++){ if(vector1[i]!=0 && vector2[i]!=0){ n=2; } else{ n=1; } vector1[i]=(vector1[i]+vector2[i])/n; } } //funcion que indica que el proceso de recogida de muestras ha terminado public boolean finconex(){ return terminado; } } 91 Anexo A: Código Fuente José Ramón Fernández Acosta A.2.1 Código interfaz cliente // Configurar un cliente que reciba una petición del servidor, envíe // una cadena al servidor y cierre la conexión import java.io.*; import java.net.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Cliente extends JFrame { private private private private private private private JTextField campoIntroducir; JTextArea areaPantalla; ObjectOutputStream salida; ObjectInputStream entrada; ServerSocket cliente; Socket conexion; int contador = 1; WiFiSpotterCliente cliente; int ejemplo[]= new int[20]; // configurar GUI public Cliente() { super( "Cliente" ); Container contenedor = getContentPane(); // crear campoIntroducir y registrar componente de escucha campoIntroducir = new JTextField(); campoIntroducir.setEditable( false ); campoIntroducir.addActionListener( new ActionListener() { // enviar mensaje al cliente public void actionPerformed( ActionEvent evento ) { enviarDatos( evento.getActionCommand() ); campoIntroducir.setText( "" ); } } ); contenedor.add( campoIntroducir, BorderLayout.NORTH ); // crear areaPantalla areaPantalla = new JTextArea(); contenedor.add( new JScrollPane( areaPantalla ), BorderLayout.CENTER ); setSize( 300, 150 ); setVisible( true ); } // fin del constructor de Cliente 92 Sistema de Localización en Interiores Basado en Redes WiFi Universidad de Sevilla // configurar y ejecutar el cliente public void ejecutarCliente() { // configurar cliente para que reciba conexiones; procesar las conexiones try { // Paso 1: crear un objeto ServerSocket. cliente = new ServerSocket( 12345, 100 ); while ( true ) { try { esperarConexion();// Paso 2: esperar una conexión obtenerFlujos();// Paso 3: obtener flujos de entrada y salida. procesarConexion(); // Paso 4: procesar la conexión. } // procesar excepción EOFException cuando el servidor cierre la conexión catch ( EOFException excepcionEOF ) { System.err.println( "El servidor terminó conexión" ); } finally { cerrarConexion(); ++contador; } // Paso 5: cerrar la conexión } // fin de instrucción while } // fin del bloque try // procesar problemas con E/S catch ( IOException excepcionES ) { excepcionES.printStackTrace(); } } // fin del método ejecutarCliente // esperar que la conexión llegue, después mostrar información de la conexión private void esperarConexion() throws IOException { mostrarMensaje( "Esperando una conexión\n" ); conexion = cliente.accept(); // permitir al cliente aceptar la conexión mostrarMensaje( "Conexión " + contador + " recibida de: " + conexion.getInetAddress().getHostName() ); } // obtener flujos para enviar y recibir datos private void obtenerFlujos() throws IOException { // establecer flujo de salida para los objetos salida = new ObjectOutputStream( conexion.getOutputStream() ); salida.flush(); // vaciar buffer de salida para enviar información de encabezado // establecer flujo de entrada para los objetos entrada = new ObjectInputStream( conexion.getInputStream() ); mostrarMensaje( "\nSe recibieron los flujos de E/S\n" ); } 93 Anexo A: Código Fuente José Ramón Fernández Acosta // procesar la conexión con el servidor mediante el protocolo de comunicación correspondiente private void procesarConexion() throws IOException { String mensaje; try { mensaje = ( String ) entrada.readObject(); if (!mensaje.equals("CLIENTE>>> LOCALIZACION")){ cerrarConexion(); ++contador; } } catch (ClassNotFoundException e) { e.printStackTrace(); } // enviar mensaje de conexión exitosa al cliente mensaje = "Conexión exitosa"; enviarDatos( mensaje ); cliente = new WiFiSpotterCliente (ejemplo, 3, 500); while(!cliente.finconex()); System.out.println("termino"); for(int i=0; i<20; i++){ enviarDatos( String.valueOf(ejemplo[i]) ); } // habilitar campoIntroducir para que el usuario del servidor pueda enviar mensajes establecerCampoTextoEditable( true ); } // fin del método procesarConexion // cerrar flujos y socket private void cerrarConexion() { mostrarMensaje( "\nFinalizando la conexión\n" ); establecerCampoTextoEditable( false ); // deshabilitar campoIntroducir try { salida.close(); entrada.close(); conexion.close(); } catch( IOException excepcionES ) { excepcionES.printStackTrace(); } } // enviar mensaje al cliente private void enviarDatos( String mensaje ) { // enviar objeto al cliente try { salida.writeObject( mensaje ); salida.flush(); mostrarMensaje( "\n" + mensaje ); } // procesar problemas que pueden ocurrir al enviar el objeto catch ( IOException excepcionES ) { areaPantalla.append( "\nError al escribir objeto" ); } } 94 Sistema de Localización en Interiores Basado en Redes WiFi Universidad de Sevilla // método utilitario que es llamado desde otros subprocesos para manipular // areaPantalla en el subproceso despachador de eventos private void mostrarMensaje( final String mensajeAMostrar ) { // mostrar mensaje del subproceso de ejecución despachador de eventos SwingUtilities.invokeLater( new Runnable() { // clase interna para asegurar que la GUI se actualice apropiadamente public void run() // actualiza areaPantalla { areaPantalla.append( mensajeAMostrar ); areaPantalla.setCaretPosition( areaPantalla.getText().length() ); } } // fin de la clase interna ); // fin de la llamada a SwingUtilities.invokeLater } // método utilitario que es llamado desde otros subprocesos para manipular // campoIntroducir en el subproceso despachador de eventos private void establecerCampoTextoEditable( final boolean editable ) { // mostrar mensaje del subproceso de ejecución despachador de eventos SwingUtilities.invokeLater( new Runnable() { // clase interna para asegurar que la GUI se actualice apropiadamente public void run() // establece la capacidad de modificar campoIntroducir { campoIntroducir.setEditable( editable ); } } // fin de la clase interna ); // fin de la llamada a SwingUtilities.invokeLater } public static void main( String args[] ) { Cliente aplicacion = new Cliente(); aplicacion.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); aplicacion.ejecutarCliente(); } } // fin de la clase Cliente 95 Anexo A: Código Fuente José Ramón Fernández Acosta A.3 Servidor de Localización A.3.1 Código Servidor de localización import import import import import java.sql.Connection; java.sql.DriverManager; java.sql.ResultSet; java.sql.SQLException; java.sql.Statement; class Localizacion { static static static static static String String String String int k= driver = "org.postgresql.Driver"; connectString = "jdbc:postgresql://localhost:5432/postgres"; user = "postgres"; password = "postgres"; 3; //valor de k para el método de los k-vecinos private Localizacion(int vector_rssi[]) { int int int int i=0; j=0; AP=0, LOCS=0; muestra[][]; int dist[]; //vector a rellenar array muestra al vector_rssi String distloc[]; float xloc[] = new float[k]; float yloc[] = new float[k]; float w = 0; //variable para el float xfin=0; //valor final en x float yfin=0; //valor final en y con la distancia de cada vector del peso asignado a los k-vecinos del punto de localización del punto de localización try { Class.forName(driver); } catch (ClassNotFoundException e1) { e1.printStackTrace(); } Connection con; try { con = DriverManager.getConnection(connectString, user , password); Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE); Statement stmt2 = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE); Statement stmt3 = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = stmt.executeQuery("SELECT locname, apmac, avg(rssi) FROM muestras " + "group by locname, apmac order by locname, apmac"); ResultSet rs2= stmt2.executeQuery("SELECT DISTINCT ON (locname) locname FROM muestras"); ResultSet rs3= stmt3.executeQuery("SELECT * FROM macpersan"); AP = numero_aps(rs3); LOCS = localizaciones_posibles(rs2); muestra = new int[LOCS][AP]; dist = new int[LOCS]; distloc = new String[LOCS]; 96 Sistema de Localización en Interiores Basado en Redes WiFi Universidad de Sevilla while(rs.next()){ System.out.println(rs.getString("locname")+" rs.getInt("avg")); } "+ rs.beforeFirst(); while(rs.next()){ rs2.beforeFirst(); i=0; while(rs2.next()){ rs3.beforeFirst(); j=0; while(rs3.next()){ if(rs.getString("apmac").equals(rs3.getString("apmac")) && rs.getString("locname").equals(rs2.getString("locname")) ){ System.out.println(rs.getString("locname")+" "+ rs.getInt("avg") +" "+i+" "+j); muestra[i][j]=rs.getInt("avg"); } j++; } i++; } } rs2.beforeFirst(); i=0; while(rs2.next()){ rs3.beforeFirst(); j=0; while(rs3.next()){ System.out.print(muestra[i][j]+ " j++; } i++; System.out.println(); } "); vector_de_distancia(rs2, rs3, dist, vector_rssi, muestra); vector_de_localizaciones(rs2, distloc); ordena_vectores( dist, distloc); i=0; rs2.beforeFirst(); while(rs2.next()){ System.out.print(dist[i]+ " "); i++; } System.out.println(); i=0; rs2.beforeFirst(); while(rs2.next()){ System.out.print(distloc[i]+ " "); i++; } System.out.println(); rs = stmt.executeQuery("SELECT * FROM persanloc"); for(i=0; i<3; i++){ while(rs.next()){ if(rs.getString("locname").equals(distloc[i])){ xloc[i]=rs.getInt("xloc"); yloc[i]=rs.getInt("yloc"); } 97 Anexo A: Código Fuente José Ramón Fernández Acosta } rs.beforeFirst(); System.out.println(xloc[i]+ " " + yloc[i]); } for(i=0; i<3; i++){ xloc[i]= xloc[i]/dist[i]; yloc[i]= yloc[i]/dist[i]; w += (float) 1/dist[i]; System.out.println(xloc[i] + " " + yloc[i] + " " + w); } for(i=0; i<3; i++){ xfin +=xloc[i]/w; yfin +=yloc[i]/w; } System.out.println(xfin + " " + yfin); stmt.close(); con.close(); locvision ventanita = new locvision(xfin, yfin); } catch (SQLException e) { e.printStackTrace(); } } //devuelve el número de puntos de acceso del sistema private int numero_aps(ResultSet rs){ int i=0; try { while(rs.next()){ i++; } } catch (SQLException e) { e.printStackTrace(); } return i; } //devuelve el número de localizaciones posibles del sistema private int localizaciones_posibles(ResultSet rs){ int i=0; try { while(rs.next()){ i++; } } catch (SQLException e) { e.printStackTrace(); } return i; } //rellena el vector con la id de cada una de las localizaciones private void vector_de_localizaciones(ResultSet rs, String vector[]){ int i=0; try { rs.beforeFirst(); while(rs.next()){ vector[i] = rs.getString("locname"); i++; 98 Sistema de Localización en Interiores Basado en Redes WiFi Universidad de Sevilla } } catch (SQLException e) { e.printStackTrace(); } } //ordena vectores de menor a mayor private void ordena_vectores(int distancia[], String iddistancia[]){ int i=0; int j=0; int pos_min; int tmp; String stmp; for(i=0; i < distancia.length-1 ; i++){ pos_min=i; for(j=i+1; j < distancia.length; j++) if(distancia[j]<distancia[pos_min]) pos_min=j; tmp=distancia[i]; distancia[i]=distancia[pos_min]; distancia[pos_min]=tmp; stmp=iddistancia[i]; iddistancia[i]=iddistancia[pos_min]; iddistancia[pos_min]=stmp; } } //calcula el vector de distancias private void vector_de_distancia(ResultSet rs, ResultSet rs1, int vector[], int vector1[], int vector2[][]){ int i=0,j=0; try { rs.beforeFirst(); while(rs.next()){ j=0; rs1.beforeFirst(); while(rs1.next()){ vector[i] += (vector1[j] - vector2[i][j]) * (vector1[j] vector2[i][j]); j++; } System.out.print(vector[i]+ " "); i++; } System.out.println(); } catch (SQLException e) { e.printStackTrace(); } } public static void main(String args[]){ int Nap=0; int rssi[]; //Esta parte del código es para obtener el número de puntos de acceso //en el sistema para el main del programa. try { Class.forName(driver); } catch (ClassNotFoundException e1) { e1.printStackTrace(); } 99 Anexo A: Código Fuente José Ramón Fernández Acosta Connection con; try { con = DriverManager.getConnection(connectString, user , password); Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs= stmt.executeQuery("SELECT * FROM macpersan"); while(rs.next()){ Nap++; } stmt.close(); con.close(); } catch (SQLException e) { e.printStackTrace(); } rssi= new int[Nap]; Servidor aplicacion; Localizacion algoritmo; aplicacion = new Servidor(Nap); while(!aplicacion.finconex()) aplicacion.rellenavector(rssi); algoritmo = new Localizacion(rssi); } } 100 Sistema de Localización en Interiores Basado en Redes WiFi Universidad de Sevilla A.3.2 Código del servidor import import import import import java.io.*; java.net.*; java.awt.*; java.awt.event.*; javax.swing.*; public class Servidor extends JFrame { private JTextField campoIntroducir; private JTextArea areaPantalla; private ObjectOutputStream salida; private ObjectInputStream entrada; private String mensaje = ""; private String servidor; private Socket servidor; private JButton conectar; boolean terminado = false; int ejemplo[]; int N; public Servidor( /*host*/ int n) { super( "Servidor" ); N=n; ejemplo= new int[N]; Container contenedor = getContentPane(); // crear campoIntroducir y registrar componente de escucha campoIntroducir = new JTextField(); campoIntroducir.setEditable( true ); campoIntroducir.addActionListener( new ActionListener() { // enviar mensaje al servidor public void actionPerformed( ActionEvent evento ) { enviarDatos( evento.getActionCommand() ); campoIntroducir.setText( "" ); } } ); contenedor.add( campoIntroducir, BorderLayout.NORTH ); // crear areaPantalla areaPantalla = new JTextArea(); contenedor.add( new JScrollPane( areaPantalla ), BorderLayout.CENTER ); conectar = new JButton("Conectar"); conectar.addActionListener( new ActionListener() { public void actionPerformed( ActionEvent evento ) { servidor = campoIntroducir.getText(); System.out.println(servidor); ejecutarServidor(); } } ); contenedor.add( conectar, BorderLayout.EAST); setSize( 300, 150 ); setVisible( true ); } // fin del constructor de Servidor 101 Anexo A: Código Fuente José Ramón Fernández Acosta // conectarse al servidor y procesar mensajes del servidor private void ejecutarServidor() { // conectarse al servidor, obtener flujos, procesar la conexión try { conectarAServidor(); // Paso 1: crear un socket para la conexión obtenerFlujos(); // Paso 2: obtener los flujos de entrada y salida procesarConexion(); // Paso 3: procesar la conexión terminado=true; procesar una conexión } //es un semáforo para indicar que se acaba de // el cliente cerró la conexión catch ( EOFException excepcionEOF ) { System.err.println( "El cliente termino la conexión"); } // procesar los problemas que pueden ocurrir al comunicarse con el servidor catch ( IOException excepcionES ) { excepcionES.printStackTrace(); } finally { //cerrarConexion(); // Paso 4: cerrar la conexión } } // fin del método ejecutarServidor // conectarse al servidor private void conectarAServidor() throws IOException { establecerCampoTextoEditable( true ); mostrarMensaje( "Intentando realizar conexión\n" ); // crear Socket para realizar la conexión con el servidor servidor = new Socket( InetAddress.getByName( servidor ), 12345 ); // mostrar la información de la conexión mostrarMensaje( "Conectado a: " + servidor.getInetAddress().getHostName() ); } // obtener flujos para enviar y recibir datos private void obtenerFlujos() throws IOException { // establecer flujo de salida para los objetos salida = new ObjectOutputStream( servidor.getOutputStream() ); salida.flush(); // vaciar buffer de salida para enviar información de encabezado // establecer flujo de entrada para los objetos entrada = new ObjectInputStream( servidor.getInputStream() ); mostrarMensaje( "\nSe recibieron los flujos de E/S\n" ); } 102 Sistema de Localización en Interiores Basado en Redes WiFi Universidad de Sevilla // procesar la conexión con el servidor private void procesarConexion() throws IOException { int i=0; // habilitar campoIntroducir para que el usuario del servidor pueda enviar mensajes establecerCampoTextoEditable( true ); enviarDatos( "LOCALIZACION" ); do { // procesar mensajes enviados del servidor // leer mensaje y mostrarlo en pantalla try { mensaje = ( String ) entrada.readObject(); if(!mensaje.equals("Conexión exitosa")){ ejemplo[i]=Integer.parseInt(mensaje); //System.out.println(ejemplo[i]); i++; } mostrarMensaje( "\n" + mensaje ); } // atrapar los problemas que pueden ocurrir al leer del servidor catch ( ClassNotFoundException excepcionClaseNoEncontrada ) { mostrarMensaje( "\nSe recibió un objeto de tipo desconocido" ); } } while ( i<N ); } // fin del método procesarConexion // cerrar flujos y socket private void cerrarConexion() { mostrarMensaje( "\nCerrando conexión" ); establecerCampoTextoEditable( false ); // deshabilitar campoIntroducir try { salida.close(); entrada.close(); servidor.close(); } catch( IOException excepcionES ) { excepcionES.printStackTrace(); } } // enviar mensaje al servidor private void enviarDatos( String mensaje ) { // enviar objeto al servidor try { salida.writeObject( "CLIENTE>>> " + mensaje ); salida.flush(); mostrarMensaje( "\nCLIENTE>>> " + mensaje ); } // procesar los problemas que pueden ocurrir al enviar el objeto catch ( IOException excepcionES ) { areaPantalla.append( "\nError al escribir el objeto" ); } } 103 Anexo A: Código Fuente José Ramón Fernández Acosta // método utilitario que es llamado desde otros subprocesos para manipular // areaPantalla en el subproceso despachador de eventos private void mostrarMensaje( final String mensajeAMostrar ) { // mostrar mensaje del subproceso de ejecución de la GUI SwingUtilities.invokeLater( new Runnable() { // clase interna para asegurar que la GUI se actualice apropiadamente public void run() // actualiza areaPantalla { areaPantalla.append( mensajeAMostrar ); areaPantalla.setCaretPosition( areaPantalla.getText().length() ); } } // fin de la clase interna ); // fin de la llamada a SwingUtilities.invokeLater } // método utilitario que es llamado desde otros subprocesos para manipular // campoIntroducir en el subproceso despachador de eventos private void establecerCampoTextoEditable( final boolean editable ) { // mostrar mensaje del subproceso de ejecución de la GUI SwingUtilities.invokeLater( new Runnable() { // clase interna para asegurar que la GUI se actualice apropiadamente public void run() // establece la capacidad de modificar campoIntroducir { campoIntroducir.setEditable( editable ); } } // fin de la clase interna ); // fin de la llamada a SwingUtilities.invokeLater } //rellena un vector que se le pasa como referencia public void rellenavector(int [] vectorssi) { for(int i=0;i<N;i++){ vectorssi [i]= ejemplo[i]; } } //devuelve el valor del semáforo definido antes, para saber si ha terminado una conexión public boolean finconex(){ return terminado; } } // fin de la clase Servidor 104 Sistema de Localización en Interiores Basado en Redes WiFi Universidad de Sevilla A.3.3 Código Representación de la localización // Demostración de un mapa de imágenes. import java.awt.*; import javax.swing.*; public class locvision extends JFrame { private JLabel estado; float xmap; float ymap; // establecer componentes de escucha del ratón public locvision(float x, float y) { estado = new JLabel(); MiPanel mipanel = new MiPanel(); getContentPane().add(mipanel); getContentPane().add(estado, BorderLayout.SOUTH); setSize(900,400); setVisible(true); xmap=x; ymap=y; } // fin del método init private class MiPanel extends JPanel { private ImageIcon imagenMapa; public MiPanel() { imagenMapa = new ImageIcon( "bin/oficinas.gif" ); //obtener la imagen } // mostrar imagenMapa public void paint( Graphics g ) { super.paint( g ); imagenMapa.paintIcon( this, g, 0, 0 ); g.drawOval((int) xmap, (int) ymap, 5, 5 ); } // devolver leyenda del tip correspondiente, con base en las coordenadas del ratón } } // fin de la clase MapaImagenes 105 Anexo A: Código Fuente José Ramón Fernández Acosta A.4 Código aplicación cambio de formato de ficheros #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { struct nodo{ char mac[20]; char ssid[20]; int rssi; struct nodo *sig; }; typedef struct nodo NODO; char c[50]; int i; int n; int ap=0; int apaux=0; int muest=0; FILE *fp = NULL; FILE *fout = NULL; NODO *ptr = NULL; NODO *ptraux = NULL; NODO *ptraux2= NULL; NODO *pmac = NULL; fp = fopen(argv[1], "r"); fout = fopen(argv[2], "w+"); ptr = (NODO*) malloc ( 1000*sizeof(NODO) ); ptraux = ptr; /*reservamos espacio para*/ /*1000 estructuras de nodo*/ if(argc != 3){ printf("a.exe archivo-ent archivo-sal\n"); exit(1); } /* En esta primera funcion realizamos la entrada de datos del archivo en */ /* el formato especificado a las listas creadas */ while ( (n=fscanf(fp, "%i", &ap)) != EOF ) { fgets(c, 128, fp); fgets(c, 128, fp); while (apaux < ap) { fscanf(fp, "%s", c); i=0; while(c[i] != ' ') { ptraux->mac[i] = c[i]; i++; } fscanf(fp, "%s", c); i=0; while(c[i] != ' ') { ptraux->ssid[i] = c[i]; i++; } ptraux->rssi = atoi(c); if(ptraux->rssi >=0 ) { fscanf(fp, "%i", &i); 106 Sistema de Localización en Interiores Basado en Redes WiFi Universidad de Sevilla ptraux->rssi = i; } ptraux->sig = ptraux+1; fgets(c, 128, fp); apaux++; ptraux++; } fgets(c, 128, fp); apaux=0; } fclose(fp); /*En esta segunda funcion vamos a ordenar las */ ptraux->sig = NULL; /*listas en grupos referenciados por la mac*/ ptraux=ptr; pmac=ptr; while (pmac->sig != NULL) { while (ptraux->sig != NULL) { if ( (!strcmp( pmac->mac, ptraux->mac )) && (ptraux != pmac)) { ptraux2->sig= ptraux->sig; ptraux->sig=pmac->sig; pmac->sig=ptraux; pmac=pmac->sig; } ptraux2=ptraux; ptraux=ptraux->sig; } pmac=pmac->sig; ptraux=pmac; } fp = fopen(argv[2], "w+"); /*En esta tercera funcion imprimimos en el */ pmac=ptr; /*fichero de salida las listas en el formato*/ ptraux=pmac; /*de salida especificado*/ while(ptraux->sig != NULL) { i=0; while( argv[1][i] != '.') { fprintf(fout, "%c", argv[1][i]); i++; } fprintf(fout, muest++; fprintf(fout, fprintf(fout, fprintf(fout, "\t"); "%i\t", muest); "%s\t", ptraux->mac); "%i\n", ptraux->rssi); if ( strcmp( ptraux->mac, ptraux->sig->mac ) ){ muest=0; } ptraux = ptraux->sig; } fclose(fout); free(ptr); ptr=ptraux=ptraux2=pmac=NULL; return 0; } 107 Anexo A: Código Fuente José Ramón Fernández Acosta A.5 Script de automatización de creación de la base de datos A.5.1 Código SQL de creación de tablas DROP TABLE muestras; DROP TABLE persanloc; DROP TABLE macpersan; -- Table: persanloc CREATE TABLE persanloc ( locname character varying(10) NOT NULL, xloc integer NOT NULL, yloc integer NOT NULL, zloc integer, sala character varying(20), descripcion character varying(30), CONSTRAINT persanloc_pkey PRIMARY KEY (locname) ); -- Table: macpersan CREATE TABLE macpersan ( apname character varying(10) NOT NULL, apmac character varying(20) NOT NULL, apmac1 character varying(20) NOT NULL, apmac2 character varying(20) NOT NULL, apmac3 character varying(20) NOT NULL, xloc integer, yloc integer, zloc integer, CONSTRAINT macpersan_pkey PRIMARY KEY (apmac, apname), CONSTRAINT macpersan_apmac_key UNIQUE (apmac), CONSTRAINT macpersan_apmac_key1 UNIQUE (apmac) ); -- Table: muestras CREATE TABLE muestras ( locname character varying(10) NOT NULL, muestra integer NOT NULL, apmac character varying(20) NOT NULL, rssi integer NOT NULL, CONSTRAINT muestras_pkey PRIMARY KEY (locname, apmac, muestra), CONSTRAINT muestras_locname_fkey FOREIGN KEY (locname) REFERENCES persanloc (locname) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION ); copy persanloc from '/persan/persanloc.txt'; copy macpersan (apname, apmac, apmac1, apmac2, apmac3) from '/persan/macpersan.txt'; copy muestras from '/persan/muestras.txt'; 108 Sistema de Localización en Interiores Basado en Redes WiFi Universidad de Sevilla A.5.2 Código Batch para la automatización de la creación de la base de datos @echo off SET PATH=c:\CYGNUS\CYGWIN~1\H-I586~1\BIN;%PATH% mkdir operaciones cd operaciones copy ..\*.txt echo ******************************************** echo *** Adaptación del formato de ficheros *** echo ******************************************** REM REM REM REM REM **************************************************** bucle para pasar todos los archivos de muestras al formato correcto mediante la llamada al programa de adaptación de formato **************************************************** for %%X in (*.txt) do ..\formato %%X %%X.sal REM REM REM REM **************************************************** copia todos los archivos generados a un solo archivo usando el parámetro /b **************************************************** copy /b *.sal salida.txt move salida.txt ..\muestras.txt cd.. rmdir /s /q operaciones echo echo echo echo REM REM REM REM REM REM ******************************************** *** Creación de la base de datos *** *** tablas y datos *** ******************************************** **************************************************** el siguiente comando tendremos que cambiarlo por la ruta de la carpeta bin de postgresql o establecerla como variable del sistema y borrar el siguiente comando **************************************************** set path=C:\Program Files\PostgreSQL\8.3\bin set PGPASSWORD=postgres psql -U postgres -c "CREATE DATABASE bd_muestras;"< creabd.sql REM el siguiente comando evita que postgresql me pida la contraseña y se pare el script set PGPASSWORD=postgres psql -U postgres -d bd_muestras < creabd.sql pause 109