package components.commchannel;
import java.util.Enumeration;
import java.util.Hashtable;
import utils.Semaphore;
import utils.defines.Defines;
import utils.tracer.TraceState;
import utils.tracer.Traceable;
import components.Component;
import components.features.Feature;
/**
* Esta clase implementa un canal de comunicaciones entre el <i>core</i>
* del robot, y sus componentes perif�ricos (sensores, motores, etc). Una
* vez creada una instancia <code>CommunicationChannel</code>, el canal
* deber� abrirse invocando a <code>open</code> antes de poder ser utilizado.
* De igual forma, el canal deber� ser cerrado mediante <code>close</code>,
* para permitirle la liberaci�n de recursos tomados. <br><br>
*
* El robot accede a sus <i>features</i> a trav�s del canal de comunicaciones.
* Mediante el m�todo <code>receive</code>, obtiene los valores actuales,
* mientras que el m�todo <code>send</code> le permite enviar datos a los
* <i>features</i> (por ejemplo, a los motores para controlar el avance) de
* acuerdo a un protocolo prestablecido. <br><br>
*
* Un canal de comunicaciones se caracteriza por un nombre, una descripci�n,
* y una instancia <code>Robot</code> asociada. <br><br>
*
* Esta clase no puede ser instanciada (necesariamente, deber� extenderse).
*/
public abstract class CommunicationChannel extends Component implements Runnable, Traceable
{
// Constantes
public static final String FRONT_SENSOR_NAME = "FRONT_SENSOR";
public static final String LEFT_SENSOR_NAME = "LEFT_SENSOR";
public static final String RIGHT_SENSOR_NAME = "RIGHT_SENSOR";
public static final String COLOR_SENSOR_NAME = "COLOR_SENSOR";
private Semaphore commChannelSemaphore;
private boolean closed;
private Thread thread;
protected CommunicationChannelState features;
/**
* Construye un nuevo canal de comunicaciones con nombre y descripci�n
* nulos, y no asociado a ning�n robot.
*/
public CommunicationChannel()
{
super();
this.thread = null;
this.closed = true;
this.features = new CommunicationChannelState();
this.features.featuresHash = new Hashtable(11);
this.commChannelSemaphore = null;
}
/**
* Construye un nuevo canal de comunicaciones con nombre <code>name</code>,
* descripci�n <code>description</code>, y asociado al robot
* <code>robot</code>.
* @param name nombre.
* @param description descripci�n.
*/
public CommunicationChannel(String name, String description)
{
super(name, description);
this.thread = null;
this.closed = true;
this.features = new CommunicationChannelState();
this.features.featuresHash = new Hashtable(11);
this.commChannelSemaphore = null;
}
/**
* Establece el sem�foro de sincronismo entre este canal y su robot
* asociado.
* @param sem sem�foro de sincronismo.
*/
public final void setCommChannelSemaphore(Semaphore sem)
{
commChannelSemaphore = sem;
}
/**
* Retorna una referencia al sem�foro de sincronismo entre este canal
* y su robot asociado.
* @return sem�foro de sincronismo.
*/
public final Semaphore getCommChannelSemaphore()
{
return commChannelSemaphore;
}
/**
* Abre el canal de comunicaciones. Este m�todo debe ser invocado antes
* de enviar o recibir datos a trav�s del mismo.
* @return <code>OK</code> si se pudo abrir con �xito, o <code>ERROR</code>
* en caso contrario.
*/
public int open(String connectionString)
{
if ( !closed )
// Ya est� abierto
return Defines.ERROR;
// Crea el thread y lo lanza
thread = new Thread( this );
thread.start();
closed = false;
return Defines.OK;
}
/**
* Cierra el canal de comunicaciones. Este m�todo debe ser invocado cuando
* el canal ya no est� en uso, para permitirle liberar recursos tomados.
* @return <code>OK</code> si se pudo cerrar con �xito, o <code>ERROR</code>
* en caso contrario.
*/
public int close()
{
closed = true;
return Defines.OK;
}
/**
* Determina si el canal est� abierto.
* @return <code>true</code> si el canal est� abierto, o <code>false</code>
* en caso contrario.
*/
public final boolean isClosed()
{
return closed;
}
/**
* Retorna los �ltimos valores le�dos, por el canal, desde los <i>features
* </i> del robot (sensores, motores, etc.).
* Estos valores se mantienen en un <i>buffer</i> interno del canal de
* comunicaciones, y se retornan como una instancia <code>Hashtable</code>.
* Para extraer los datos desde este hash, deber�n utilizarse los nombres
* definidos como constantes (
* {@link #FRONT_SENSOR_NAME FRONT_SENSOR_NAME},
* {@link #LEFT_SENSOR_NAME LEFT_SENSOR_NAME},
* {@link #RIGHT_SENSOR_NAME RIGHT_SENSOR_NAME},
* {@link #COLOR_SENSOR_NAME COLOR_SENSOR_NAME}, etc).
* @return instancia <code>Hashtable</code> con los valores de los
* <i>features</i>.
*/
public abstract Hashtable receive();
/**
* Env�a un mensaje que, de acuerdo a un protocolo prestablecido, permite
* establecer valores en los <i>features</i> que conforman el robot (por
* ejemplo, control de motores).
* @param msg valores a establecer seg�n el protocolo prestablecido.
*/
public abstract void send(String msg);
/**
* Verifica el funcionamiento del canal de comunicaciones.
* @return <code>true</code> si el canal funciona correctamente, o
* <code>false</code> en caso contrario.
*/
public abstract boolean test();
/**
* Registra el objeto <code>feature</code> para que el canal
* pueda actualizarlo cuando recibe nuevos valores desde el robot.
* @param feature <code>feature</code> a registrar.
* @throws CommunicationChannelException si el <code>feature</code> ya
* fue registrado anteriormente.
*/
public final void registerFeature(Feature feature) throws CommunicationChannelException
{
if ( features.featuresHash.containsKey(feature.getName()) )
throw new CommunicationChannelException("El objeto " +
feature.getName() +
" ya fue registrado!");
features.featuresHash.put(feature.getName(), feature);
}
public synchronized void setCommunicationChannelState(TraceState state)
{
CommunicationChannelState commState = (CommunicationChannelState)state;
if ( commState == null || commState.featuresHash == null )
return;
if ( features != null && features.featuresHash != null )
{
for (Enumeration e = commState.featuresHash.keys(); e.hasMoreElements(); )
{
String featureName = (String)e.nextElement();
Feature feature = (Feature)commState.featuresHash.get( featureName );
Object value = feature.getValue();
feature = (Feature)features.featuresHash.get( featureName );
if ( feature != null )
feature.setValue( value );
}
}
}
public synchronized TraceState getTraceableState()
{
return (TraceState)features.clone();
}
public void dispose()
{
if ( !isClosed() )
close();
}
public boolean isDisposed()
{
return isClosed();
}
public void join()
{
try
{
if ( thread != null )
thread.join( 3000 );
}
catch (InterruptedException e)
{ }
}
}