![JAR search and dependency download from the Maven repository](/logo.png)
com.rapplogic.aru.uploader.wifi.WifiSketchUploader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of arduino-remote-uploader Show documentation
Show all versions of arduino-remote-uploader Show documentation
Command line tool and client api for uploading Arduino Sketches to a remote Arduino
The newest version!
/**
* 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 .
*/
package com.rapplogic.aru.uploader.wifi;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;
import java.text.ParseException;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.OptionBuilder;
import com.google.common.collect.Maps;
import com.rapplogic.aru.uploader.CliOptions;
import com.rapplogic.aru.uploader.SketchUploader;
import com.rapplogic.xbee.api.XBeeException;
public class WifiSketchUploader extends SketchUploader {
// this is up for debate. esp seems to drop more packets around low forties. and fails outright around 46
public final int WIFI_PAGE_SIZE = 32;
private Socket socket = null;
private volatile boolean connected;
public final static String host = "host";
public final static String port = "port";
public final static String connectionTimeoutSecs = "socket-connection-timeout-s";
public final static String readTimeoutSecs = "socket-read-timeout-s";
public WifiSketchUploader() {
super();
}
public void flash(String file, String host, int port, int connectionTimeoutSecs, int readTimeoutSecs, final boolean verbose, int ackTimeoutMillis, int arduinoTimeoutSecs, int retriesPerPacket, int delayBetweenRetriesMillis) throws IOException {
Map context = Maps.newHashMap();
context.put("host", host);
context.put("port", port);
context.put("connectionTimeoutSecs", connectionTimeoutSecs);
context.put("readTimeoutSecs", readTimeoutSecs);
// determine max data we can send with each programming packet
// NOTE remember to size the array on the Arduino accordingly to accomadate this size
int pageSize = WIFI_PAGE_SIZE - getProgramPageHeader(0, 0).length;
super.process(file, pageSize, ackTimeoutMillis, arduinoTimeoutSecs, retriesPerPacket, delayBetweenRetriesMillis, verbose, context);
}
// private int[] toIntArray(List list) {
// int[] reply = new int[list.size()];
// for (int i = 0; i < list.size(); i++) {
// reply[i] = list.get(i);
// }
//
// return reply;
// }
private String intArrayToString(int[] arr) {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < arr.length; i++) {
stringBuilder.append(arr[i] + ",");
}
return stringBuilder.toString();
}
private Thread t;
@Override
protected void open(final Map context) throws Exception {
String host = (String) context.get("host");
Integer port = (Integer) context.get("port");
Integer connectionTimeoutSecs = (Integer) context.get("connectionTimeoutSecs");
Integer readTimeoutSecs = (Integer) context.get("readTimeoutSecs");
// open socket
socket = new Socket();
socket.connect(new InetSocketAddress(host, port), connectionTimeoutSecs*1000);
socket.setSoTimeout(readTimeoutSecs*1000);
connected = true;
final int[] reply = new int[5];
final AtomicInteger replyIndex = new AtomicInteger(0);
// TODO unlike other wireless protocols, wifi is stateful so we need to handle situations where we lose the socket and reconnect
t = new Thread(new Runnable() {
@Override
public void run() {
int ch = 0;
// reply always terminated with 13,10
try {
while ((ch = socket.getInputStream().read()) > -1) {
if (replyIndex.get() < reply.length) {
reply[replyIndex.getAndIncrement()] = ch;
} else if (replyIndex.get() == 5 && ch == 13) {
replyIndex.getAndIncrement();
// discard
} else if (replyIndex.get() == 6 && ch == 10) {
//System.out.println("reply is " + stringBuilder.toString());
// stringBuilder = new StringBuilder();
handleReply(reply);
replyIndex.set(0);
} else {
//error
throw new RuntimeException("Expected CR/LF -- invalid reply at position " + replyIndex.get() + ", array: " + intArrayToString(reply));
}
}
} catch (IOException e) {
if (!connected && e instanceof SocketException) {
// expected.. ignore
} else {
System.out.println("IO error in socket reader");
e.printStackTrace();
}
} catch (Exception e) {
System.out.println("Unexpected error in socket reader");
e.printStackTrace();
}
connected = false;
}
});
t.setDaemon(true);
t.start();
}
protected boolean isConnected() {
return connected;
}
private void handleReply(int[] reply) {
//System.out.println("Received reply " + intArrayToString(reply));
// { MAGIC_BYTE1, MAGIC_BYTE2, 0, 0, 0};
addReply(reply);
}
@Override
protected void writeData(int[] data, Map context) throws Exception {
// ugh, convert to byte[] required or esp will receive multiple IPD commands
byte[] b = new byte[data.length + 2];
for (int i = 0; i < data.length; i++) {
b[i] = (byte) (data[i] & 0xff);
}
// every transmission must end with CR/LF
b[data.length] = (byte)13;
b[data.length + 1] = (byte)10;
socket.getOutputStream().write(b);
}
@Override
protected void close() throws Exception {
connected = false;
// close socket
socket.close();
}
@Override
protected String getName() {
return "wifi";
}
private void runFromCmdLine(String[] args) throws org.apache.commons.cli.ParseException, IOException {
CliOptions cliOptions = getCliOptions();
cliOptions.addOption(
OptionBuilder
.withLongOpt(host)
.hasArg()
.isRequired(true)
.withDescription("Host ip address of wifi device. Required")
.create("x")); // single arg is optional
cliOptions.addOption(
OptionBuilder
.withLongOpt(port)
.hasArg()
.isRequired(true)
.withType(Number.class)
.withDescription("Port of wifi server. Required")
.create("p"));
cliOptions.getDefaults().put(connectionTimeoutSecs, "10");
cliOptions.addOption(
OptionBuilder
.withLongOpt(connectionTimeoutSecs)
.hasArg()
.isRequired(false)
.withType(Number.class)
.withDescription("Connection timeout seconds")
.create("q")); // arbitrary -- running out of letters
cliOptions.getDefaults().put(readTimeoutSecs, "10");
cliOptions.addOption(
OptionBuilder
.withLongOpt(readTimeoutSecs)
.hasArg()
.isRequired(false)
.withType(Number.class)
.withDescription("Connection read seconds")
.create("v"));
cliOptions.build();
CommandLine commandLine = cliOptions.parse(args);
if (commandLine != null) {
new WifiSketchUploader().flash(
commandLine.getOptionValue(CliOptions.sketch),
commandLine.getOptionValue(host),
cliOptions.getIntegerOption(port),
cliOptions.getIntegerOption(connectionTimeoutSecs),
cliOptions.getIntegerOption(readTimeoutSecs),
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$ ./wifi-uploader.sh --host 192.168.1.115 --port 1111 -s ../../../resources/BlinkSlow.cpp.hex
Sending sketch to wifi 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
Sending page 1 of 43, with address 0, length 32, packet ef,ac,20,20,0,0,c,94,61,0,c,94,7e,0,c,94,7e,0,c,94,7e,0,c,94,7e,0,c,94,7e,0,c,94
Sending page 2 of 43, with address 26, length 32, packet ef,ac,20,20,0,1a,7e,0,c,94,7e,0,c,94,7e,0,c,94,7e,0,c,94,7e,0,c,94,7e,0,c,94,7e,0
..
Sending flash start packet ef,ac,40,6,4,4e
Sending flash packet to radio ef,ac,40,6,4,4e
Successfully flashed remote Arduino in 7s, with 0 retries
* @param args
* @throws NumberFormatException
* @throws IOException
* @throws XBeeException
* @throws ParseException
* @throws org.apache.commons.cli.ParseException
*/
public static void main(String[] args) throws NumberFormatException, IOException, ParseException, org.apache.commons.cli.ParseException {
initLog4j();
WifiSketchUploader wifiSketchUploader = new WifiSketchUploader();
wifiSketchUploader.runFromCmdLine(args);
// new WifiSketchUploader().flash(
// "/Users/andrew/Documents/dev/arduino-remote-uploader/resources/BlinkFast.cpp.hex",
// "192.168.1.115",
// 1111,
// 10,
// 10,
// true,
// 3000,
// 5,
// 3,
// 0);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy