com.thesmartguild.firmloader.app.LoaderUserDisplay.java Source code

Java tutorial

Introduction

Here is the source code for com.thesmartguild.firmloader.app.LoaderUserDisplay.java

Source

/*
 *    FirmwareInstaller - Used to install firmware on embedded devices including wireless routers.
 *    Copyright (C) 2015 The Smart Guild LLC
 *    http://www.thesmartguild.com
 *    Author: Brian O'Connell brianjoc@gmail.com
 *
 *    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, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    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 com.thesmartguild.firmloader.app;

import gnu.io.NoSuchPortException;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.LayoutManager;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Iterator;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.ExecutionException;

import javax.swing.ButtonGroup;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.TransferHandler;
import javax.swing.UIManager;
import javax.swing.event.MenuEvent;
import javax.swing.event.MenuListener;
import javax.swing.text.DefaultCaret;

import org.apache.commons.codec.binary.Hex;

import com.thesmartguild.firmloader.lib.app_comms.DisplayInterface;
import com.thesmartguild.firmloader.lib.tftp.TFTPServerFactory;
import com.thesmartguild.firmloader.lib.tftp.TFTPServerFactory.ServerInfo;
import com.thesmartguild.firmloader.nativelib.networking.NetworkSettings;
import com.thesmartguild.firmloader.nativelib.networking.NetworkSettingsFactory;

public class LoaderUserDisplay extends JFrame implements DisplayInterface {
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private String initText = "Please Drag and Drop your new Firmware image here";
    private File fImage = null;
    private File md5file;
    private String md5String;
    private DeviceConnectedPanel devConnectedPanel = new DeviceConnectedPanel();
    private Md5Panel md5Panel = new Md5Panel();
    //private JPanel optionsPanel;
    private InstallPanel installPanel = new InstallPanel();
    private JList<File> fileDropper = new JList<File>(new DefaultListModel<File>());
    private TextOutPanel outPanel = new TextOutPanel();
    private LoaderSerialIO serial;
    private NetworkSettings network;
    private ServerInfo serv;
    private Menu menu;
    private String ip = "192.168.1.3";
    JPanel south;
    private boolean originalState = true;

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new LoaderUserDisplay("TEST");
            }
        });

    }

    public LoaderUserDisplay(String title, LoaderSerialIO serial, String ip) {
        super(title);
        this.serial = serial;
        this.ip = ip;

        initialize();
    }

    public LoaderUserDisplay(String title) {
        super(title);
        try {
            this.serial = new LoaderSerialIO(this);
            this.devConnectedPanel.setConnected(true);

            this.devConnectedPanel.addComToTitle(this.serial.getCom());
        } catch (NoSuchPortException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            this.devConnectedPanel.setConnected(false);
        } catch (UnableToConnectPortException e) {
            this.devConnectedPanel.setConnected(false);
        }
        network = NetworkSettingsFactory.createNetworkSettings();
        new TFTPStart().execute();

        initialize();
    }

    private void initialize() {
        Runtime.getRuntime().addShutdownHook(new On_Exit());
        menu = new Menu();
        LayoutManager manager = new BorderLayout();
        this.getContentPane().setLayout(manager);
        this.setJMenuBar(menu);
        this.setTransferHandler(new DragAndDrop());
        this.setResizable(true);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.add(this.devConnectedPanel, BorderLayout.NORTH);
        this.add(this.outPanel, BorderLayout.CENTER);
        south = new JPanel();
        south.add(this.md5Panel);
        south.add(this.installPanel);
        this.add(south, BorderLayout.SOUTH);
        this.setSize(700, 500);
        this.setMinimumSize(new Dimension(500, 300));
        this.outPanel.sendText(initText + "\n");
        this.setVisible(true);
    }

    @Override
    public void sendText(String text) {
        outPanel.sendText(text);
    }

    @Override
    public void setDeviceConnected(boolean connected) {
        // TODO Auto-generated method stub

    }

    public void setMD5(File file) {
        try {
            new MD5Calc(file).execute();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    @Override
    public void setMD5(String md5) {
        md5String = md5;
        //this.sendText(md5String+"\n");
        md5Panel.updateMd5(md5);
    }

    @Override
    public File getFile() {
        return fImage;
    }

    private void setFile(File file) {
        if (file.getName().contains("md5") || file.getName().contains("MD5")) {
            this.md5file = file;
            new MD5FileRead(this.fImage, md5file).execute();
        } else {
            this.fImage = file;
            serv.addFile(file);
            setMD5(file);
            if (this.md5file != null) {
                new MD5FileRead(file, md5file).execute();
            } else {
                this.md5Panel.updateMd5Status(Md5Panel.NO_REFRENCE);
            }
        }
    }

    private void reInitSerial(String com) {
        this.devConnectedPanel.addComToTitle(com);
        try {
            if (serial != null) {
                serial.disconnect();
            }
            this.devConnectedPanel.setConnected(false);
            serial = new LoaderSerialIO(this, com);
            this.devConnectedPanel.setConnected(true);
        } catch (NoSuchPortException e) {
            e.printStackTrace();
            System.out.println("Not there");
        }
    }

    private synchronized void install() {
        try {
            new Install(serial, ip, fImage).execute();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    private void afterInstall() {
        this.remove(south);
        this.add(new SendCommands(), BorderLayout.SOUTH);
        this.revalidate();
        this.repaint();
    }

    private class DeviceConnectedPanel extends JPanel {
        /**
         * 
         */
        private static final long serialVersionUID = 5415122402127726488L;
        String labelTitle = "Connection Status";
        private JLabel connectedLabel = new JLabel(labelTitle + ":", JLabel.TRAILING);
        private JRadioButton notConnectedRButton = new JRadioButton();
        private JRadioButton connectedRButton = new JRadioButton();

        public DeviceConnectedPanel() {
            JPanel pan = new JPanel();
            setConnected(false);
            notConnectedRButton.setEnabled(false);
            connectedRButton.setEnabled(false);
            connectedLabel.setLabelFor(pan);
            this.add(connectedLabel);
            pan.add(notConnectedRButton);
            pan.add(connectedRButton);
            this.add(pan);
            pan.setVisible(true);
        }

        public void setConnected(boolean connected) {
            if (connected) {
                connectedRButton.setBackground(Color.GREEN);
                connectedRButton.setSelected(true);
                notConnectedRButton.setBackground(UIManager.getColor("Button.background"));
                notConnectedRButton.setSelected(false);
            } else {
                notConnectedRButton.setBackground(Color.RED);
                notConnectedRButton.setSelected(true);
                connectedRButton.setBackground(UIManager.getColor("Button.background"));
                connectedRButton.setSelected(false);
            }
        }

        public void addComToTitle(String com) {
            connectedLabel.setText(labelTitle + " " + com + ":");
        }
    }

    private class TextOutPanel extends JScrollPane {
        /**
         * 
         */
        private static final long serialVersionUID = -2655348533140734984L;
        private JTextArea out = new JTextArea();
        //JScrollPane pan = new JScrollPane();

        public TextOutPanel() {
            out.setEditable(false);
            out.setLineWrap(true);
            out.setTransferHandler(new DragAndDrop());
            out.setFont(new Font("monospaced", Font.PLAIN, 12));
            DefaultCaret caret = (DefaultCaret) out.getCaret();
            caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
            this.setViewportView(out);
        }

        public void sendText(String text) {
            out.append(text);
        }
    }

    private class Md5Panel extends JPanel {
        /**
         * 
         */
        private static final long serialVersionUID = 1L;
        private JTextField md5Box = new JTextField();
        private JLabel md5Label = new JLabel("MD5:", JLabel.TRAILING);
        public final static int DOES_NOT_MATCH = 1;
        public final static int NO_REFRENCE = 2;
        public final static int MATCH = 3;

        public Md5Panel() {
            md5Label.setLabelFor(md5Box);
            md5Box.setColumns(20);
            md5Box.setEditable(false);
            this.add(md5Label);
            this.add(md5Box);
        }

        public void updateMd5(String md5) {
            md5Box.setText(md5);
        }

        public void updateMd5Status(int status) {
            switch (status) {
            case DOES_NOT_MATCH:
                md5Box.setBackground(Color.RED);
                break;
            case NO_REFRENCE:
                md5Box.setBackground(Color.yellow);
                break;
            case MATCH:
                md5Box.setBackground(Color.GREEN);
                break;
            default:
                md5Box.setBackground(UIManager.getColor("TextField.background"));
            }
        }

    }

    private class Menu extends JMenuBar {
        /**
         * 
         */
        private static final long serialVersionUID = 1L;
        JMenu main = new JMenu("Main");
        JMenu settings = new JMenu("Settings");
        JMenu help = new JMenu("Help");

        public Menu() {
            this.add(main);
            this.add(settings);
            this.add(help);
            addComTo();
        }

        public void addComTo() {
            Iterator<String> it = LoaderSerialIO.availableComPorts().iterator();
            ButtonGroup group = new ButtonGroup();
            while (it.hasNext()) {
                String com = it.next();
                JRadioButtonMenuItem b = new JRadioButtonMenuItem(com);
                group.add(b);
                if (serial != null) {
                    if (com.equals(serial.getCom())) {
                        group.setSelected(b.getModel(), true);
                    }
                }
                b.addActionListener(new ChangeList());
                settings.add(b);
            }
            JRadioButtonMenuItem b = new JRadioButtonMenuItem("fart");
            group.add(b);
            b.addActionListener(new ChangeList());
            settings.add(b);
            settings.addMenuListener(new updateSettings());
        }

        private class ChangeList implements ActionListener {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                // TODO Auto-generated method stub
                reInitSerial(arg0.getActionCommand());
            }

        }

        private class updateSettings implements MenuListener {

            @Override
            public void menuCanceled(MenuEvent arg0) {
                // TODO Auto-generated method stub

            }

            @Override
            public void menuDeselected(MenuEvent arg0) {
                // TODO Auto-generated method stub

            }

            @Override
            public void menuSelected(MenuEvent arg0) {
                // TODO Auto-generated method stub{
                settings.removeAll();
                Iterator<String> it = LoaderSerialIO.availableComPorts().iterator();
                ButtonGroup group = new ButtonGroup();
                while (it.hasNext()) {
                    String com = it.next();
                    JRadioButtonMenuItem b = new JRadioButtonMenuItem(com);
                    group.add(b);
                    if (serial != null) {
                        if (com.equals(serial.getCom())) {
                            group.setSelected(b.getModel(), true);
                        }
                    }
                    b.addActionListener(new ChangeList());
                    settings.add(b);
                }
            }

        }
    }

    private class InstallPanel extends JPanel implements ActionListener {
        /**
         * 
         */
        private static final long serialVersionUID = 1L;
        private JButton install = new JButton();

        public InstallPanel() {
            super();
            install.setText("Install");
            install.addActionListener(this);
            setInstallAble(false);
            this.add(install);
        }

        public void setInstallAble(boolean bool) {
            this.install.setEnabled(bool);
        }

        @Override
        public void actionPerformed(ActionEvent arg0) {
            install();
            setInstallAble(false);
        }
    }

    private class SendCommands extends JPanel implements KeyListener {
        /**
         * 
         */
        private static final long serialVersionUID = 1L;
        JLabel sendLabel = new JLabel("Enter Commands", JLabel.TRAILING);
        JTextField commandField = new JTextField();

        public SendCommands() {
            sendLabel.setLabelFor(commandField);
            commandField.setColumns(30);
            commandField.addKeyListener(this);
            this.add(sendLabel);
            this.add(commandField);
        }

        public void sendCommand() {
            serial.sendCommand(commandField.getText());
            commandField.setText("");
        }

        @Override
        public void keyPressed(KeyEvent e) {
            if (e.getKeyChar() == KeyEvent.VK_ENTER) {
                this.sendCommand();
            }
        }

        @Override
        public void keyReleased(KeyEvent e) {
            // TODO Auto-generated method stub

        }

        @Override
        public void keyTyped(KeyEvent e) {
            // TODO Auto-generated method stub

        }
    }

    private class DragAndDrop extends TransferHandler {

        private static final long serialVersionUID = 1L;

        @Override
        public boolean canImport(TransferHandler.TransferSupport info) {
            // we only import FileList
            if (!info.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
                return false;
            }
            return true;
        }

        @SuppressWarnings("unchecked")
        @Override
        public boolean importData(TransferHandler.TransferSupport info) {
            if (!info.isDrop()) {
                return false;
            }

            // Check for FileList flavor
            if (!info.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
                sendText("List doesn't accept a drop of this type.");
                return false;
            }

            // Get the fileList that is being dropped.
            Transferable t = info.getTransferable();
            List<File> data;
            try {

                //TODO add check for data type
                //this is the suppressed line, the check is done earlier and thus missed
                data = (List<File>) t.getTransferData(DataFlavor.javaFileListFlavor);
            } catch (Exception e) {
                return false;
            }

            ////////////////Don't Know if this is needed/////////////////
            DefaultListModel<File> model = (DefaultListModel<File>) fileDropper.getModel();
            for (File file : data) {
                model.addElement(file);
            }
            /////////////////////////////////////////////////////////////

            //set the md5 of the file just added
            sendText(model.getElementAt(model.size() - 1) + "\n");
            sendText("Now waiting on MD5 calculation\n");
            setFile(model.getElementAt(model.size() - 1));
            return true;
        }
    }

    public class MD5FileRead extends SwingWorker<String, Object> {
        File file;
        File md5File;

        public MD5FileRead(File file, File md5File) {
            this.file = file;
            this.md5File = md5File;
        }

        @Override
        protected String doInBackground() throws Exception {
            if (file == null) {
                return null;
            }
            InputStream read = new FileInputStream(file);
            Scanner scan = new Scanner(read);
            while (scan.hasNext()) {
                String token = scan.next();
                if (token.contains(file.getName())) {
                    scan.close();
                    token = token.substring(file.getName().length());
                    return token;
                }
            }
            scan.close();
            return null;
        }

        @Override
        public void done() {
            try {
                String get = get();
                if (get == null) {
                    md5Panel.updateMd5Status(Md5Panel.NO_REFRENCE);
                } else {
                    if (md5String.equals(get)) {
                        md5Panel.updateMd5Status(Md5Panel.MATCH);
                    } else {
                        md5Panel.updateMd5Status(Md5Panel.DOES_NOT_MATCH);
                    }
                }
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (ExecutionException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    }

    public class MD5Calc extends SwingWorker<String, Object> {
        File file;

        public MD5Calc(File file) {
            this.file = file;
        }

        @Override
        protected String doInBackground() throws Exception {
            try {
                MessageDigest dig = MessageDigest.getInstance("MD5");
                InputStream is = new FileInputStream(file);
                DigestInputStream dis = new DigestInputStream(is, dig);
                while (dis.read() > -1) {
                }
                dis.close();
                is.close();
                return Hex.encodeHexString(dig.digest());
            } catch (NoSuchAlgorithmException | IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return null;
        }

        @Override
        public void done() {
            installPanel.setInstallAble(true);
            try {
                sendText("MD5 calculation done\n");
                setMD5(get());

            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (ExecutionException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    public class Install extends SwingWorker<Void, Object> {
        LoaderSerialIO serial;
        String ip;
        File file;

        public Install(LoaderSerialIO serial, String ip, File fImage) {
            this.serial = serial;
            this.ip = ip;
            this.file = fImage;
        }

        @Override
        protected Void doInBackground() throws Exception {
            network.setStaticIp(ip);
            originalState = false;
            this.serial.installFirmware(this.ip, this.file);
            network.returnState();
            originalState = true;
            return null;
        }

        @Override
        public void done() {
            afterInstall();
        }
    }

    public class TFTPStart extends SwingWorker<Void, Object> {

        @Override
        protected Void doInBackground() throws Exception {
            serv = TFTPServerFactory.instantiate();
            return null;
        }

    }

    private class On_Exit extends Thread {
        public On_Exit() {
        }

        public void run() {
            if (!originalState) {
                network.returnState();
            }
        }
    }
}