package org.nanovm; // // NanoVMTool, Converter and Upload Tool for the NanoVM // Copyright (C) 2005-2006 by Till Harbaum <Till@Harbaum.org> // Oliver Schulz <whisp@users.sf.net> // // 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 2 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, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // Parts of this tool are based on public domain code written by Kimberley // Burchett: http://www.kimbly.com/code/classfile/ // import org.nanovm.converter.Config; import java.io.*; import java.util.*; import gnu.io.*; // needs to be added to vm public class Uploader { // ASCII codes used during transmission final static int ASCII_SOH = 0x01; final static int ASCII_STX = 0x02; final static int ASCII_EOT = 0x04; final static int ASCII_ACK = 0x06; final static int ASCII_DLE = 0x10; final static int ASCII_XON = 0x11; final static int ASCII_XOFF = 0x13; final static int ASCII_NAK = 0x15; final static int ASCII_SYN = 0x16; final static int ASCII_CAN = 0x18; final static int ASCII_EOF = 0x1A; final static int BLOCK_SIZE = 16; // Asure needs specific handling static boolean asuro_echo_suppression = false; static Enumeration portList; static CommPortIdentifier portId; static SerialPort serialPort; static OutputStream outputStream; static InputStream inputStream; static boolean outputBufferEmptyFlag = false; public static void setUploader(String type){ // ignore for now... } static int get(boolean timeout) { final int TIMEOUT = 50; byte[] inputArray = new byte[1]; if(timeout) { int cnt=0; try { while((inputStream.available() == 0) && (cnt<TIMEOUT)) { Thread.currentThread().sleep(10); // 10 msec cnt++; } } catch(Exception e) {} if(cnt == TIMEOUT) return -1; } try { inputStream.read(inputArray); } catch (Exception e) { System.out.println("Error reading from serial port"); System.out.println(e.toString()); System.exit(-1); } return inputArray[0]; } static void put(int i) { byte[] ioArray = new byte[1]; i &= 0xff; ioArray[0] = (byte)i; // System.out.println("sending " + // Integer.toHexString(((int)ioArray[0])&0xff)+" "+ // Integer.toHexString(i)); try { outputStream.write(ioArray); } catch (Exception e) { System.out.println("Error writing to serial port"); System.out.println(e.toString()); System.exit(-1); } if(asuro_echo_suppression) { // simple echo cancelation try { inputStream.read(ioArray); } catch (Exception e) { System.out.println("Error reading echo from serial port"); System.out.println(e.toString()); System.exit(-1); } if((((int)ioArray[0])&0xff) != i) System.out.println("Echo error: " + Integer.toHexString(i) + "/" + Integer.toHexString(((int)ioArray[0])&0xff)); } } public static void upload(String device, int target, int speed, byte[] file, int length) { boolean portFound = false; int i, j, block, n; int sum; boolean done; int cur = 0; if(target == Config.TARGET_NVC1_ASURO) { System.out.println("Enabling Asuro IR echo suppression."); asuro_echo_suppression = true; } portList = CommPortIdentifier.getPortIdentifiers(); while (portList.hasMoreElements()) { portId = (CommPortIdentifier) portList.nextElement(); if(portId.getPortType() == CommPortIdentifier.PORT_SERIAL) { if(portId.getName().equals(device)) { System.out.println("Found port " + device); portFound = true; try { serialPort = (SerialPort) portId.open("Uploader", 2000); } catch (PortInUseException e) { System.out.println("Port in use."); continue; } try { outputStream = serialPort.getOutputStream(); inputStream = serialPort.getInputStream(); } catch (IOException e) {} try { serialPort.setSerialPortParams(speed, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); } catch (UnsupportedCommOperationException e) {} try { serialPort.notifyOnOutputEmpty(true); } catch (Exception e) { System.out.println("Error setting event notification"); System.out.println(e.toString()); serialPort.close(); System.exit(-1); } if ( (target == Config.TARGET_NVC1_AUTO) || (target == Config.TARGET_NVC1_UART) || (target == Config.TARGET_NVC1_ASURO) ) { // == NVMCOMM1 ======================================================== // first flush buffers while((i = get(true)) != -1); System.out.println("Using NanoVM Communication Protocol v1.0"); // wait for NAK System.out.println("Please reset/start target now ..."); while((i=get(false)) != ASCII_NAK) { System.out.println("Received " + i); } // wait some time for receiver to start try { Thread.currentThread().sleep(100); } catch(Exception e) {} // start sending first block i = ASCII_ACK; block = 0; j = 0; do { if(i == ASCII_ACK) { cur += j; j = length - cur; if(j > BLOCK_SIZE) j = BLOCK_SIZE; block++; if(j > 0) System.out.print("Sending block " + block + " with " + j + " bytes ... "); } else System.out.print("Resending block " + block + " ... "); if(j > 0) { // send header put(ASCII_SOH); put(block); put(~block); // send data and calculate sum for(n=0,sum=0;n<j;n++) { sum += file[cur+n]; put(file[cur+n]); } // fill up with zeros if required for(;n<BLOCK_SIZE;n++) put(0); // send sum put(sum); // check result while(((i=get(true)) != ASCII_NAK)&&(i != ASCII_ACK)) { // ignore timeouts if(i>=0) System.out.println("received " + i); } // if we received an ack -> good!! if(i == ASCII_ACK) { System.out.println("ok"); if(j == BLOCK_SIZE) done = false; else done = true; } else { System.out.println("error"); done = false; } } else done = true; // no more bytes to send } while(!done); // transmission ended, send eof and expect ack put(ASCII_EOF); while(((i=get(true)) != ASCII_NAK)&&(i != ASCII_ACK)); if(i == ASCII_ACK) { if(asuro_echo_suppression) System.out.println("Download successful, " + "please restart your Asuro"); else System.out.println("Download successful, " + "program started!"); } else System.out.println("Error: nak after eof"); // ==================================================================== } // NVMCOMM1 else if (target == Config.TARGET_NVC2_AUTO) { // == NVMCOMM2 ======================================================== final int maxSearchTries = 10000; short slaveAddr = 0x10; // default slave address; System.out.println("Using NanoVM Communication Protocol v2.0"); // System.out.println("DEBUG: speed = "+speed); NVMComm2 nvc = new NVMComm2(inputStream, outputStream, speed); boolean slaveFound = false; System.out.print("Info: Looking for target system"); for (int tryctr=0; tryctr<maxSearchTries; ++tryctr) { NVMComm2.ResponseMessage response = nvc.executeQuery(slaveAddr, false, NVMComm2.CMD_NONE, null, 1); if ((response != null) && !response.isError()) { slaveFound = true; break; } try{ Thread.currentThread().sleep(100); } catch(Exception e) {} System.out.print(" ."); } System.out.println(""); if (slaveFound) { System.out.println("Info: Target system found"); NVMComm2.ResponseMessage response; System.out.println("Info: Setting target runlevel to conf."); response = nvc.executeQuery(slaveAddr, false, NVMComm2.CMD_RUNLVL, NVMComm2.RUNLVL_CONF, 0); System.out.println("Info: Opening target firmware."); response = nvc.executeQuery(slaveAddr, false, NVMComm2.CMD_FOPEN, (byte)0, 0); for (int filePos=0; filePos < length;) { int dlen = NVMComm2.MAX_DATA_LEN < length-filePos ? NVMComm2.MAX_DATA_LEN : length-filePos; byte[] queryData = new byte[dlen]; int dataPos = 0; while ( (dataPos < queryData.length) && (filePos < length) ) queryData[dataPos++] = file[filePos++]; System.out.println("Info: Writing firmware bytes "+Integer.toHexString(filePos-queryData.length)+" to "+Integer.toHexString(filePos-1)); response = nvc.executeQuery(slaveAddr, false, NVMComm2.CMD_RWFILE, queryData, 0); if ((response == null) || response.isError()) { System.out.println("Info: Error writing firmware!"); break; } } System.out.println("Info: Closing target firmware."); response = nvc.executeQuery(slaveAddr, false, NVMComm2.CMD_FCLOSE, (byte)0, 0); System.out.println("Info: Setting target runlevel to reset."); response = nvc.executeQuery(slaveAddr, false, NVMComm2.CMD_RUNLVL, NVMComm2.RUNLVL_RESET, 0); try { Thread.currentThread().sleep(200); } catch(Exception e) {} System.out.println("Info: Setting target runlevel to conf."); response = nvc.executeQuery(slaveAddr, false, NVMComm2.CMD_RUNLVL, NVMComm2.RUNLVL_CONF, 0); System.out.println("Info: Opening target firmware."); response = nvc.executeQuery(slaveAddr, false, NVMComm2.CMD_FOPEN, (byte)0, 0); byte[] testFile = new byte[length]; for (int filePos=0; filePos < length;) { int rlen = NVMComm2.MAX_DATA_LEN < length-filePos ? NVMComm2.MAX_DATA_LEN : length-filePos; System.out.println("Info: Reading firmware bytes "+Integer.toHexString(filePos)+" to "+Integer.toHexString(filePos+rlen-1)); response = nvc.executeQuery(slaveAddr, true, NVMComm2.CMD_RWFILE, (byte)rlen, 0); if ((response == null) || response.isError()) { System.out.println("Info: Error reading firmware!"); break; } for (int pos = 0; pos < response.getData().length; ++pos) { testFile[filePos] = response.getData()[pos]; filePos++; } } System.out.println("Info: Closing target firmware."); response = nvc.executeQuery(slaveAddr, false, NVMComm2.CMD_FCLOSE, (byte)0, 0); System.out.println("Info: Checking target firmware."); for (int pos=0; pos<length; ++pos) { if (file[pos] != testFile[pos]) System.out.println("Info: Firmware verify failed at byte 0x"+Integer.toHexString(pos)+" : "+Integer.toHexString(0xFF & (int)testFile[pos])+" != "+Integer.toHexString(0xFF & (int)file[pos])); } System.out.println("Info: Setting target runlevel to halt."); response = nvc.executeQuery(slaveAddr, false, NVMComm2.CMD_RUNLVL, NVMComm2.RUNLVL_HALT, 0); } else { System.out.println("Error: Target system not responding"); } // ==================================================================== } // NVMCOMM2 else System.out.println("Error: unknown target"); serialPort.close(); System.exit(0); } } } if (!portFound) { System.out.println("Port " + device + " not found."); } } public static void main(String[] args) { byte[] buffer = null; if(args.length != 3) { System.out.println("Usage: Uploader device {bitrate|asuro} file"); System.exit(-1); } // load file into memory // nvmcomm2 not enabled here yet. try { File inputFile = new File(args[2]); buffer = new byte[(int)inputFile.length()]; FileInputStream in = new FileInputStream(inputFile); in.read(buffer); in.close(); } catch(IOException e) { System.out.println("Error loading file " + args[2]); System.exit(-1); } if(args[1].equalsIgnoreCase("asuro")) upload(args[0], Config.TARGET_NVC1_ASURO, 2400, buffer, buffer.length); else upload(args[0], Config.TARGET_NVC1_UART, Integer.parseInt(args[1]), buffer, buffer.length); } }