com.rapplogic.aru.uploader.nordic.NordicSketchUploader.java Source code

Java tutorial

Introduction

Here is the source code for com.rapplogic.aru.uploader.nordic.NordicSketchUploader.java

Source

/**
 * Copyright (c) 2015 Andrew Rapp. All rights reserved.
 *
 * This file is part of arduino-remote-uploader
 *
 * arduino-remote-uploader 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.
 *
 * arduino-remote-uploader 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 arduino-remote-uploader.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.rapplogic.aru.uploader.nordic;

import gnu.io.PortInUseException;
import gnu.io.SerialPortEvent;
import gnu.io.UnsupportedCommOperationException;

import java.io.IOException;
import java.text.ParseException;
import java.util.Map;
import java.util.TooManyListenersException;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.OptionBuilder;
import org.apache.log4j.Logger;

import com.google.common.collect.Maps;
import com.rapplogic.aru.uploader.CliOptions;
import com.rapplogic.aru.uploader.serial.SerialSketchUploader;

/**
 * Uploads sketch to Nordic via the NordicSerialToSPI Sketch
 * 
 * @author andrew
 *
 */
public class NordicSketchUploader extends SerialSketchUploader {

    final Logger log = Logger.getLogger(NordicSketchUploader.class);

    private StringBuilder stringBuilder = new StringBuilder();

    private final int NORDIC_PACKET_SIZE = 32;

    public NordicSketchUploader() {
        super();
    }

    protected void handleSerial(SerialPortEvent event) {
        switch (event.getEventType()) {
        case SerialPortEvent.DATA_AVAILABLE:
            byte[] readBuffer = new byte[32];

            try {
                int numBytes = getInputStream().read(readBuffer);

                for (int i = 0; i < numBytes; i++) {
                    //System.out.println("read " + (char) readBuffer[i]);

                    // don't add lf/cr chars
                    if ((readBuffer[i] != 10 && readBuffer[i] != 13)) {
                        stringBuilder.append((char) readBuffer[i]);
                    }

                    // got a new line
                    if ((int) readBuffer[i] == 10) {
                        handleSerialReply(stringBuilder.toString());
                        stringBuilder = new StringBuilder();
                    }
                }
            } catch (Exception e) {
                log.error("Serial error", e);
            }

            break;
        }
    }

    protected void handleSerialReply(String reply) throws InterruptedException {
        // convert back to byte array for framework
        int[] replyArray = new int[] { MAGIC_BYTE1, MAGIC_BYTE2, 0, 0, 0 };

        if (isVerbose()) {
            System.out.println("<-" + reply);
        }

        // because we only have one serial port I've adopted a simple convention to use the serial
        // port for both debugging and control. Here's the convention:
        // starts with OK continue with net
        // starts with RETRY tx err/no ack, try again
        // starts with ERROR unrecoverable, fail
        // anything else is just debug

        if (reply.startsWith("OK")) {
            // parse id
            int replyId = Integer.parseInt(reply.split(",")[1].trim());

            replyArray[2] = OK;
            replyArray[3] = (replyId >> 8) & 0xff;
            replyArray[4] = replyId & 0xff;
        } else if (reply.startsWith("RETRY")) {
            // hacky
            replyArray[2] = RETRY;
        } else if (reply.startsWith("ERROR")) {
            replyArray[2] = START_OVER;
        }

        // if not debug message, add reply to queue
        if (replyArray[2] != 0) {
            addReply(replyArray);
        }
    }

    @Override
    public void open(Map<String, Object> context) throws Exception {
        this.openSerial((String) context.get("device"), (Integer) context.get("speed"));
    }

    @Override
    public void close() throws Exception {
        getSerialPort().close();
    }

    // TODO send nordic address

    public void flash(String file, String device, int speed, boolean verbose, int ackTimeout, int arduinoTimeout,
            int retriesPerPacket, int delayBetweenRetriesMillis) throws IOException, PortInUseException,
            UnsupportedCommOperationException, TooManyListenersException, StartOverException {
        Map<String, Object> context = Maps.newHashMap();
        context.put("device", device);
        context.put("speed", speed);

        // determine max data we can send with each programming packet
        int pageSize = NORDIC_PACKET_SIZE - getProgramPageHeader(0, 0).length;
        super.process(file, pageSize, ackTimeout, arduinoTimeout, retriesPerPacket, delayBetweenRetriesMillis,
                verbose, context);
    }

    @Override
    protected void writeData(int[] data, Map<String, Object> context) throws Exception {
        //System.out.println("Writing packet " + toHex(data));
        for (int i = 0; i < data.length; i++) {
            write(data[i]);
        }
    }

    @Override
    protected String getName() {
        return "nRF24L01";
    }

    public final static String serialPort = "serial-port";
    public final static String baudRate = "baud-rate";

    private void runFromCmdLine(String[] args) throws org.apache.commons.cli.ParseException, IOException,
            PortInUseException, UnsupportedCommOperationException, TooManyListenersException, StartOverException {
        CliOptions cliOptions = getCliOptions();

        cliOptions.addOption(OptionBuilder.withLongOpt(serialPort).hasArg().isRequired(true).withDescription(
                "Serial port of of Arduino running NordicSPI2Serial sketch (e.g. /dev/tty.usbserial-A6005uRz). Required")
                .create("p"));

        cliOptions.addOption(OptionBuilder.withLongOpt(baudRate).hasArg().isRequired(true).withType(Number.class)
                .withDescription("Baud rate of Arduino. Required").create("b"));

        cliOptions.build();

        CommandLine commandLine = cliOptions.parse(args);

        if (commandLine != null) {
            new NordicSketchUploader().flash(commandLine.getOptionValue(CliOptions.sketch),
                    commandLine.getOptionValue(serialPort), cliOptions.getIntegerOption(baudRate),
                    commandLine.hasOption(CliOptions.verboseArg),
                    cliOptions.getIntegerOption(CliOptions.ackTimeoutMillisArg),
                    cliOptions.getIntegerOption(CliOptions.arduinoTimeoutArg),
                    cliOptions.getIntegerOption(CliOptions.retriesPerPacketArg),
                    cliOptions.getIntegerOption(CliOptions.delayBetweenRetriesMillisArg));
        }
    }

    /**
     * ex ceylon:arduino-remote-uploader-1.0-SNAPSHOT andrew$ ./nordic-uploader.sh --sketch /Users/andrew/Documents/dev/arduino-remote-uploader/resources/BlinkSlow.cpp.hex --serial-port /dev/tty.usbmodemfa131 --baud-rate 19200 arduino-timeout 0 --ack-timeout-ms 5000 --retries 50
    Experimental:  JNI_OnLoad called.
    Stable Library
    =========================================
    Native lib Version = RXTX-2.1-7
    Java lib Version   = RXTX-2.1-7
    Sending sketch to nRF24L01 radio, size 1102 bytes, md5 8e7a58576bdc732d3f9708dab9aea5b9, number of packets 43, and 26 bytes per packet, header ef,ac,10,a,4,4e,0,2b,1a,3c
    ...........................................
    Successfully flashed remote Arduino in 3s, with 0 retries
        
     * @param args
     * @throws NumberFormatException
     * @throws IOException
     * @throws ParseException
     * @throws org.apache.commons.cli.ParseException
     * @throws PortInUseException
     * @throws UnsupportedCommOperationException
     * @throws TooManyListenersException
     * @throws StartOverException
     */
    public static void main(String[] args)
            throws NumberFormatException, IOException, ParseException, org.apache.commons.cli.ParseException,
            PortInUseException, UnsupportedCommOperationException, TooManyListenersException, StartOverException {
        initLog4j();
        new NordicSketchUploader().runFromCmdLine(args);
        //      new NordicSketchUploader().processNordic("/Users/andrew/Documents/dev/arduino-remote-uploader/resources/RAU-328-13k.hex", "/dev/tty.usbmodemfa131", Integer.parseInt("19200"), false, 5, 0, 50, 250);
    }
}