All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.robokind.api.motion.messaging.RemoteRobotHost Maven / Gradle / Ivy

/*
 * Copyright 2011 Hanson Robokind LLC.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.robokind.api.motion.messaging;

import java.util.logging.Level;
import java.util.logging.Logger;
import org.robokind.api.motion.protocol.RobotRequest;
import org.jflux.api.core.Listener;
import org.jflux.api.messaging.rk.MessageAsyncReceiver;
import org.jflux.api.messaging.rk.MessageSender;
import org.robokind.api.motion.Joint;
import org.robokind.api.motion.Robot;
import org.robokind.api.motion.Robot.JointId;
import org.robokind.api.motion.Robot.RobotPositionMap;
import org.robokind.api.motion.protocol.RobotResponse;
import org.robokind.api.motion.protocol.RobotResponse.RobotResponseHeader;
import org.robokind.api.motion.protocol.MotionFrameEvent;
import org.robokind.api.motion.protocol.RobotDefinitionResponse;

/**
 * Hosts a Robot to be controlled by a RemoteRobotClient through some Messaging
 * channel.  Receives RobotRequest Messages and replies with RobotResponse 
 * Messages.
 * 
 * @author Matthew Stevenson 
 */
public class RemoteRobotHost {
    private final static Logger theLogger = 
            Logger.getLogger(RemoteRobotHost.class.getName());
    private Robot myRobot;
    private String mySourceId;
    private String myDestinationId;
    private MessageSender myResponseSender;
    private MessageAsyncReceiver myRequestReceiver;
    private RequestListener myRequestListener;
    private RobotResponseFactory myResponseFactory;
    private MessageAsyncReceiver myMotionFrameReceiver;
    private Listener myMoveHandler;
    /**
     * Creates a new RemoteRobotHost to host the given Robot.
     * @param robot Robot to host
     * @param sourceId arbitrary String identifying this host
     * @param destinationId arbitrary String identifying a client
     * @param sender MessageSender to send RobotResponses
     * @param receiver MessageReceiver to receive RobotRequests from a client
     * @param factory factory for creating new RobotResponse Messages
     * @param motionFrameReceiver MessageReceiver to receive MotionFrameEvents
     * @param moveHandler Listener to handle MotionFrameEvents from clients
     */
    public RemoteRobotHost(Robot robot, 
            String sourceId, String destinationId, 
            MessageSender sender, 
            MessageAsyncReceiver receiver, 
            RobotResponseFactory factory, 
            MessageAsyncReceiver motionFrameReceiver, 
            Listener moveHandler){
        this(sourceId, destinationId);
        initialize(robot, sender, receiver, 
                factory, motionFrameReceiver, moveHandler);
    }
    /**
     * Creates an empty RemoteRobotHost.
     * @param sourceId arbitrary String identifying this host
     * @param destinationId arbitrary String identifying a client
     */
    protected RemoteRobotHost(String sourceId, String destinationId){
        if(sourceId == null || destinationId == null){
            throw new NullPointerException();
        }
        mySourceId = sourceId;
        myDestinationId = destinationId;
        myRequestListener = new RequestListener();
        theLogger.log(Level.INFO, 
                "Creating Remote Robot.  sourceId={0}, destId={1}", 
                new Object[]{mySourceId, myDestinationId});
    }
    
    private void initialize(
            Robot robot, 
            MessageSender sender, 
            MessageAsyncReceiver receiver, 
            RobotResponseFactory factory, 
            MessageAsyncReceiver motionFrameReceiver, 
            Listener moveHandler){
        if(myRequestReceiver != null && myRequestListener != null){
            myRequestReceiver.removeListener(myRequestListener);
        }if(myMotionFrameReceiver != null && myMoveHandler != null){
            myMotionFrameReceiver.removeListener(myMoveHandler);
        }
        myRobot = robot;
        myResponseSender = sender;
        myRequestReceiver = receiver;
        myResponseFactory = factory;
        myMotionFrameReceiver = motionFrameReceiver;
        myMoveHandler = moveHandler;
        if(myRequestReceiver != null){
            myRequestReceiver.addListener(myRequestListener);
        }
        if(myMotionFrameReceiver != null){
            myMotionFrameReceiver.addListener(myMoveHandler);
        }       
        theLogger.log(Level.INFO, 
                "Initializing Remote Robot.  sourceId={0}, destId={1}, robotId={2}", 
                new Object[]{mySourceId, myDestinationId, myRobot.getRobotId()}); 
    }
    /**
     * Sets the Robot to host.
     * @param robot Robot to host
     */
    public void setRobot(Robot robot){
        myRobot = robot;
    }
    /**
     * Sets the MessageSender to send RobotResponses.
     * @param sender MEssageSender to use
     */
    public void setResponseSender(MessageSender sender){
        myResponseSender = sender;
    }
    
    public MessageSender getResponseSender(){
        return myResponseSender;
    }
    /**
     * Sets the MessageReceiver to receive RobotRequests.
     * @param receiver MessageReceiver to use
     */
    public void setRequestReceiver(
            MessageAsyncReceiver receiver){
        if(myRequestReceiver != null && myRequestListener != null){
            myRequestReceiver.removeListener(myRequestListener);
        }
        myRequestReceiver = receiver;
        if(myRequestReceiver != null && myRequestListener != null){
            myRequestReceiver.addListener(myRequestListener);
        }
    }
    /**
     * Sets the factory to use for creating new RobotResponse Messages.
     * @param factory factory to use for creating new RobotResponse Messages
     */
    public void setResponseFactory(RobotResponseFactory factory){
        myResponseFactory = factory;
    }
    /**
     * Sets the MessageReceiver to receive MotionFrames
     * @param receiver MessageReceiver to use
     */
    public void setMotionFrameReceiver(
            MessageAsyncReceiver receiver){
        if(myMotionFrameReceiver != null && myMoveHandler != null){
            myMotionFrameReceiver.removeListener(myMoveHandler);
        }
        myMotionFrameReceiver = receiver;
        if(myMotionFrameReceiver != null && myMoveHandler != null){
            myMotionFrameReceiver.addListener(myMoveHandler);
        }
    }
    /**
     * Sets the Listener to handle MotionFrames from clients.
     * @param moveHandler Listener to handle MotionFrames from clients
     */
    public void setMoveHandler(Listener moveHandler){
        if(myMotionFrameReceiver != null && myMoveHandler != null){
            myMotionFrameReceiver.removeListener(myMoveHandler);
        }
        myMoveHandler = moveHandler;
        if(myMotionFrameReceiver != null && myMoveHandler != null){
            myMotionFrameReceiver.addListener(myMoveHandler);
        }
    }
    /**
     * Returns the hosted Robot's id.
     * @return hosted Robot's id
     */
    public Robot.Id getRobotId(){
        if(myRobot == null){
            return null;
        }
        return myRobot.getRobotId();
    }
    /**
     * Returns a String identifying this host.  Currently unused.
     * @return String identifying this host
     */
    public String getSourceId(){
        return mySourceId;
    }
    /**
     * Returns a String identifying a client.  Currently unused.
     * @return String identifying a client
     */
    public String getDestinationId(){
        return myDestinationId;
    }
    
    public Robot getRobot(){
        return myRobot;
    }
    
    /**
     * Creates and sends a RobotDefinitionResponse.
     * @param req RobotRequest the host is responding to
     */
    protected void handleDefinitionRequest(RobotRequest req){
        sendDefinitionResponse(req);
    }
    /**
     * Calls connect() on the hosted Robot.  The return value from
     * that call is returned in a RobotStatusResponse.
     * @param req RobotRequest the host is responding to
     */
    protected void handleConnectRequest(RobotRequest req){
        sendStatusResponse(req, getRobot().connect());
    }
    /**
     * Calls disconnect() on the hosted Robot.  The return value 
     * from that call is returned in a RobotStatusResponse.
     * @param req RobotRequest the host is responding to
     */
    protected void handleDisconnectRequest(RobotRequest req){
        getRobot().disconnect();
        sendStatusResponse(req, true);
    }
    /**
     * Creates and sends a RobotStatusResponse with the Robot's connection
     * status
     * @param req RobotRequest the host is responding to
     */
    protected void handleConnectionStatusRequest(RobotRequest req){
        sendStatusResponse(req, getRobot().isConnected());
    }
    /**
     * Calls setEnabled(true) on the hosted Robot.  Sends a
     * successful RobotStatusResponse.
     * @param req RobotRequest the host is responding to
     */
    protected void handleEnableRequest(RobotRequest req){
        getRobot().setEnabled(true);
        sendStatusResponse(req, true);
    }
    /**
     * Calls setEnabled(false) on the hosted Robot.  Sends a
     * successful RobotStatusResponse.
     * @param req RobotRequest the host is responding to
     */
    protected void handleDisableRequest(RobotRequest req){
        getRobot().setEnabled(false);
        sendStatusResponse(req, true);
    }
    /**
     * Creates and sends a RobotStatusResponse with the Robot's enabled status
     * @param req RobotRequest the host is responding to
     */
    protected void handleEnabledStatusRequest(RobotRequest req){
        sendStatusResponse(req, getRobot().isEnabled());
    }
    /**
     * Calls setEnabled(true) on the hosted Robot's Joint.  Sends a
     * successful RobotStatusResponse.
     * @param req RobotRequest the host is responding to
     */
    protected void handleEnableRequestForJoint(RobotRequest req){
        getRequestedJoint(req).setEnabled(true);
        sendStatusResponse(req, true);
    }
    /**
     * Calls setEnabled(true) on the hosted Robot's Joint.  Sends a
     * successful RobotStatusResponse.
     * @param req RobotRequest the host is responding to
     */
    protected void handleDisableRequestForJoint(RobotRequest req){
        getRequestedJoint(req).setEnabled(false);
        sendStatusResponse(req, true);
    }
    /**
     * Creates and sends a RobotStatusResponse with the Joint's connection
     * status
     * @param req RobotRequest the host is responding to
     */
    protected void handleEnabledStatusRequestForJoint(RobotRequest req){
        sendStatusResponse(req, getRequestedJoint(req).getEnabled());
    }
    /**
     * Retrieves the Joint specified in the RobotRequest.
     * @param req RobotRequest specifying a Joint
     * @return Joint specified in the RobotRequest
     */
    protected Joint getRequestedJoint(RobotRequest req){
        Integer jIdInt = req.getRequestIndex();
        if(jIdInt == null){
            throw new NullPointerException();
        }
        Joint.Id jId = new Joint.Id(jIdInt);
        Robot.Id rId = req.getRobotId();
        JointId jointId = new Robot.JointId(rId, jId);
        Joint j = getRobot().getJoint(jointId);
        if(j == null){
            throw new NullPointerException();
        }
        return j;
    }
    
    /**
     * Sends a RobotPositionResponse with the Robot's default positions.
     * @param req RobotRequest the host is responding to
     */
    protected void handleDefaultPositionRequest(RobotRequest req){
        sendPositionResponse(req, getRobot().getDefaultPositions());
    }
    /**
     * Sends a RobotPositionResponse with the Robot's goal positions.
     * @param req RobotRequest the host is responding to
     */
    protected void handleGoalPositionRequest(RobotRequest req){
        sendPositionResponse(req, getRobot().getGoalPositions());
    }
    /**
     * Sends a RobotPositionResponse with the Robot's current positions.
     * @param req RobotRequest the host is responding to
     */
    protected void handleCurrentPositionRequest(RobotRequest req){
        sendPositionResponse(req, getRobot().getCurrentPositions());
    }
    
    private void sendDefinitionResponse(RobotRequest req){
        theLogger.log(Level.INFO, 
                "Sending Definition Response."
                + "  Request Timestamp: {0}, Type: {1}, Source: {2}, Dest: {3}, Robot: {4}.", 
                new Object[]{req.getTimestampMillisecUTC(), req.getRequestType(), 
                    req.getSourceId(), req.getDestinationId(), req.getRobotId()});
        if(myResponseSender == null){
        theLogger.log(Level.INFO, 
                "Unable to send Definition Response, missing ResponseSender."
                + "  Request Timestamp: {0}, Type: {1}, Source: {2}, Dest: {3}, Robot: {4}.", 
                new Object[]{req.getTimestampMillisecUTC(), req.getRequestType(), 
                    req.getSourceId(), req.getDestinationId(), req.getRobotId()});
            return;
        }
        RobotResponseHeader header = getHeader(req);
        Robot robot = getRobot();
        
        theLogger.log(Level.INFO, 
                "Creating Definition Response."
                + "  Request Timestamp: {0}, Type: {1}, Source: {2}, Dest: {3}, Robot: {4}."
                + "  Using Header: {5}, Robot: {6}", 
                new Object[]{req.getTimestampMillisecUTC(), req.getRequestType(), 
                    req.getSourceId(), req.getDestinationId(), req.getRobotId(),
                    header, robot});
        RobotDefinitionResponse def = 
                myResponseFactory.createDefinitionResponse(header, robot);
        myResponseSender.notifyListeners(def);
        theLogger.log(Level.INFO, 
                "Definition Response Sent."
                + "  Request Timestamp: {0}, Type: {1}, Source: {2}, Dest: {3}, Robot: {4}.", 
                new Object[]{req.getTimestampMillisecUTC(), req.getRequestType(), 
                    req.getSourceId(), req.getDestinationId(), req.getRobotId()});
    }
    private void sendStatusResponse(RobotRequest req, boolean value){
        if(myResponseSender == null){
            return;
        }
        myResponseSender.notifyListeners(
                myResponseFactory.createStatusResponse(
                    getHeader(req), 
                    value));
    }
    private void sendPositionResponse(
            RobotRequest req, RobotPositionMap positions){
        if(myResponseSender == null){
            return;
        }
        myResponseSender.notifyListeners(
                myResponseFactory.createPositionResponse(
                    getHeader(req), 
                    positions));
    }
    private RobotResponseHeader getHeader(RobotRequest req){
        return myResponseFactory.createHeader(
                getRobotId(), mySourceId, myDestinationId,
                req.getRequestType(), req.getTimestampMillisecUTC());
    }
    
    class RequestListener implements Listener{

        @Override
        public void handleEvent(RobotRequest event) {
            String reqType = event.getRequestType();
            if(reqType == null){
                theLogger.info("Received RobotRequest with null RequestType.");
            }else{
                theLogger.log(Level.INFO, 
                        "Received RobotRequest with RequestType: {0}.", reqType);
            }
            if(reqType.equals(RobotRequest.CMD_GET_ROBOT_DEFINITION)){
                handleDefinitionRequest(event);
            }else if(reqType.equals(RobotRequest.CMD_CONNECT_ROBOT)){
                handleConnectRequest(event);
            }else if(reqType.equals(RobotRequest.CMD_DISCONNECT_ROBOT)){
                handleDisconnectRequest(event);
            }else if(reqType.equals(RobotRequest.CMD_GET_CONNECTION_STATUS)){
                handleConnectionStatusRequest(event);
            }else if(reqType.equals(RobotRequest.CMD_ENABLE_ROBOT)){
                handleEnableRequest(event);
            }else if(reqType.equals(RobotRequest.CMD_DISABLE_ROBOT)){
                handleDisableRequest(event);
            }else if(reqType.equals(RobotRequest.CMD_GET_ENABLED_STATUS)){
                handleEnabledStatusRequest(event);
            }else if(reqType.equals(RobotRequest.CMD_GET_DEFAULT_POSITIONS)){
                handleDefaultPositionRequest(event);
            }else if(reqType.equals(RobotRequest.CMD_GET_GOAL_POSITIONS)){
                handleGoalPositionRequest(event);
            }else if(reqType.equals(RobotRequest.CMD_GET_CURRENT_POSITIONS)){
                handleGoalPositionRequest(event);
            }else if(reqType.equals(RobotRequest.CMD_ENABLE_JOINT)){
                handleEnableRequestForJoint(event);
            }else if(reqType.equals(RobotRequest.CMD_DISABLE_JOINT)){
                handleDisableRequestForJoint(event);
            }else if(reqType.equals(RobotRequest.CMD_GET_JOINT_ENABLED_STATUS)){
                handleEnabledStatusRequestForJoint(event);
            }else{
                theLogger.log(Level.WARNING, 
                        "Received unknown request type: {0}", reqType);
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy