Subversion Repositories Code-Repo

Rev

Blame | Last modification | View Log | RSS feed

/**************************************************************************
 * Copyright 2011 Jules White
 *
 * 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 ioio.debugger.server;

import ioio.debugger.server.NetworkIOIOProtocol.Message;
import ioio.debugger.server.NetworkIOIOProtocol.Message.Builder;
import ioio.debugger.server.NetworkIOIOProtocol.TrackingMessage;

import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelEvent;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import org.jboss.netty.channel.group.ChannelGroup;
import org.jboss.netty.channel.group.DefaultChannelGroup;

public class IOIODebuggerServerHandler extends SimpleChannelUpstreamHandler {

        private static final Logger logger = Logger.getLogger(IOIODebuggerServerHandler.class.getName());

        static final ChannelGroup channels = new DefaultChannelGroup();

        private ServerHelper helperClass;
        private boolean clientConnected;
        
        public void setServerHelper(ServerHelper helper) {
                helperClass = helper;
        }
        
        @Override
        public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e)
                        throws Exception {
                if (e instanceof ChannelStateEvent) {
                        logger.info(e.toString());
                }
                super.handleUpstream(ctx, e);
        }

        public void broadcast(TrackingMessage msg) {
                for (Channel c : channels) {
                        c.write(msg);
                }
        }
        
        @Override
        public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e)
                        throws Exception {

                channels.add(e.getChannel());
        }

        @Override
        public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
                // Unregister the channel from the global channel list
                // so the channel does not receive messages anymore.
                channels.remove(e.getChannel());
                clientConnected = false;
        }

        @Override
        public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
                
                TrackingMessage tmsg = (TrackingMessage) e.getMessage();
                
                List<Message> msgList;
                // Handle each message depending on the type
                switch (tmsg.getType()) {
                case 10:
                        // If there are no clients connected, reply with an ok reponse
                        if (!clientConnected) {
                                System.out.println("No clients currently connected, allowing connection");
                                clientConnected = true;
                                TrackingMessage newMsg = TrackingMessage.newBuilder()
                                        .setId(0)
                                        .setType(11)
                                        .build();
                                e.getChannel().write(newMsg);
                        // Otherwise reply with an error response
                        } else {
                                System.out.println("Client currently connected, rejecting connection");
                                TrackingMessage newMsg = TrackingMessage.newBuilder()
                                        .setId(0)
                                        .setType(12)
                                        .build();
                                e.getChannel().write(newMsg);
                        }
                        break;
                case 50:
                        msgList = tmsg.getMessageList();
                        for (Message msg : msgList) {
                                if (msg.getType().compareTo("InAnalog") == 0) {
                                        helperClass.AddNewAnalogIn(msg.getPin(), msg.getFreq());
                                } else if (msg.getType().compareTo("InDigital") == 0) {
                                        helperClass.AddNewDigitalIn(msg.getPin(), msg.getFreq(), msg.getMode());
                                } else if (msg.getType().compareTo("OutDigital") == 0) {
                                        helperClass.AddNewDigitalOut(msg.getPin(), msg.getState(), msg.getBoolean());
                                }
                        }
                        break;
                case 51:
                        msgList = tmsg.getMessageList();
                        for (Message msg : msgList) {
                                helperClass.StopPin(msg.getPin());
                        }
                        break;
                case 52:
                        msgList = tmsg.getMessageList();
                        for (Message msg : msgList) {
                                helperClass.RemovePin(msg.getPin());
                        }
                        break;
                case 70:
                        msgList = tmsg.getMessageList();
                        for (Message msg : msgList) {
                                List<Double> dataList = msg.getDataList();
                                helperClass.DataRecieved(msg.getPin(), dataList);
                        }
                        break;
                }
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
                logger.log(Level.WARNING, "Unexpected exception from downstream.",
                                e.getCause());
                e.getChannel().close();
        }
        
        /** Queries if clients are currently connected to the server
         * 
         *  @return true if there are clients connected, false otherwise
         *  */
        public boolean areClientsConnected() {
                return clientConnected;
        }
        
        /** Sends a command to the client to add a new analog input 
         * 
         * @param pin - Pin number to add
         * @param freq - Frequency that pin should update
         */
        public void sendAddNewAnalogIn(int pin, long freq) {
                System.out.println("Sending command to add new analog input  Pin: " + pin + "  Freq: " + freq);
                Builder message = Message.newBuilder()
                                .setPin(pin)
                                .setFreq(freq)
                                .setType("InAnalog");
                
                TrackingMessage newMsg = TrackingMessage.newBuilder()
                                .setId(0)
                                .setType(50)
                                .addMessage(message)
                                .build();
                
                broadcast(newMsg);
        }
        
        /** Sends a command to the client to add a new digital input 
         * 
         * @param pin - Pin number to add
         * @param freq - Frequency that pin should update
         * @param mode - Mode that pin should be started in [Float/Pull Up/Pull Down]
         */
        public void sendAddNewDigitalIn(int pin, long freq, String mode) {
                System.out.println("Sending command to add new digital input  Pin: " + pin + "  Freq: " + freq +  "Mode: " + mode);
                Builder message = Message.newBuilder()
                                .setPin(pin)
                                .setFreq(freq)
                                .setMode(mode)
                                .setType("InDigital");
                
                TrackingMessage newMsg = TrackingMessage.newBuilder()
                                .setId(0)
                                .setType(50)
                                .addMessage(message)
                                .build();
                
                broadcast(newMsg);
        }
        
        /** Sends a command to the client to add a new digital output 
         * 
         * @param pin - Pin number to add
         * @param state - Initial state of pin [Low/High]
         * @param openDrain - Option to start pin in open drain mode [true if yes, false if no]
         */
        public void sendAddNewDigitalOut(int pin, String state, boolean openDrain) {
                System.out.println("Sending command to add new analog input  Pin: " + pin + "  InitialState: " + state + "  OpenDrainMode: " + openDrain);
                Builder message = Message.newBuilder()
                                .setPin(pin)
                                .setState(state)
                                .setBoolean(openDrain)
                                .setType("OutDigital");
                
                TrackingMessage newMsg = TrackingMessage.newBuilder()
                                .setId(0)
                                .setType(50)
                                .addMessage(message)
                                .build();
                
                broadcast(newMsg);
        }
        
        /** Sends a command to the client to execute a hard reset */
        public void sendHardReset() {
                TrackingMessage newMsg = TrackingMessage.newBuilder()
                                .setId(0)
                                .setType(13)
                                .build();
                broadcast(newMsg);
        }
}