/* This file is part of JOP, the Java Optimized Processor (http://www.jopdesign.com/) Copyright (C) 2001-2008, Martin Schoeberl (martin@jopdesign.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 udp; import java.io.*; import java.net.*; /** * TFTP client for Flash programming and read of internal memory (stack). */ public class Tftp { public static final int PORT = 69; private static final int RRQ = 1; private static final int WRQ = 2; private static final int DAT = 3; private static final int ACK = 4; private static final int ERR = 5; private String addrString; private int retryCnt = 0; private static final int MAX_CNT = 3; private boolean verbose; /** * */ public Tftp(String addr) { addrString = addr; verbose = true; } /** * test Main read internal memory of JOP. */ public static void main(String[] args) throws IOException { int i; String file = "i0"; if (args.length==0) { System.out.println("usage: Tftp ip-address [file]"); System.exit(-1); } if (args.length==2) file = args[1]; Tftp t = new Tftp(args[0]); int[] buf = new int[65536/4]; int rcv_len = t.read(file, buf); System.out.println(rcv_len+" words received"); System.out.println(); for (i=0; i<rcv_len; ++i) { System.out.println(i+" "+buf[i]); } System.out.println(); } public int read(String fn, int[] buf) { try { byte[] byteBuf = new byte[buf.length*4]; byte f = (byte) fn.charAt(0); byte s = (byte) fn.charAt(1); int len = read(f, s, byteBuf); for (int i=0; i<len; i+=4) { buf[i/4] = (byteBuf[i]<<24) + ((byteBuf[i+1]<<16)&0xff0000) + ((byteBuf[i+2]<<8)&0xff00) + (byteBuf[i+3]&0xff); } return len/4; } catch (Exception e) { return 0; } } public int read(byte fn, byte sector, byte[] buf) throws IOException { // get a datagram socket DatagramSocket socket = new DatagramSocket(); byte[] sndBuf = new byte[512+4]; byte[] rcvBuf = new byte[512+4]; InetAddress address = InetAddress.getByName(addrString); sndBuf[0] = 0; sndBuf[1] = RRQ; sndBuf[2] = fn; sndBuf[3] = sector; sndBuf[4] = sndBuf[5] = 0; DatagramPacket send = new DatagramPacket(sndBuf, 6, address, PORT); socket.send(send); socket.setSoTimeout(10000); int expBlock = 1; int len = 0; retryCnt = 0; // get response for (;;) { // this is neccessary! I don't know why I have to construct a new packet for every reveive. DatagramPacket rcv = new DatagramPacket(rcvBuf, rcvBuf.length); try { socket.receive(rcv); // display response byte[] resp = rcv.getData(); retryCnt = 0; if (resp[1]==DAT) { sndBuf[0] = 0; sndBuf[1] = ACK; sndBuf[2] = (byte) (expBlock >>> 8); sndBuf[3] = (byte) expBlock; send = new DatagramPacket(sndBuf, 4, address, PORT); socket.send(send); int block = ((((int) resp[2])&0xff)<<8) + (((int) resp[3])&0xff); if (verbose) System.out.print("got "+block+"\r"); if (block == expBlock) { for (int i=0; i<rcv.getLength()-4; ++i) { buf[(block-1)*512+i] = resp[i+4]; } if (rcv.getLength()<512+4) { len = (block-1)*512+rcv.getLength()-4; break; } expBlock += 1; } } else { len = 0; break; } } catch (Exception e) { ++retryCnt; if (retryCnt > MAX_CNT) return 0; if (verbose) System.out.println(); System.out.println(e); // retry if (expBlock==1) { if (verbose) System.out.println("retry RRQ"); sndBuf[0] = 0; sndBuf[1] = RRQ; sndBuf[2] = fn; sndBuf[3] = sector; } else { if (verbose) System.out.println("retry ACK "+(expBlock-1)); sndBuf[0] = 0; sndBuf[1] = ACK; sndBuf[2] = (byte) ((expBlock-1) >>> 8); sndBuf[3] = (byte) (expBlock-1); } send = new DatagramPacket(sndBuf, 4, address, PORT); socket.send(send); } } socket.close(); return len; } public boolean write(byte fn, byte sector, byte[] buf, int len) throws IOException { // get a datagram socket DatagramSocket socket = new DatagramSocket(); byte[] sndBuf = new byte[512+4]; byte[] rcvBuf = new byte[512+4]; InetAddress address = InetAddress.getByName(addrString); sndBuf[0] = 0; sndBuf[1] = WRQ; sndBuf[2] = fn; sndBuf[3] = sector; sndBuf[4] = sndBuf[5] = 0; DatagramPacket send = new DatagramPacket(sndBuf, 6, address, PORT); socket.send(send); socket.setSoTimeout(5000); int expBlock = 0; boolean ret = false; // get response for (;;) { // this is neccessary! I don't know why I have to construct a new packet for every reveive. DatagramPacket rcv = new DatagramPacket(rcvBuf, rcvBuf.length); try { socket.receive(rcv); // display response byte[] resp = rcv.getData(); if (resp[1]==ACK) { int block = ((((int) resp[2])&0xff)<<8) + (((int) resp[3])&0xff); if (block != expBlock) { ret = false; break; } ++expBlock; if (verbose) System.out.print("send "+expBlock+"\r"); } else { ret = false; break; } } catch (Exception e) { if (verbose) System.out.println(); System.out.println(e); // retry if (expBlock==0) { if (verbose) System.out.println("retry WRQ"); } else { if (verbose) System.out.println("retry DAT "+expBlock); } } if (expBlock==0) { sndBuf[0] = 0; sndBuf[1] = WRQ; sndBuf[2] = fn; sndBuf[3] = sector; sndBuf[4] = sndBuf[5] = 0; send = new DatagramPacket(sndBuf, 6, address, PORT); socket.send(send); } else { sndBuf[0] = 0; sndBuf[1] = DAT; sndBuf[2] = (byte) (expBlock >>> 8); sndBuf[3] = (byte) expBlock; int start = (expBlock-1)*512; int k=4; if (start>len) { // last acked packet was less than 512 ret = true; break; } for (int i=start; i<len && k<4+512; ++i) { sndBuf[k] = buf[i]; ++k; } send = new DatagramPacket(sndBuf, k, address, PORT); socket.send(send); if (k==4) { // last packet is empty ret = true; break; } } } socket.close(); return ret; } /** * @return */ public boolean isVerbose() { return verbose; } /** * @param b */ public void setVerbose(boolean b) { verbose = b; } }