@@ -2,3 +2,5 @@ | |||||
*.project | *.project | ||||
*.classpath | *.classpath | ||||
*.doc | |||||
@@ -1,25 +1,47 @@ | |||||
/** | |||||
* @file AQR.java | |||||
* | |||||
* @author Christos Choutouridis AEM:8997 | |||||
* @email cchoutou@ece.auth.gr | |||||
*/ | |||||
package net.hoo2.auth.vmodem; | package net.hoo2.auth.vmodem; | ||||
/** @name imports */ | |||||
/** @{ */ | |||||
import java.util.*; | import java.util.*; | ||||
/** @} */ | |||||
/** | |||||
* @class AQR | |||||
* | |||||
* Class to used for the ACK-NACK sequence | |||||
*/ | |||||
class AQR { | class AQR { | ||||
static final int AQ_DURATION_DEFAULT = 240; | |||||
static final int AQR_BUFFER_SIZE = 256; | |||||
static final String AQR_BEGIN = "PSTART"; | |||||
static final String AQR_END = "PSTOP"; | |||||
static final int AQ_DURATION_DEFAULT = 240; /**< Default duration for the sequence */ | |||||
static final int AQR_BUFFER_SIZE = 256; /**< AQR buffer size */ | |||||
static final String AQR_BEGIN = "PSTART"; /**< Begin pattern of the response */ | |||||
static final String AQR_END = "PSTOP"; /**< End pattern of the response */ | |||||
static final int AQR_SEQUENCE_BEGIN = 31; | |||||
static final int AQR_SEQUENCE_END = 47; | |||||
static final int AQR_CRC_BEGIN = 49; | |||||
static final int AQR_CRC_END = 52; | |||||
static final int AQR_SEQUENCE_BEGIN = 31; /**< The response sequence string position */ | |||||
static final int AQR_SEQUENCE_END = 47; /**< The end of response sequence string position */ | |||||
static final int AQR_CRC_BEGIN = 49; /**< The response crc string position */ | |||||
static final int AQR_CRC_END = 52; /**< The end of response crc string position */ | |||||
private Com com_; | |||||
private Log log_; | |||||
private Transaction transaction_; | |||||
private int duration_; | |||||
private byte[] ack_; | |||||
private byte[] nack_; | |||||
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 | |||||
*/ | |||||
AQR (Com com, Log log, byte[] ack, byte[] nack, int duration) { | AQR (Com com, Log log, byte[] ack, byte[] nack, int duration) { | ||||
com_ = com; | com_ = com; | ||||
log_ = log; | log_ = log; | ||||
@@ -28,7 +50,13 @@ class AQR { | |||||
ack_ = ack; | ack_ = ack; | ||||
nack_ = nack; | 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) { | void caption (byte[] ack, byte[] nack) { | ||||
String line; | String line; | ||||
@@ -40,6 +68,10 @@ class AQR { | |||||
log_.out(line); | log_.out(line); | ||||
} | } | ||||
/** | |||||
* Main transaction loop. It send requests to server, get the response | |||||
* and log the procedure while doing it. | |||||
*/ | |||||
void run () { | void run () { | ||||
long start; | long start; | ||||
long now; | long now; | ||||
@@ -51,12 +83,13 @@ class AQR { | |||||
start = System.currentTimeMillis(); | start = System.currentTimeMillis(); | ||||
do { | do { | ||||
// Check if the previous transaction was error-free | |||||
if (good) | if (good) | ||||
transaction_ = com_.request(transaction_, ack_, AQR_BEGIN.getBytes(), AQR_END.getBytes(), false); | transaction_ = com_.request(transaction_, ack_, AQR_BEGIN.getBytes(), AQR_END.getBytes(), false); | ||||
else | else | ||||
transaction_ = com_.request(transaction_, nack_, AQR_BEGIN.getBytes(), AQR_END.getBytes(), false); | transaction_ = com_.request(transaction_, nack_, AQR_BEGIN.getBytes(), AQR_END.getBytes(), false); | ||||
good = (_crc_check(transaction_.response)) ? true : false; | |||||
bads = (good) ? 0 : bads+1; | |||||
good = (_crc_check(transaction_.response)) ? true : false; // crc check the response | |||||
bads = (good) ? 0 : bads+1; // count the error strike | |||||
// delay calculation | // delay calculation | ||||
if (prev && !good) mark = transaction_.departure; | if (prev && !good) mark = transaction_.departure; | ||||
@@ -73,18 +106,33 @@ class AQR { | |||||
now = System.currentTimeMillis(); | now = System.currentTimeMillis(); | ||||
} while (now - start < duration_*1000); | } 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) { | private boolean _crc_check (byte[] data) { | ||||
byte[] seq = Arrays.copyOfRange(data, AQR_SEQUENCE_BEGIN, AQR_SEQUENCE_END); | byte[] seq = Arrays.copyOfRange(data, AQR_SEQUENCE_BEGIN, AQR_SEQUENCE_END); | ||||
int crc = Integer.valueOf( | int crc = Integer.valueOf( | ||||
new String(Arrays.copyOfRange(data, AQR_CRC_BEGIN, AQR_CRC_END))); | new String(Arrays.copyOfRange(data, AQR_CRC_BEGIN, AQR_CRC_END))); | ||||
return (crc == _crc(seq)) ? true : false; | 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) { | private int _crc (byte[] data) { | ||||
int calc =0; | int calc =0; | ||||
for (int i=0 ; i<data.length ; ++i) | for (int i=0 ; i<data.length ; ++i) | ||||
calc ^= data[i]; | calc ^= data[i]; | ||||
return calc; | return calc; | ||||
} | } | ||||
/**@} */ | |||||
} | } |
@@ -1,17 +1,35 @@ | |||||
/** | |||||
* @file Com.java | |||||
* | |||||
* @author Christos Choutouridis AEM:8997 | |||||
* @email cchoutou@ece.auth.gr | |||||
*/ | |||||
package net.hoo2.auth.vmodem; | package net.hoo2.auth.vmodem; | ||||
/** @name imports */ | |||||
/** @{ */ | |||||
import java.util.Arrays; | import java.util.Arrays; | ||||
import ithakimodem.*; | 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 { | class Com { | ||||
static final int SPEED_DEFAULT = 48000; | |||||
static final int TIMEOUT_DEFAULT = 2000; | |||||
static final String URL_DEFAULT = "ithaki"; | |||||
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_; | |||||
private int speed_; | |||||
private int timeout_; | |||||
private Modem modem_; /**< Ref to Modem */ | |||||
private int speed_; /**< Communication speed [bps] */ | |||||
private int timeout_; /**< communication timeout [sec] */ | |||||
/** | |||||
* Basic constructor | |||||
*/ | |||||
Com () { | Com () { | ||||
modem_ = new Modem(); | modem_ = new Modem(); | ||||
speed_ = SPEED_DEFAULT; | speed_ = SPEED_DEFAULT; | ||||
@@ -19,6 +37,14 @@ class Com { | |||||
modem_.setSpeed(speed_); | modem_.setSpeed(speed_); | ||||
modem_.setTimeout(timeout_); | 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) { | Com (Log log, int speed, int timeout) { | ||||
modem_ = new Modem(); | modem_ = new Modem(); | ||||
speed_ = speed; | speed_ = speed; | ||||
@@ -26,63 +52,96 @@ class Com { | |||||
modem_.setSpeed(speed_); | modem_.setSpeed(speed_); | ||||
modem_.setTimeout(timeout_); | modem_.setTimeout(timeout_); | ||||
} | } | ||||
// get/set | |||||
/** @name Mutator interface */ | |||||
/**@{ */ | |||||
/** Get the current timeout value [sec] */ | |||||
int timeout () { return timeout_; } | int timeout () { return timeout_; } | ||||
/** Set the timeout value [sec] */ | |||||
void timeout (int timeout) { | void timeout (int timeout) { | ||||
if (timeout_ != timeout) { | if (timeout_ != timeout) { | ||||
timeout_ = timeout; | timeout_ = timeout; | ||||
modem_.setTimeout(timeout_); | modem_.setTimeout(timeout_); | ||||
} | } | ||||
} | } | ||||
/** Get the current speed [bps] */ | |||||
int speed () { return speed_; } | int speed () { return speed_; } | ||||
/** Set the speed [bps] */ | |||||
void speed (int speed) { | void speed (int speed) { | ||||
if (speed_ != speed) { | if (speed_ != speed) { | ||||
speed_ = speed; | speed_ = speed; | ||||
modem_.setSpeed(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); } | boolean open (String url) { return modem_.open(url); } | ||||
/** Open a communication channel with Ithaki */ | |||||
boolean open () { return modem_.open(URL_DEFAULT); } | boolean open () { return modem_.open(URL_DEFAULT); } | ||||
/** Close the connection */ | |||||
boolean close() { return modem_.close(); } | 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) { | Transaction request (Transaction data, byte[] code, byte[] begin, byte[] end, boolean bin) { | ||||
int ch =0; | int ch =0; | ||||
boolean have_begin = (begin != null) ? false : true; | boolean have_begin = (begin != null) ? false : true; | ||||
boolean incoming = false; | boolean incoming = false; | ||||
// Clear the receive buffer first | |||||
_clear (data.response, 0, data.response.length); | _clear (data.response, 0, data.response.length); | ||||
if (code != null) { | if (code != null) { | ||||
data.code = code; | |||||
modem_.write(data.code); | |||||
// 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'); | modem_.write((int)'\r'); | ||||
data.departure = System.currentTimeMillis();// - (long)((8*(data.code.length+1))*(1000.0/speed_)); | data.departure = System.currentTimeMillis();// - (long)((8*(data.code.length+1))*(1000.0/speed_)); | ||||
} | } | ||||
// main receive loop | |||||
data.size =0; | data.size =0; | ||||
do { | do { | ||||
// escape guard for memory protection | |||||
if (data.size >= data.response.length) { | if (data.size >= data.response.length) { | ||||
data.size =0; | data.size =0; | ||||
return data; | return data; | ||||
} | } | ||||
// read the data byte from server | |||||
try { | try { | ||||
ch = modem_.read(); | ch = modem_.read(); | ||||
} | } | ||||
catch (Exception e) { | catch (Exception e) { | ||||
// Oops!!!! something went wrong. Break and return :( | |||||
System.err.println (e.getMessage()); | System.err.println (e.getMessage()); | ||||
data.size =0; | data.size =0; | ||||
return data; | return data; | ||||
} | } | ||||
if (!incoming) { | if (!incoming) { | ||||
// first byte triggered. mark the time | |||||
incoming = true; | incoming = true; | ||||
data.arrival = System.currentTimeMillis();// - (long)(8*(1000.0/speed_)); | data.arrival = System.currentTimeMillis();// - (long)(8*(1000.0/speed_)); | ||||
} | } | ||||
data.response [data.size++] = (byte)ch; | |||||
data.response [data.size++] = (byte)ch; // store the byte | |||||
if (!have_begin && (detect(data.response, begin, data.size) != -1)) { | if (!have_begin && (detect(data.response, begin, data.size) != -1)) { | ||||
// If begin pattern detected, start over. | |||||
_clear(data.response, 0, data.size); | _clear(data.response, 0, data.size); | ||||
data.size = _copy (data.response, begin); | data.size = _copy (data.response, begin); | ||||
have_begin = true; | have_begin = true; | ||||
@@ -95,9 +154,28 @@ class Com { | |||||
) | ) | ||||
) | ) | ||||
); | ); | ||||
/*^ | |||||
* 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; | 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) { | static int detect (byte[] data, byte[] pattern, int max) { | ||||
if (pattern != null) { | if (pattern != null) { | ||||
for (int i =0 ; i<max && i<data.length - pattern.length; ++i) { | for (int i =0 ; i<max && i<data.length - pattern.length; ++i) { | ||||
@@ -114,12 +192,27 @@ class Com { | |||||
} | } | ||||
return -1; | 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) { | private void _clear (byte[] buffer, int begin, int end) { | ||||
for (int i=begin ; i<end && i<buffer.length ; ++i) | for (int i=begin ; i<end && i<buffer.length ; ++i) | ||||
buffer[i] = 0; | 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) { | private int _copy (byte[] dest, byte[] src) { | ||||
if (dest.length >= src.length) { | if (dest.length >= src.length) { | ||||
for (int i=0 ; i<src.length ; ++i) | for (int i=0 ; i<src.length ; ++i) | ||||
@@ -128,24 +221,35 @@ class Com { | |||||
} | } | ||||
return 0; | return 0; | ||||
} | } | ||||
/**@}*/ | |||||
} | } | ||||
/** | |||||
* @class | |||||
* Class to represent client-server transaction data | |||||
*/ | |||||
class Transaction { | class Transaction { | ||||
byte[] code; | |||||
byte[] response; | |||||
long departure; | |||||
long arrival; | |||||
int size; | |||||
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) { | Transaction (byte[] code, byte[] response) { | ||||
this.code = code; | this.code = code; | ||||
this.response = response; | this.response = response; | ||||
departure = arrival = 0; | departure = arrival = 0; | ||||
size = 0; | size = 0; | ||||
} | } | ||||
/** | |||||
* Get a copy of the response | |||||
*/ | |||||
byte[] getResponse() { | byte[] getResponse() { | ||||
return Arrays.copyOf(response, size); | return Arrays.copyOf(response, size); | ||||
} | } | ||||
@@ -1,25 +1,49 @@ | |||||
/** | |||||
* @file Echo.java | |||||
* | |||||
* @author Christos Choutouridis AEM:8997 | |||||
* @email cchoutou@ece.auth.gr | |||||
*/ | |||||
package net.hoo2.auth.vmodem; | package net.hoo2.auth.vmodem; | ||||
/** | |||||
* @class Echo | |||||
* | |||||
* Class to used for the echo sequence | |||||
*/ | |||||
class Echo { | class Echo { | ||||
static final int ECHO_DURATION_DEFAULT = 240; | |||||
static final int ECHO_BUFFER_SIZE = 256; | |||||
static final String ECHO_BEGIN = "PSTART"; | |||||
static final String ECHO_END = "PSTOP"; | |||||
private Com com_; | |||||
private Log log_; | |||||
private Transaction transaction_; | |||||
private int duration_; | |||||
private byte[] code_; | |||||
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) { | Echo (Com com, Log log, byte[] code, int duration) { | ||||
com_ = com; | com_ = com; | ||||
log_ = log; | log_ = log; | ||||
duration_ = duration; | duration_ = duration; | ||||
// Allocate memory for the response | |||||
transaction_= new Transaction(null, new byte[ECHO_BUFFER_SIZE]); | transaction_= new Transaction(null, new byte[ECHO_BUFFER_SIZE]); | ||||
code_ = 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) { | void caption (byte[] code) { | ||||
String line; | String line; | ||||
@@ -31,6 +55,10 @@ class Echo { | |||||
log_.out(line); | log_.out(line); | ||||
} | } | ||||
/** | |||||
* Main transaction loop. It send requests to server, get the response | |||||
* and log the procedure while doing it. | |||||
*/ | |||||
void run () { | void run () { | ||||
long start; | long start; | ||||
long now; | long now; | ||||
@@ -1,31 +1,48 @@ | |||||
/** | |||||
* @file GPS.java | |||||
* | |||||
* @author Christos Choutouridis AEM:8997 | |||||
* @email cchoutou@ece.auth.gr | |||||
*/ | |||||
package net.hoo2.auth.vmodem; | package net.hoo2.auth.vmodem; | ||||
/** @name imports */ | |||||
/** @{ */ | |||||
import java.util.Arrays; | import java.util.Arrays; | ||||
/** @} */ | |||||
/** | |||||
* @class GPS | |||||
* | |||||
* Class to used for the GPS session | |||||
*/ | |||||
class GPS { | class GPS { | ||||
static final int GPS_BUFFER_SIZE = 256; | |||||
static final String GPS_BEGIN = "START ITHAKI GPS TRACKING"; | |||||
static final String GPS_END = "STOP ITHAKI GPS TRACKING"; | |||||
static final int GPS_USE_TRACK = 1; | |||||
static final String GPS_TRACK_PREFIX = "R="; | |||||
static final String GPS_IMAGE_PREFIX = "T="; | |||||
static final int GPS_MAX_POINTS = 9; | |||||
static final int GPS_COORDINATES_SIZE = 6; | |||||
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; | |||||
static final int GPS_LATITUDE_END = 28; | |||||
static final int GPS_LONGITUDE_BEGIN= 29; | |||||
static final int GPS_LONGITUDE_END = 41; | |||||
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_; | |||||
private Log log_; | |||||
private Transaction transaction_; | |||||
private byte[] code_; | |||||
private int start_; | |||||
private int duration_; | |||||
private int points_; | |||||
private byte[] coordinates_; | |||||
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) { | GPS (Com com, Log log, byte[] code, int start, int duration, int points) { | ||||
com_ = com; | com_ = com; | ||||
log_ = log; | log_ = log; | ||||
@@ -37,6 +54,10 @@ class GPS { | |||||
coordinates_= new byte[GPS_COORDINATES_SIZE]; | coordinates_= new byte[GPS_COORDINATES_SIZE]; | ||||
} | } | ||||
/** | |||||
* Functionality to drain the response buffer for the welcome message | |||||
* from the server | |||||
*/ | |||||
void caption () { | void caption () { | ||||
String line; | String line; | ||||
@@ -49,10 +70,15 @@ class GPS { | |||||
log_.out(line); | 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 run () { | ||||
String code, image_code; | String code, image_code; | ||||
String line; | String line; | ||||
log_.out("Get traces"); | log_.out("Get traces"); | ||||
image_code = new String(code_); | image_code = new String(code_); | ||||
for (int trace =start_ ; trace < start_+duration_ ; trace += duration_/points_) { | for (int trace =start_ ; trace < start_+duration_ ; trace += duration_/points_) { | ||||
@@ -72,7 +98,15 @@ class GPS { | |||||
} | } | ||||
return image_code; | 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) { | private byte[] _get_coordinates (byte[] stream) { | ||||
int start = Com.detect(stream, "GPGGA".getBytes(), stream.length); | int start = Com.detect(stream, "GPGGA".getBytes(), stream.length); | ||||
double latitude = _nmea2dec (Double.valueOf( | double latitude = _nmea2dec (Double.valueOf( | ||||
@@ -95,10 +129,15 @@ class GPS { | |||||
- coordinates_[4]/60.0)*3600); // latitude " | - coordinates_[4]/60.0)*3600); // latitude " | ||||
return coordinates_; | return coordinates_; | ||||
} | } | ||||
/** | |||||
* A helper to convert the NMEA format to canonical | |||||
* decimal coordinate format | |||||
*/ | |||||
double _nmea2dec (double c) { | double _nmea2dec (double c) { | ||||
int d = (int)c/100; | int d = (int)c/100; | ||||
c -= d*100; | c -= d*100; | ||||
return d + (c/60); | return d + (c/60); | ||||
} | } | ||||
/** @} */ | |||||
} | } |
@@ -1,30 +1,59 @@ | |||||
/** | |||||
* @file Image.java | |||||
* | |||||
* @author Christos Choutouridis AEM:8997 | |||||
* @email cchoutou@ece.auth.gr | |||||
*/ | |||||
package net.hoo2.auth.vmodem; | package net.hoo2.auth.vmodem; | ||||
/** @name imports */ | |||||
/** @{ */ | |||||
import java.io.*; | import java.io.*; | ||||
/** @} */ | |||||
/** | |||||
* @class Image | |||||
* | |||||
* Class to used for the error free and non error free image requests | |||||
*/ | |||||
class Image { | class Image { | ||||
static final int IMAGE_BUFFER_SIZE = 256*1024; | |||||
static final byte[] IMAGE_BEGIN = {(byte)0xFF, (byte)0xD8}; | |||||
static final byte[] IMAGE_END = {(byte)0xFF, (byte)0xD9}; | |||||
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_; | |||||
private Log log_; | |||||
private Transaction transaction_; | |||||
private String filename_; | |||||
private int items_; | |||||
private byte[] code_; | |||||
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) { | Image (Com com, Log log, byte[] code, String filename, int items) { | ||||
com_ = com; | com_ = com; | ||||
log_ = log; | log_ = log; | ||||
// Allocate memory for the response | |||||
transaction_= new Transaction(null, new byte[IMAGE_BUFFER_SIZE]); | transaction_= new Transaction(null, new byte[IMAGE_BUFFER_SIZE]); | ||||
filename_ = filename; | filename_ = filename; | ||||
items_ = items; | items_ = items; | ||||
code_ = code; | code_ = code; | ||||
} | } | ||||
/** Get function for the code */ | |||||
void code (byte[] code) { code_ = 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) { | void caption (byte[] code) { | ||||
String line; | String line; | ||||
@@ -35,12 +64,17 @@ class Image { | |||||
line = new String(transaction_.getResponse()); | line = new String(transaction_.getResponse()); | ||||
log_.out(line); | log_.out(line); | ||||
} | } | ||||
/** | |||||
* Main transaction loop. It send requests to server, get the response | |||||
* and log the procedure while doing it. | |||||
*/ | |||||
void run () { | void run () { | ||||
String file, line; | String file, line; | ||||
BufferedOutputStream ostream; | BufferedOutputStream ostream; | ||||
for (int i =1 ; i<= items_ ; ++i) { | for (int i =1 ; i<= items_ ; ++i) { | ||||
// Make the filename string | |||||
if (items_>1) | if (items_>1) | ||||
file = filename_ + "_" + i + ".jpg"; | file = filename_ + "_" + i + ".jpg"; | ||||
else | else | ||||
@@ -1,19 +1,42 @@ | |||||
/** | |||||
* @file Log.java | |||||
* | |||||
* @author Christos Choutouridis AEM:8997 | |||||
* @email cchoutou@ece.auth.gr | |||||
*/ | |||||
package net.hoo2.auth.vmodem; | package net.hoo2.auth.vmodem; | ||||
/** @name imports */ | |||||
/** @{ */ | |||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.PrintWriter; | import java.io.PrintWriter; | ||||
/** @} */ | |||||
/** | |||||
* @class Log | |||||
* | |||||
* A common log functionality class for all sessions | |||||
*/ | |||||
class Log { | class Log { | ||||
private String logfile_; | |||||
private boolean verbose_; | |||||
private PrintWriter writer_; | |||||
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) { | Log (String logfile, boolean verbose) { | ||||
logfile_ = logfile; | logfile_ = logfile; | ||||
verbose_ = verbose; | verbose_ = verbose; | ||||
} | } | ||||
/** | |||||
* Try to open the log file | |||||
* @return The status of the operation | |||||
*/ | |||||
boolean open () { | boolean open () { | ||||
if (logfile_ != null) { | if (logfile_ != null) { | ||||
try { | try { | ||||
@@ -26,11 +49,20 @@ class Log { | |||||
} | } | ||||
return true; | 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) { | boolean open (String logfile) { | ||||
logfile_ = logfile; | logfile_ = logfile; | ||||
return open(); | return open(); | ||||
} | } | ||||
/** | |||||
* Close the opened file | |||||
* @return The status of the operation | |||||
*/ | |||||
boolean close () { | boolean close () { | ||||
try { | try { | ||||
if (writer_ != null) | if (writer_ != null) | ||||
@@ -40,17 +72,30 @@ class Log { | |||||
} | } | ||||
return true; | 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) { | void write (String line, boolean out) { | ||||
if (logfile_ != null) writer_.println(line); | if (logfile_ != null) writer_.println(line); | ||||
if (verbose_ || out) System.out.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) { | void write (String line) { | ||||
if (logfile_ != null) writer_.println(line); | if (logfile_ != null) writer_.println(line); | ||||
if (verbose_) System.out.println(line); | if (verbose_) System.out.println(line); | ||||
} | } | ||||
/** | |||||
* Echo the line to console | |||||
* @param line The line to print | |||||
*/ | |||||
void out (String line) { | void out (String line) { | ||||
if (verbose_) System.out.println(line); | if (verbose_) System.out.println(line); | ||||
} | } | ||||
@@ -10,7 +10,7 @@ package net.hoo2.auth.vmodem; | |||||
/** @name imports */ | /** @name imports */ | ||||
/** @{ */ | /** @{ */ | ||||
import org.apache.commons.cli.*; | |||||
import org.apache.commons.cli.*; /**< command line utility */ | |||||
/** @} */ | /** @} */ | ||||
@@ -19,31 +19,35 @@ import org.apache.commons.cli.*; | |||||
* | * | ||||
* @brief This is the main control class of the program. | * @brief This is the main control class of the program. | ||||
* | * | ||||
* This class includes the main function.Using this class's api | |||||
* the user can ... | |||||
* This class includes the main function which read the user input | |||||
* and create the apropriate object for the requested sequence to | |||||
* retrieve data. | |||||
*/ | */ | ||||
public class VirtualModem { | public class VirtualModem { | ||||
/** @name Data */ | /** @name Data */ | ||||
/** @{ */ | /** @{ */ | ||||
CommandLine line; | |||||
CommandLineParser parser; | |||||
Options options; | |||||
HelpFormatter formatter; | |||||
Com com; | |||||
Log log; | |||||
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 basig logging module */ | |||||
/** @} */ | /** @} */ | ||||
/** @name constructors */ | |||||
/** @{ */ | |||||
/** | |||||
* @brief The main constructor of the class | |||||
* We allocate memory for the data needed for the command line | |||||
*/ | |||||
public VirtualModem () { | public VirtualModem () { | ||||
parser = new DefaultParser(); | parser = new DefaultParser(); | ||||
options = new Options(); | options = new Options(); | ||||
formatter = new HelpFormatter(); | formatter = new HelpFormatter(); | ||||
com = new Com(); | com = new Com(); | ||||
Option verb = new Option ("v", "verbose", false, "Be more verbose"); | |||||
// 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 help = new Option ("h", "help", false, "Print this message"); | ||||
Option timeout = Option.builder("t") | Option timeout = Option.builder("t") | ||||
.longOpt("timeout") | .longOpt("timeout") | ||||
@@ -60,27 +64,40 @@ public class VirtualModem { | |||||
Option log = Option.builder("l") | Option log = Option.builder("l") | ||||
.longOpt("log") | .longOpt("log") | ||||
.hasArg() | .hasArg() | ||||
.desc("Log file name") | |||||
.desc("Log file name to use") | |||||
.build(); | .build(); | ||||
Option echo = Option.builder("e") | Option echo = Option.builder("e") | ||||
.longOpt("echo") | .longOpt("echo") | ||||
.numberOfArgs(2) | .numberOfArgs(2) | ||||
.desc ("Request echo sequence") | |||||
.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(); | .build(); | ||||
Option aqr = Option.builder("a") | Option aqr = Option.builder("a") | ||||
.longOpt("aqr") | .longOpt("aqr") | ||||
.numberOfArgs(3) | .numberOfArgs(3) | ||||
.desc ("Request aqr sequence") | |||||
.desc ("Request aqr 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(); | .build(); | ||||
Option img = Option.builder("g") | Option img = Option.builder("g") | ||||
.longOpt("img") | .longOpt("img") | ||||
.numberOfArgs(3) | .numberOfArgs(3) | ||||
.desc("Request an image sequence") | |||||
.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(); | .build(); | ||||
Option gps = Option.builder("p") | Option gps = Option.builder("p") | ||||
.longOpt("gps") | .longOpt("gps") | ||||
.numberOfArgs(5) | |||||
.desc("Request a GPS sequence") | |||||
.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(); | .build(); | ||||
options.addOption(verb); | options.addOption(verb); | ||||
options.addOption(help); | options.addOption(help); | ||||
@@ -92,8 +109,15 @@ public class VirtualModem { | |||||
options.addOption(img); | options.addOption(img); | ||||
options.addOption(gps); | 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) { | private boolean getCmdOptions (String[] args) { | ||||
try { | try { | ||||
// parse the command line arguments | // parse the command line arguments | ||||
@@ -106,10 +130,19 @@ public class VirtualModem { | |||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
/** | |||||
* Dispatch the correct functionality based on arguments | |||||
* @return the status of the operation (currently true) | |||||
*/ | |||||
private boolean commandDispatcher () { | private boolean commandDispatcher () { | ||||
boolean verbose = false; | boolean verbose = false; | ||||
if (line.hasOption("help")) { | |||||
formatter.printHelp( "virtualModem", options ); | |||||
return true; | |||||
} | |||||
// Get log and verbose options first | // Get log and verbose options first | ||||
if (line.hasOption("verbose")) | if (line.hasOption("verbose")) | ||||
verbose = true; | verbose = true; | ||||
@@ -129,68 +162,64 @@ public class VirtualModem { | |||||
} | } | ||||
// Execution dispatcher | // Execution dispatcher | ||||
do { | |||||
if (line.hasOption("help")) { | |||||
formatter.printHelp( "virtualModem", options ); | |||||
break; | |||||
} | |||||
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(); | |||||
} | |||||
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("aqr")) { | |||||
byte[] ack = line.getOptionValues("aqr")[0].getBytes(); | |||||
byte[] nack = line.getOptionValues("aqr")[1].getBytes(); | |||||
AQR a = new AQR(com, log, ack, nack, | |||||
Integer.valueOf(line.getOptionValues("aqr")[2])); | |||||
if (com.open()) { | |||||
a.caption(ack, nack); | |||||
a.run(); | |||||
com.close(); | |||||
} | |||||
} | |||||
else if (line.hasOption("aqr")) { | |||||
byte[] ack = line.getOptionValues("aqr")[0].getBytes(); | |||||
byte[] nack = line.getOptionValues("aqr")[1].getBytes(); | |||||
AQR a = new AQR(com, log, ack, nack, | |||||
Integer.valueOf(line.getOptionValues("aqr")[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("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(); | |||||
} | |||||
} | |||||
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(); | |||||
} | } | ||||
} while (false); | |||||
} | |||||
log.close(); | log.close(); | ||||
return true; | return true; | ||||
} | } | ||||
/**@}*/ | |||||
/** | /** | ||||
* @brief Main | |||||
* | |||||
* @brief Main function | |||||
*/ | */ | ||||
public static void main(String[] args) { | public static void main(String[] args) { | ||||
// allocate the main object | // allocate the main object | ||||
@@ -199,9 +228,8 @@ public class VirtualModem { | |||||
// prepare command line input | // prepare command line input | ||||
if (vmodem.getCmdOptions (args) != true) | if (vmodem.getCmdOptions (args) != true) | ||||
return; | return; | ||||
// Call the requested functionality | |||||
if (vmodem.commandDispatcher() != true) | if (vmodem.commandDispatcher() != true) | ||||
return; | return; | ||||
} | } | ||||
} | } |