virtualModem/report/source.tex

1160 lines
42 KiB
TeX
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

%
% Network programming Lab report source code
%
% authors:
% Χρήστος Χουτουρίδης ΑΕΜ 8997
% cchoutou@ece.auth.gr
% Document configuration
\newcommand{\ClassName}{Δίκτυα Υπολογιστών Ι}
\newcommand{\DocTitle}{Κώδικας εφαρμογής}
\newcommand{\InstructorName}{Δημήτριος Μητράκος}
\newcommand{\InstructorMail}{mitrakos@eng.auth.gr}
\newcommand{\CurrentDate}{\today}
\input{AuthReport.tex}
%\renewcommand{\AuthorName}{Χρήστος Χουτουρίδης}
%\renewcommand{\AuthorMail}{cchoutou@ece.auth.gr}
%\renewcommand{\AuthorAEM}{8997}
\fancyhead[L]{\ClassName}
\fancyhead[R]{Χρήστος Χουτουρίδης 8997}
% Document
% =================
\begin{document}
\FirstPage
\tableofcontents
\section{Περιγραφή}
Για την ανάπτυξη του κώδικα χρησιμοποιήσαμε το περιβάλλον \eng{eclipse} και το \eng{openjdk} στην έκδοση 11.
Επειδή η εφαρμογή λειτουργεί ως \eng{command line tool,} χρησιμοποιήσαμε ακόμα το \eng{commons-cli} από \href{http://commons.apache.org/proper/commons-cli/}{\eng{apache commons}} ώς εργαλείο ανάγνωσης των ορισμάτων του χρήστη.
Η υλοποίηση της εφαρμογής είναι πολύ απλή.
Δεν χρησιμοποιούμε \eng{interfaces} ή κληρονομικότητα.
Αντίθετα έχουμε χωρίσει την εφαρμογή σε αυτόνομα αντικείμενα.
Τα αντικείμενα \eng{Com} και \eng{Log} παρέχουν τις βασικές λειτουργίες για την επικοινωνία με τον \eng{server} και την έξοδο του προγράμματος αντίστοιχα.
Τα αντικείμενα αυτά χρησιμοποιούνται απλώς μέσα υπόλοιπα.
Χρησιμοποιούμε δηλαδή την απλούστερη δυνατή τεχνική (\eng{build by composition}).
\par Τον κώδικα καθώς και την παραγόμενη τεκμηρίωσή του μέσω \eng{JavaDoc} μπορείτε να την βρείτε στο παραδοτέο αρχείο στους καταλόγους \eng{src} και \eng{doc.}
Τέλος στο \href{https://git.hoo2.net/hoo2/virtualModem}{προσωπικό αποθετήριο} του συντάκτη υπάρχει όλος ο κώδικας της εφαρμογής, της εργασίας και της επεξεργασίας των αποτελεσμάτων.
Παραθέτουμε παρακάτω τον κώδικα της εφαρμογής σε μορφή !!κειμένου!!, όπως αυτό ζητήθηκε από την εκφώνηση της εργασίας.
Το κάθε κεφάλαιο αντιστοιχεί σε ξεχωριστό αρχείο του κώδικα.
\selectlanguage{english}
\titleformat{\section}[block]{\large\textbf}{\thesection.}{1em}{}
\small
\section{virtualModem.java}
\begin{verbatim}
/**
* @file VirtualModem.java
* @brief
* Contain the Main class for the project VirtualModem
*
* Usage examples:
* ==========================
* java -jar ./VirtualModem.jar -v -l Exxxx-$(date +%F-%T).log -e Exxxx 600
* java -jar ./VirtualModem.jar -v -l Qxxx-Rxxxx-$(date +%F-%T).log -a Qxxxx Rxxxx 600
* java -jar ./VirtualModem.jar -v -l Pxxxx_600_80_8p-$(date +%F-%T).log -p Pxxxx 600 80 8 P1124-$(date +%F-%T)
* java -jar ./VirtualModem.jar -v -l Mxxxx-$(date +%F-%T).log -g Mxxxx Mxxxx-$(date +%F-%T) 2
* java -jar ./VirtualModem.jar -v -l Gxxxx-$(date +%F-%T).log -g Gxxxx Gxxxx-$(date +%F-%T) 2
*
* @author Christos Choutouridis AEM:8997
* @email cchoutou@ece.auth.gr
*/
package net.hoo2.auth.vmodem;
/** @name imports */
/** @{ */
import org.apache.commons.cli.*; /** command line utility */
/** @} */
/**
* @class VirtualModem
*
* @brief This is the main control class of the program.
*
* This class includes the main function which read the user input
* and create the appropriate object for the requested sequence to
* retrieve data.
*/
public class VirtualModem {
/** @name Data */
/** @{ */
CommandLine line; /** Command line for the argument list */
CommandLineParser parser; /** Parser for the argument list */
Options options; /** Option configuration container */
HelpFormatter formatter; /** An extra helper for -h */
Com com; /** Reference to basic configuration module */
Log log; /** Reference to basic logging module */
/** @} */
/**
* @brief The main constructor of the class
* We allocate memory for the data needed for the command line
*/
public VirtualModem () {
parser = new DefaultParser();
options = new Options();
formatter = new HelpFormatter();
com = new Com();
// Create argument options and a basic help file
// for future use.
Option verb = new Option ("v", "verbose", false, "Be more verbose to the console");
Option help = new Option ("h", "help", false, "Print this message");
Option timeout = Option.builder("t")
.longOpt("timeout")
.hasArg()
.valueSeparator('=')
.desc("Select timeout in [sec]")
.build();
Option speed = Option.builder("s")
.longOpt("speed")
.hasArg()
.valueSeparator('=')
.desc("Select speed in [bps]")
.build();
Option log = Option.builder("l")
.longOpt("log")
.hasArg()
.desc("Log file name to use")
.build();
Option echo = Option.builder("e")
.longOpt("echo")
.numberOfArgs(2)
.desc ("Request echo sequence where <arg> = <1> <2>\n"
+ " <1>: The echo requested code from virtual lab\n"
+ " <2>: The time duration of the session [sec]")
.build();
Option arq = Option.builder("a")
.longOpt("arq")
.numberOfArgs(3)
.desc ("Request arq sequence where <arg> = <1> <2> <3>\n"
+ " <1>: The ACK requested code for virtual lab\n"
+ " <2>: The NACK requested code from virtual lab\n"
+ " <2>: The time duration for the session [sec]")
.build();
Option img = Option.builder("g")
.longOpt("img")
.numberOfArgs(3)
.desc("Request an image sequence where <arg> = <1> <2> <3>\n"
+ " <1>: The image requested code from virtual lab\n"
+ " <2>: The filename to use for storing the image (without .jpg)\n"
+ " <3>: The requested images to fetch.")
.build();
Option gps = Option.builder("p")
.longOpt("gps")
.numberOfArgs(5) // G8164 10 800 8 gps_10_800
.desc("Request a GPS sequence where <arg> = <1> <2> <3> <4>\n"
+ " <1>: The gps requested code from virtual lab\n"
+ " <2>: The time from trace to use as starting point [sec]\n"
+ " <3>: The time duration for the trace to fetch [sec]\n"
+ " <4>: The number of points to fetch from the above trace\n"
+ " <5>: The filename to use for storing the image (without .jpg)")
.build();
options.addOption(verb);
options.addOption(help);
options.addOption(timeout);
options.addOption(speed);
options.addOption(log);
options.addOption(echo);
options.addOption(arq);
options.addOption(img);
options.addOption(gps);
}
/** @name private api */
/**@{*/
/**
* parse the command line arguments
* @param args the arguments to parse
* @return the status of the operation
*/
private boolean getCmdOptions (String[] args) {
try {
// parse the command line arguments
line = parser.parse (options, args);
}
catch( ParseException exp ) {
// oops, something went wrong
System.err.println( "Parsing command line failed: " + exp.getMessage() );
return false;
}
return true;
}
/**
* Dispatch the correct functionality based on arguments
* @return the status of the operation (currently true)
*/
private boolean commandDispatcher () {
boolean verbose = false;
if (line.hasOption("help")) {
formatter.printHelp( "virtualModem", options );
return true;
}
// Get log and verbose options first
if (line.hasOption("verbose"))
verbose = true;
if (line.hasOption("log"))
log = new Log (line.getOptionValue("log"), verbose);
else
log = new Log (null, verbose);
if (log.open() != true)
return false;
// get other options
if (line.hasOption("timeout")) {
com.timeout(Integer.parseInt(line.getOptionValue("timeout")));
}
if (line.hasOption("speed")) {
com.speed(Integer.parseInt(line.getOptionValue("speed")));
}
// Execution dispatcher
if (line.hasOption("echo")) {
byte[] code = line.getOptionValues("echo")[0].getBytes();
Echo e = new Echo(com, log, code,
Integer.valueOf(line.getOptionValues("echo")[1]));
if (com.open()) {
e.caption(code);
e.run();
com.close();
}
}
else if (line.hasOption("arq")) {
byte[] ack = line.getOptionValues("arq")[0].getBytes();
byte[] nack = line.getOptionValues("arq")[1].getBytes();
ARQ a = new ARQ(com, log, ack, nack,
Integer.valueOf(line.getOptionValues("arq")[2]));
if (com.open()) {
a.caption(ack, nack);
a.run();
com.close();
}
}
else if (line.hasOption("img")) {
byte[] code = line.getOptionValues("img")[0].getBytes();
Image im = new Image (com, log, code,
line.getOptionValues("img")[1],
Integer.valueOf(line.getOptionValues("img")[2]));
if (com.open()) {
im.caption(code);
im.run();
com.close();
}
}
else if (line.hasOption("gps")) {
byte[] code = line.getOptionValues("gps")[0].getBytes();
GPS g = new GPS (
com, log, code,
Integer.valueOf(line.getOptionValues("gps")[1]),
Integer.valueOf(line.getOptionValues("gps")[2]),
Integer.valueOf(line.getOptionValues("gps")[3])
);
Image im = new Image (
com, log, null,
line.getOptionValues("gps")[4], 1
);
if (com.open()) {
g.caption();
im.code(g.run().getBytes());
im.run();
com.close();
}
}
log.close();
return true;
}
/**@}*/
/**
* @brief Main function
*/
public static void main(String[] args) {
// allocate the main object
VirtualModem vmodem = new VirtualModem();
// prepare command line input
if (vmodem.getCmdOptions (args) != true)
return;
// Call the requested functionality
if (vmodem.commandDispatcher() != true)
return;
}
}
\end{verbatim}
\section{Com.java}
\begin{verbatim}
/**
* @file Com.java
*
* @author Christos Choutouridis AEM:8997
* @email cchoutou@ece.auth.gr
*/
package net.hoo2.auth.vmodem;
/** @name imports */
/** @{ */
import java.util.Arrays;
import ithakimodem.*;
/** @} */
/**
* @class Com
*
* Wrapper object of the provided Modem class to provide
* a convenient and common API for all the session functionalities
*/
class Com {
static final int SPEED_DEFAULT = 48000; /** default communication speed [bps] */
static final int TIMEOUT_DEFAULT = 2000; /** default timeout values [sec] */
static final String URL_DEFAULT = "ithaki"; /** Default destination. Ithaki of-course */
private Modem modem_; /** Ref to Modem */
private int speed_; /** Communication speed [bps] */
private int timeout_; /** communication timeout [sec] */
/**
* Basic constructor
*/
Com () {
modem_ = new Modem();
speed_ = SPEED_DEFAULT;
timeout_ = TIMEOUT_DEFAULT;
modem_.setSpeed(speed_);
modem_.setTimeout(timeout_);
}
/** A more fancy constructor
*
* @param log Reference to Log to use
* @param speed The desired speed [bps]
* @param timeout The desired timeout [sec]
* @note
* Currently not used
*/
Com (Log log, int speed, int timeout) {
modem_ = new Modem();
speed_ = speed;
timeout_ = timeout;
modem_.setSpeed(speed_);
modem_.setTimeout(timeout_);
}
/** @name Mutator interface */
/**@{ */
/** Get the current timeout value [sec] */
int timeout () { return timeout_; }
/** Set the timeout value [sec] */
void timeout (int timeout) {
if (timeout_ != timeout) {
timeout_ = timeout;
modem_.setTimeout(timeout_);
}
}
/** Get the current speed [bps] */
int speed () { return speed_; }
/** Set the speed [bps] */
void speed (int speed) {
if (speed_ != speed) {
speed_ = speed;
modem_.setSpeed(speed_);
}
}
/**@} */
/** @name Public API of the class */
/**@{ */
/** Open a communication channel with a URL */
boolean open (String url) { return modem_.open(url); }
/** Open a communication channel with Ithaki */
boolean open () { return modem_.open(URL_DEFAULT); }
/** Close the connection */
boolean close() { return modem_.close(); }
/**
* @grief The basic communication functionality
*
* This function sends a request to server and return the response. In order to
* do that, the main reading loop seeks for the starting pattern and use the data
* from that point up to the ending pattern. This is very helpful for binary incoming
* data.
* @note
* Blocking mode
* @param data Reference to Transaction data to use @see Transaction
* @param code The request code to send
* @param begin The starting pattern of the response data
* @param end The ending pattern of the response data
* @param bin A flag to indicate that the data are in binary form
* @return Reference to Transaction object with the response data. @see Transaction
*/
Transaction request (Transaction data, byte[] code, byte[] begin, byte[] end, boolean bin) {
int ch =0;
boolean have_begin = (begin != null) ? false : true;
boolean incoming = false;
// Clear the receive buffer first
_clear (data.response, 0, data.response.length);
if (code != null) {
// if we have a request
data.code = code; // store the request code for the transaction
modem_.write(data.code); // send the code and mark the time
modem_.write((int)'\r');
data.departure = System.currentTimeMillis();// - (long)((8*(data.code.length+1))*(1000.0/speed_));
}
// main receive loop
data.size =0;
do {
// escape guard for memory protection
if (data.size >= data.response.length) {
data.size =0;
return data;
}
// read the data byte from server
try {
ch = modem_.read();
}
catch (Exception e) {
// Oops!!!! something went wrong. Break and return :(
System.err.println (e.getMessage());
data.size =0;
return data;
}
if (!incoming) {
// first byte triggered. mark the time
incoming = true;
data.arrival = System.currentTimeMillis();// - (long)(8*(1000.0/speed_));
}
data.response [data.size++] = (byte)ch; // store the byte
if (!have_begin && (detect(data.response, begin, data.size) != -1)) {
// If begin pattern detected, start over.
_clear(data.response, 0, data.size);
data.size = _copy (data.response, begin);
have_begin = true;
}
} while (
ch != -1 && (
!have_begin || (
(bin || (detect (data.response, "\r\n\n\n".getBytes(), data.size) == -1))
&& (bin || (detect (data.response, "NO CARRIER".getBytes(), data.size) == -1))
&& (detect (data.response, end, data.size) == -1)
)
)
);
/*^
* We loop until:
* 1) server returns -1
* 2) A end pattern arrives
* 3) A "\r\n\n\n" sequence arrives (in character mode, not for binary files)
* 4) A "NO CARRIER" sequence arrives (in character mode, not for binary files)
*/
return data;
}
/**
* @brief
* A pattern detect functionality.
*
* Search in data input for the pattern and return its position if found.
* @note
* O(n^2) in time.
* @param data The data buffer to search into
* @param pattern The pattern to search for
* @param max The maximum length to search
* @return The position of pattern in data, or -1 if not found
*/
static int detect (byte[] data, byte[] pattern, int max) {
if (pattern != null) {
for (int i =0 ; i<max && i<data.length - pattern.length; ++i) {
boolean detected = true;
for (int j=0 ; j<pattern.length ; ++j) {
if (data[i+j] != pattern[j]) {
detected = false;
break;
}
}
if (detected)
return i;
}
}
return -1;
}
/**@} */
/** @name Private helper api */
/**@{*/
/**
* Clear a buffer segment
* @param buffer Buffer to clear
* @param begin The starting point
* @param end The ending point
*/
private void _clear (byte[] buffer, int begin, int end) {
for (int i=begin ; i<end && i<buffer.length ; ++i)
buffer[i] = 0;
}
/**
* Copy a buffer to another
* @param dest The destination buffer
* @param src The source buffer
* @return The number of bytes copied
*/
private int _copy (byte[] dest, byte[] src) {
if (dest.length >= src.length) {
for (int i=0 ; i<src.length ; ++i)
dest[i] = src[i];
return src.length;
}
return 0;
}
/**@}*/
}
/**
* @class
* Class to represent client-server transaction data
*/
class Transaction {
byte[] code; /** request code from client */
byte[] response; /** response data from server */
long departure; /** request time */
long arrival; /** response time */
int size; /** size of response data in bytes */
/**
* Basic constructor
* @param code Code to use
* @param response Response buffer to use
*/
Transaction (byte[] code, byte[] response) {
this.code = code;
this.response = response;
departure = arrival = 0;
size = 0;
}
/**
* Get a copy of the response
*/
byte[] getResponse() {
return Arrays.copyOf(response, size);
}
}
\end{verbatim}
\section{Log.java}
\begin{verbatim}
/**
* @file Log.java
*
* @author Christos Choutouridis AEM:8997
* @email cchoutou@ece.auth.gr
*/
package net.hoo2.auth.vmodem;
/** @name imports */
/** @{ */
import java.io.IOException;
import java.io.PrintWriter;
/** @} */
/**
* @class Log
*
* A common log functionality class for all sessions
*/
class Log {
private String logfile_; /** The log file name */
private boolean verbose_; /** The desired verbosity (for the console)*/
private PrintWriter writer_; /** A buffered writer to use for streaming */
/**
* Basic constructor
* @param logfile The log filename
* @param verbose The desired verbosity (for the console)
*/
Log (String logfile, boolean verbose) {
logfile_ = logfile;
verbose_ = verbose;
}
/**
* Try to open the log file
* @return The status of the operation
*/
boolean open () {
if (logfile_ != null) {
try {
writer_ = new PrintWriter(logfile_);
}
catch (IOException exp) {
System.err.println( "Open log file failed: " + exp.getMessage() );
return false;
}
}
return true;
}
/**
* Try to open a log file
* @param logfile The log file to open
* @return The status of the operation
*/
boolean open (String logfile) {
logfile_ = logfile;
return open();
}
/**
* Close the opened file
* @return The status of the operation
*/
boolean close () {
try {
if (writer_ != null)
writer_.close();
} catch (Exception ex) {
return false;
}
return true;
}
/**
* Log to file and print to console
* @param line The line to log
* @param out Console output request flag. If true, echo the line to console
*/
void write (String line, boolean out) {
if (logfile_ != null) writer_.println(line);
if (verbose_ || out) System.out.println(line);
}
/**
* Log to file and print to console
* @param line The line to log
*/
void write (String line) {
if (logfile_ != null) writer_.println(line);
if (verbose_) System.out.println(line);
}
/**
* Echo the line to console
* @param line The line to print
*/
void out (String line) {
if (verbose_) System.out.println(line);
}
}
\end{verbatim}
\section{ARQ.java}
\begin{verbatim}
/**
* @file ARQ.java
*
* @author Christos Choutouridis AEM:8997
* @email cchoutou@ece.auth.gr
*/
package net.hoo2.auth.vmodem;
/** @name imports */
/** @{ */
import java.util.*;
/** @} */
/**
* @class ARQ
*
* Class to used for the ACK-NACK sequence
*/
class ARQ {
static final int ARQ_DURATION_DEFAULT = 240; /** Default duration for the sequence */
static final int ARQ_BUFFER_SIZE = 256; /** ARQ buffer size */
static final String ARQ_BEGIN = "PSTART"; /** Begin pattern of the response */
static final String ARQ_END = "PSTOP"; /** End pattern of the response */
static final int ARQ_SEQUENCE_BEGIN = 31; /** The response sequence string position */
static final int ARQ_SEQUENCE_END = 47; /** The end of response sequence string position */
static final int ARQ_CRC_BEGIN = 49; /** The response crc string position */
static final int ARQ_CRC_END = 52; /** The end of response crc string position */
private Com com_; /** Reference to communication module */
private Log log_; /** Reference to logging module */
private Transaction transaction_; /** A transaction object to used as a buffer for all requests */
private int duration_; /** The desired duration for the session */
private byte[] ack_; /** The desired ACK code for the session */
private byte[] nack_; /** The desired NACK code for the session */
/**
* Basic constructor
* @param com The Com module to use
* @param log The Log module to use
* @param ack The desired ACK code
* @param nack The desired NACK code
* @param duration The desired duration for the session
*/
ARQ (Com com, Log log, byte[] ack, byte[] nack, int duration) {
com_ = com;
log_ = log;
duration_ = duration;
transaction_= new Transaction(null, new byte[ARQ_BUFFER_SIZE]);
ack_ = ack;
nack_ = nack;
}
/**
* Functionality to drain the response buffer for the welcome message
* from the server
* @param ack The ack code that we will use (for printing, not sending)
* @param nack The nack code that we will use (for printing, not sending)
*/
void caption (byte[] ack, byte[] nack) {
String line;
line = "Running ARQ with: " + new String(ack) + "/" + new String(nack);
log_.write(line, true);
transaction_ = com_.request (transaction_, null, null, null, false);
line = new String(transaction_.getResponse());
log_.out(line);
}
/**
* Main transaction loop. It send requests to server, get the response
* and log the procedure while doing it.
*/
void run () {
long start;
long now;
long mark =0, tr =0, ts =0, tt =0;
String line;
int errors = 0;
boolean good = true;
start = System.currentTimeMillis();
do {
// Check if the previous transaction was error-free
if (good)
transaction_ = com_.request(transaction_, ack_, ARQ_BEGIN.getBytes(), ARQ_END.getBytes(), false);
else
transaction_ = com_.request(transaction_, nack_, ARQ_BEGIN.getBytes(), ARQ_END.getBytes(), false);
good = (_crc_check(transaction_.response)) ? true : false; // crc check the response
// time calculations
tr = transaction_.arrival - transaction_.departure;
tt = 0;
if ((errors == 0) && good) {
tt = ts = tr;
}
if ((errors == 0) && !good) {
mark = transaction_.departure;
ts = tr;
}
if ((errors != 0) && good) {
tt = transaction_.arrival - mark;
ts += tr;
}
if ((errors !=0) && !good) {
ts += tr;
}
errors = (good) ? 0 : errors+1; // update the error strike
line = new String(transaction_.code) + ": "
+ new String(transaction_.getResponse())
+ " Er: " + errors
+ " Tr= " + tr + " [msec]";
if (errors !=0)
line += " Ts= 0 [msec] Tt= 0 [msec]";
else
line += " Ts= " + ts + " [msec]" + " Tt= " + tt + " [msec]";
log_.write(line);
now = System.currentTimeMillis();
} while (now - start < duration_*1000);
}
/** @name private helper API */
/**@{ */
/**
* A CRC check functionality
* @param data The data to check for validity
* @return The check result
*/
private boolean _crc_check (byte[] data) {
byte[] seq = Arrays.copyOfRange(data, ARQ_SEQUENCE_BEGIN, ARQ_SEQUENCE_END);
int crc = Integer.valueOf(
new String(Arrays.copyOfRange(data, ARQ_CRC_BEGIN, ARQ_CRC_END))
);
return (crc == _crc(seq)) ? true : false;
}
/**
* A CRC calculation function. This primitive CRC calculator
* does not use any known CRC polynomial. It just uses XOR
* @param data Reference to buffer
* @return The CRC result
*/
private int _crc (byte[] data) {
int calc =0;
for (int i=0 ; i<data.length ; ++i)
calc ^= data[i];
return calc;
}
/**@} */
}
\end{verbatim}
\section{Echo.java}
\begin{verbatim}
/**
* @file Echo.java
*
* @author Christos Choutouridis AEM:8997
* @email cchoutou@ece.auth.gr
*/
package net.hoo2.auth.vmodem;
/**
* @class Echo
*
* Class to used for the echo sequence
*/
class Echo {
static final int ECHO_DURATION_DEFAULT = 240; /** Default duration for the sequence */
static final int ECHO_BUFFER_SIZE = 256; /** Echo buffer size */
static final String ECHO_BEGIN = "PSTART"; /** Begin pattern of the response */
static final String ECHO_END = "PSTOP"; /** End pattern of the response */
private Com com_; /** Reference to communication module */
private Log log_; /** Reference to logging module */
private Transaction transaction_; /** A transaction object to used as a buffer for all requests */
private int duration_; /** The desired duration for the session */
private byte[] code_; /** The desired code for the session */
/**
* Basic constructor
* @param com The Communication module to use
* @param log The logging module to use
* @param code The code to use
* @param duration The duration to use
*/
Echo (Com com, Log log, byte[] code, int duration) {
com_ = com;
log_ = log;
duration_ = duration;
// Allocate memory for the response
transaction_= new Transaction(null, new byte[ECHO_BUFFER_SIZE]);
code_ = code;
}
/**
* Functionality to drain the response buffer for the welcome message
* from the server
* @param code The code that we will use (for printing, not sending)
*/
void caption (byte[] code) {
String line;
line = "Running ECHO with: " + new String(code);
log_.write(line, true);
transaction_ = com_.request (transaction_, null, null, null, false);
line = new String(transaction_.getResponse());
log_.out(line);
}
/**
* Main transaction loop. It send requests to server, get the response
* and log the procedure while doing it.
*/
void run () {
long start;
long now;
String line;
start = System.currentTimeMillis();
do {
transaction_ = com_.request(transaction_, code_, ECHO_BEGIN.getBytes(), ECHO_END.getBytes(), false);
line = new String(transaction_.code) + ": "
+ new String(transaction_.getResponse())
+ " Tr= " + (transaction_.arrival - transaction_.departure) + " [msec]";
log_.write(line);
now = System.currentTimeMillis();
} while (now - start < duration_*1000);
}
}
\end{verbatim}
\section{GPS.java}
\begin{verbatim}
/**
* @file GPS.java
*
* @author Christos Choutouridis AEM:8997
* @email cchoutou@ece.auth.gr
*/
package net.hoo2.auth.vmodem;
/** @name imports */
/** @{ */
import java.util.Arrays;
/** @} */
/**
* @class GPS
*
* Class to used for the GPS session
*/
class GPS {
static final int GPS_BUFFER_SIZE = 256; /** GPS trace buffer size */
static final String GPS_BEGIN = "START ITHAKI GPS TRACKING"; /** starting pattern */
static final String GPS_END = "STOP ITHAKI GPS TRACKING"; /** ending pattern */
static final int GPS_USE_TRACK = 1; /** Which track to use (given) */
static final String GPS_TRACK_PREFIX = "R="; /** GPS command track request prefix */
static final String GPS_IMAGE_PREFIX = "T="; /** GPS command image request prefix */
static final int GPS_MAX_POINTS = 9; /** Maximum points (given) */
static final int GPS_COORDINATES_SIZE = 6; /** Coordinates size */
static final int GPS_LATITUDE_BEGIN = 17; /** The latitude sequence string position */
static final int GPS_LATITUDE_END = 28; /** The end of latitude sequence string position */
static final int GPS_LONGITUDE_BEGIN= 29; /** The longitude sequence string position */
static final int GPS_LONGITUDE_END = 41; /** The end of longitude sequence string position */
private Com com_; /** Reference to communication module */
private Log log_; /** Reference to logging module */
private Transaction transaction_; /** A transaction object to used as a buffer for all requests */
private byte[] code_; /** The desired code for the session */
private int start_; /** Starting point [sec] */
private int duration_; /** Duration of requested trace */
private int points_; /** Number of points to fetch from the above trace */
private byte[] coordinates_; /** Coordinates buffer */
/**
* Basic constructor
*/
GPS (Com com, Log log, byte[] code, int start, int duration, int points) {
com_ = com;
log_ = log;
transaction_= new Transaction(null, new byte[GPS_BUFFER_SIZE]);
code_ = code;
start_ = start;
duration_ = duration;
points_ = (points <= GPS_MAX_POINTS) ? points : GPS_MAX_POINTS;
coordinates_= new byte[GPS_COORDINATES_SIZE];
}
/**
* Functionality to drain the response buffer for the welcome message
* from the server
*/
void caption () {
String line;
line = "Running GPS with: " + new String(code_)
+ " time [" + start_ + " - " +(start_+duration_) + ") sec" + " [" + points_ + " points]";
log_.write(line, true);
transaction_ = com_.request (transaction_, null, null, null, false);
line = new String(transaction_.getResponse());
log_.out(line);
}
/**
* Main transaction loop. It send requests to server, get the response
* and log the procedure while doing it.
* @return the image request code to pass to image module
*/
String run () {
String code, image_code;
String line;
log_.out("Get traces");
image_code = new String(code_);
for (int trace =start_ ; trace < start_+duration_ ; trace += duration_/points_) {
code = new String(code_) + GPS_TRACK_PREFIX + GPS_USE_TRACK + String.format("%04d", trace) + "01";
transaction_ = com_.request(transaction_, code.getBytes(), GPS_BEGIN.getBytes(), GPS_END.getBytes(), false);
line = new String(transaction_.code) + ": "
+ new String(transaction_.getResponse())
+ " Tr= " + (transaction_.arrival - transaction_.departure) + " [msec]";
log_.write(line);
_get_coordinates(transaction_.getResponse());
image_code += GPS_IMAGE_PREFIX +
String.format("%02d%02d%02d%02d%02d%02d", coordinates_[0], coordinates_[1],
coordinates_[2], coordinates_[3],
coordinates_[4], coordinates_[5]);
}
return image_code;
}
/** @name private helper API */
/** @{ */
/**
* Extract coordinates from response
* @param stream The stream to search
* @return The coordinates buffer
*/
private byte[] _get_coordinates (byte[] stream) {
int start = Com.detect(stream, "GPGGA".getBytes(), stream.length);
double latitude = _nmea2dec (Double.valueOf(
new String (Arrays.copyOfRange(stream,
start+GPS_LATITUDE_BEGIN,
start+GPS_LATITUDE_END-2))));
double longitude = _nmea2dec (Double.valueOf(
new String(Arrays.copyOfRange(stream,
start+GPS_LONGITUDE_BEGIN,
start+GPS_LONGITUDE_END-2))));
coordinates_[0] = (byte)(longitude); // longitude deg
coordinates_[1] = (byte)((longitude - coordinates_[0]) * 60.0); // longitude '
coordinates_[2] = (byte)((longitude - coordinates_[0]
- coordinates_[1]/60.0)*3600); // longitude "
coordinates_[3] = (byte)(latitude); // latitude deg
coordinates_[4] = (byte)((latitude - coordinates_[3]) * 60.0); // latitude '
coordinates_[5] = (byte)((latitude - coordinates_[3]
- coordinates_[4]/60.0)*3600); // latitude "
return coordinates_;
}
/**
* A helper to convert the NMEA format to canonical
* decimal coordinate format
*/
double _nmea2dec (double c) {
int d = (int)c/100;
c -= d*100;
return d + (c/60);
}
/** @} */
}
\end{verbatim}
\section{Image.java}
\begin{verbatim}
/**
* @file Image.java
*
* @author Christos Choutouridis AEM:8997
* @email cchoutou@ece.auth.gr
*/
package net.hoo2.auth.vmodem;
/** @name imports */
/** @{ */
import java.io.*;
/** @} */
/**
* @class Image
*
* Class to used for the error free and non error free image requests
*/
class Image {
static final int IMAGE_BUFFER_SIZE = 256*1024; /** image buffer size */
static final byte[] IMAGE_BEGIN = {(byte)0xFF, (byte)0xD8}; /** jpeg image begin pattern */
static final byte[] IMAGE_END = {(byte)0xFF, (byte)0xD9}; /** jpeg image end pattern */
private Com com_; /** Reference to communication module */
private Log log_; /** Reference to logging module */
private Transaction transaction_; /** A transaction object to used as a buffer for all requests */
private String filename_; /** The filename to store */
private int items_; /** how many images to fetch */
private byte[] code_; /** The image request code for the virtual lab */
/**
* Basic constructor
* @param com The com module to use
* @param log The log module to use
* @param code The request code
* @param filename The filename
* @param items How many items to fetch
*/
Image (Com com, Log log, byte[] code, String filename, int items) {
com_ = com;
log_ = log;
// Allocate memory for the response
transaction_= new Transaction(null, new byte[IMAGE_BUFFER_SIZE]);
filename_ = filename;
items_ = items;
code_ = code;
}
/** Get function for the code */
void code (byte[] code) { code_ = code; }
/**
* Functionality to drain the response buffer for the welcome message
* from the server
* @param code The code that we will use (for printing, not sending)
*/
void caption (byte[] code) {
String line;
line = "Running video decoder with: " + new String(code);
log_.write(line, true);
transaction_ = com_.request (transaction_, null, null, null, false);
line = new String(transaction_.getResponse());
log_.out(line);
}
/**
* Main transaction loop. It send requests to server, get the response
* and log the procedure while doing it.
*/
void run () {
String file, line;
BufferedOutputStream ostream;
for (int i =1 ; i<= items_ ; ++i) {
// Make the filename string
if (items_>1)
file = filename_ + "_" + i + ".jpg";
else
file = filename_ + ".jpg";
line = new String(code_) + ": ";
log_.write(line);
transaction_ = com_.request(transaction_, code_, IMAGE_BEGIN, IMAGE_END, true);
line = "File= " + file
+ " Tr= " + (transaction_.arrival - transaction_.departure) + " [msec]"
+ " Tt= " + (System.currentTimeMillis() - transaction_.departure) + " [msec]";
log_.write(line);
try {
ostream = new BufferedOutputStream(new FileOutputStream(file));
ostream.write(transaction_.response);
ostream.flush();
ostream.close();
}
catch (Exception exp) {
System.err.println ("Error creating " + file + exp.getMessage());
return;
}
}
}
}
\end{verbatim}
\end{document}