Package jaid.ais.message

Source Code of jaid.ais.message.AISMsg

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package jaid.ais.message;

import exception.InvalidPositionException;
import java.util.Calendar;
import nav.position.Position;
import nav.util.string.StringUtil;


/**
* Represents an AIS message. Superclass to the various AIS message types.
* See ITU-R M.1371-3 for information.
*
* @author Benjamin Jakobus
* @since 1.0
*/
public class AISMsg {
    /* A constant denoting that a field/attribute is unknown */
    public final static int UNKNOWN = -1;

    /* A constant denoting that the origin of this message cannot contain a
     * diven attribute.
     */
    public final static int NOT_AVAILABLE = -2;

    /* The vessel's name. */
    private String name;

    /* Message type. */
    private int messageType;

    /* Message repeat indicator. */
    private int repeatIndicator;

    /* Message time stamp. */
    private long timestamp;

    /* Message time stamp. */
    private String timestampStr;

    /* Entity MMSI. */
    private String mmsi;

    /* Type of EPFS in use. */
    private String epfs;

    /* Position Accuracy. */
    private String posAccuracy;

    /* Positio.n */
    private Position position;

    /* Length/width dimensions - see ITU-1371-3, fig. 44 for explanation. */
    int a;
    int b;
    int c;
    int d;

    private static final int CLOCK_JITTER = 2;

    /* Initialize dimension parameters to default of -1. */
    { a = -1; b = -1; c = -1; d = -1; name = null; }

    /**
     * Decodes the vessel's name.
     *
     * @param input             A raw AIS data feed.
     * @since 1.0
     */
    public void decodeName(String input) {
        name = decode6BitBinary(input);
    }

    public float getMaxDraft() {
        return -1;
    }

    /**
     * Decodes the entity's position.
     *
     * @param input             A raw AIS data feed.
     * @since 1.0
     */
    public void decodePosition(String input) {
        // Longitude (0-29)
        float lng = extractPosition(input.substring(0, 28));
        // Latitude (29-116)
        float lat = extractPosition(input.substring(28));

        // Init the position vessel's position
        try {
            position = new Position(lat, lng);
        } catch (InvalidPositionException ipe) {
            try {
                position = new Position(0, 0);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Decode the target's heading.
     *
     * @param input         A raw AIS data feed.
     * @return heading      The target's heading.
     * @since 1.0
     */
    public String decodeHdg(int input) {
        String output = "";
        StringUtil u = new StringUtil();

        if (input == 511) {
            output = "n/a";
        } else {
            output = String.valueOf(u.padNumZero(input, 3));
        }

        return output;
    }

    /**
     * Converts a 6-bit binary string into and 8-bit ASCII string.
     *
     * @param input         6-bit binary string
     * @return              8-bit ASCII string.
     * @since 1.0
     */
    public String decode6BitBinary(String input) {
        String output = "";
        int loop = input.length() / 6;
        for (int i = 0; i < loop; i++) {
            // Avoid trailing @ in ASCII strings
            String char6 = input.substring(0, 6);
            if (char6.compareTo("000000") == 0) {
                break;
            }
            input = input.substring(6);
            int asciiNum = bin2int(char6);
            // 6 bit binary to 8 bit binary conversion
            if (asciiNum < 32) {
                asciiNum += 64;
            }
            output += (char) asciiNum;
        }
        return output.trim();
    }

    /**
     * Returns the AID type if the sender is a base station
     * Overridden by children.
     *
     * @return              AID type
     * @since 1.0
     */
    public String getAidType() {
        return "NA";
    }

    /**
     * Decodes the EPFS type data.
     *
     * @param input         A raw AIS data feed.
     * @since 1.0
     */
    public void decodeEPFSType(String input) {
        switch (Integer.parseInt(input, 2)) {
            case 0:
                epfs = "Undefined";
                break;
            case 1:
                epfs = "GPS";
                break;
            case 2:
                epfs = "GLONASS";
                break;
            case 3:
                epfs = "GPS+GLONASS";
                break;
            case 4:
                epfs = "Loran-C";
                break;
            case 5:
                epfs = "Chayka";
                break;
            case 6:
                epfs = "INS";
                break;
            case 7:
                epfs = "Surveyed";
                break;
            case 8:
                epfs = "GALILEO";
                break;
            default:
                epfs = "?: " + Integer.parseInt(input, 2);
        }
    }

    /**
     * Decodes the EPFS position accuracy.
     *
     * @param input         A raw AIS data feed.
     * @since 1.0
     */
    public void decodePosAccuracy(String input) {
        switch (Integer.parseInt(input, 2)) {
            case 0:
                posAccuracy = "Low";
                break;
            case 1:
                posAccuracy = "High";
                break;
            default:
                posAccuracy = Integer.parseInt(input, 2) + ": ??";
        }
    }

    /**
     * Decodes the vessel dimensions and EPFS sensor position data.
     *
     * @param input         A raw AIS data feed.
     * @since 1.0
     */
    public void decodeEntityDimensions(String input) {
        a = Integer.parseInt(input.substring(0, 9), 2);
        input = input.substring(9);
        b = Integer.parseInt(input.substring(0, 9), 2);
        input = input.substring(9);
        c = Integer.parseInt(input.substring(0, 6), 2);
        input = input.substring(6);
        d = Integer.parseInt(input.substring(0, 6), 2);
    }

    /**
     * Decodes a time stamp and converts it to a full hh:mm:ss stamp
     * To allow for processing delay that may result in the wrong
     * minute being assigned - i.e. the next minute instead of the previous,
     * I do some 'jitter' checking. This problem occurs because the AIS
     * system assumes all equipment involved is UTC locked.
     *
     * @param input         A raw AIS data feed.
     * @since 1.0
     */
    public void decodeTimeStamp(String input) {
        Calendar cal = Calendar.getInstance();
        //determine UTC time - time zone & DST conversion
        cal.add(
                Calendar.MILLISECOND,
                -cal.get(Calendar.DST_OFFSET)
                - cal.get(Calendar.ZONE_OFFSET));

        int hoursNow = cal.get(Calendar.HOUR_OF_DAY);
        int minsNow = cal.get(Calendar.MINUTE);
        int secsNow = cal.get(Calendar.SECOND);

        StringUtil su = new StringUtil();

        /* AIS seconds - assumes 'current' minute... due network &
         * processing delays, it may in fact be the previous minute
         * as we're not GPS hardware time synchronised...
         */
        int aisSecs = Integer.parseInt(input, 2);

        switch (aisSecs) {
            case 60:
                timestampStr = "Not Available";
                break;
            case 61:
                timestampStr = "EPFS manual";
                break;
            case 62:
                timestampStr = "EPFS DR";
                break;
            case 63:
                timestampStr = "EPFS U/S";
                break;
            default:
                /* Do a simple check to see if it was 'probably' the previous
                 * minute... if so, correct the display time. NOTE: the PC
                 * system clock needs to be pretty close to UTC (within 1-2s)
                 * for this to work - clock synchronisation is needed regularly!
                 */
                if ((minsNow * 60) + secsNow + CLOCK_JITTER < (minsNow * 60) + aisSecs) {
                    switch (minsNow) {
                        case 0:
                            minsNow = 59;
                            switch (hoursNow) {
                                case 0:
                                    hoursNow = 23;
                                    break;
                                default:
                                    hoursNow -= 1;
                            }
                            break;
                        default:
                            minsNow -= 1;
                    }
                }
                // Set the calendar time to the AIS message received time - in UTC
                cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH),
                        cal.get(Calendar.DAY_OF_MONTH), hoursNow, minsNow, aisSecs);
                //Store this as the last update time
                timestamp = cal.getTimeInMillis();

                Calendar newCal = Calendar.getInstance();

                // Current system time in UTC
                newCal.add(
                        Calendar.MILLISECOND,
                        -newCal.get(Calendar.DST_OFFSET)
                        - newCal.get(Calendar.ZONE_OFFSET));

                // build a string representation of the message time...
                timestampStr = String.valueOf(su.padNumZero(hoursNow, 2))
                        + ":" + String.valueOf(su.padNumZero(minsNow, 2))
                        + ":" + String.valueOf(su.padNumZero(aisSecs, 2));
        }
    }

    /**
     * Returns the sender's MMSI.
     *
     * @return mmsi         The sender's MMSI number.
     * @since 1.0
     */
    public String getMMSI() {
        return mmsi;
    }

    /**
     * Returns the sender's name.
     *
     * @return name         The sender's name.
     * @since 1.0
     */
    public String getName() {
        return name;
    }

    /**
     * Returns the message's type.
     * See ITU-R M.1371-3 for details.
     *
     * @return              The message type. See ITU-R M.1371-3 for details.
     * @since 1.0
     */
    public int getMsgType() {
        return messageType;
    }

    /**
     * Returns the sender's position accuracy.
     *
     * @return              The sender's position accuracy.
     * @since 1.0
     */
    public String getPosAccuracy() {
        return posAccuracy;
    }

    /**
     * Returns the sender's destination. Overriden by children.
     *
     * @return              Destination or "Unknown" if not known.
     * @since 1.0
     */
    public String getDestination() {
        return "unknown";
    }

    /**
     * Returns the sender's position.
     *
     * @return              The sender's position.
     * @since 1.0
     */
    public Position getPosition() {
        return position;
    }

    /**
     * Returns the message's timestamp.
     *
     * @return              Timestamp of when the message was generated.
     * @since 1.0
     */
    public String getUtcTimeStampStr() {
        return timestampStr;
    }

    /**
     * Returns the mesage's timestamp in milliseconds.
     *
     * @return timestamp    Timestamp (in milliseconds) of when the message was generated.
     * @since 1.0
     */
    public long getUtcTimeStamp() {
        return timestamp;
    }

    /**
     * Returns the message's repeat indicator.
     *
     * @return              Repeat indicator
     * @since 1.0
     */
    public int getRepeatIndicator() {
        return repeatIndicator;
    }

    /**
     * Sets the repeat indicator.
     *
     * @param repeatIndicator       The message's repeat indicator.
     * @since 1.0
     */
    public void setRepeatIndicator(int repeatIndicator) {
        this.repeatIndicator = repeatIndicator;
    }

    /**
     * Sets the message type.
     * See ITU-R M.1371-3 for message types.
     *
     * @param messageType           The message type.
     * @since 1.0
     */
    public void setMessageType(int messageType) {
        this.messageType = messageType;
    }

    /**
     * Sets the sender's MMSI.
     *
     * @param mmsi                  The sender's MMSI number.
     * @since 1.0
     */
    public void setMmsi(String mmsi) {
        this.mmsi = mmsi;
    }

    /**
     * Prints the message contents.
     *
     * @return
     * @since 1.0
     */
    public String print() {
        return "";
    }

    /**
     * Decodes the sender's position.
     *
     * @param sgnBinNum             The string contained the sender's encoded position.
     * @return                      The sender's position
     * @since 1.0
     */
    private float extractPosition(String sgnBinNum) {
        //convert binary string into int array for ease of manipulation
        if (sgnBinNum.substring(0, 1).compareTo("1") == 0) {
            sgnBinNum = twosCompliment(sgnBinNum);
            return -((float) Integer.parseInt(sgnBinNum, 2)) / 600000;
        } else {
            return ((float) Integer.parseInt(sgnBinNum, 2)) / 600000;
        }
    }

    /**
     * Processes 2's compliment.
     *
     * @param input                 Binary string presented using two's compliment.
     * @return                      Decoded two's complement.
     * @since 1.0
     */
    public static String twosCompliment(String input) {
        char[] bits = input.toCharArray();
        String compliment = "";
        int i;
        for (i = bits.length - 1; i >= 0; i--) {
            if (bits[i] == '0') {
                //copy '0's unchanged
                compliment = bits[i] + compliment;
            } else {
                //we've found our first 1 - game changes
                compliment = bits[i] + compliment;
                break;
            }
        }
        //flip all remaining bits...
        for (int j = i - 1; j >= 0; j--) {
            switch (bits[j]) {
                case '1':
                    compliment = "0" + compliment;
                    break;
                case '0':
                    compliment = "1" + compliment;
            }
        }
        return compliment;
    }

    /**
     * Returns the target's A-dimension. A target's A-dimension is the distance
     * (in meters) between the the target's GPS antenna and its bow.
     *
     * @return          The target's A dimension. Measured in meters.
     * @since 1.0
     */
    public int getA() {
        return a;
    }

    /**
     * Returns the target's B-dimension. A target's B-dimension is the distance
     * (in meters) between the the target's GPS antenna and its back.
     *
     * @return      The target's B dimension. Measured in meters.
     * @since 1.0
     */
    public int getB() {
        return b;
    }

    /**
     * Returns the target's C-dimension. A target's C-dimension is the distance
     * (in meters) between the the target's GPS antenna and its left side.
     *
     * @return      The target's C dimension. Measured in meters.
     * @since 1.0
     */
    public int getC() {
        return c;
    }

    /**
     * Returns the target's D-dimension. A target's D-dimension is the distance
     * (in meters) between the the target's GPS antenna and its right side.
     *
     * @return      The target's D dimension. Measured in meters.
     * @since 1.0
     */
    public int getD() {
        return d;
    }

    /**
     * Returns the sender's EPFS
     * @return the EPFS
     * @since 1.0
     */
    public String getEpfs() {
        return epfs;
    }

    /**
     * Sets the message's timestamp as Unix time
     * @param timestamp
     * @since 1.0
     */
    public void setTimestamp(long timestamp) {
        this.timestamp = timestamp;
    }

    /**
     * Sets the message's timestamp in string format
     * @param timestampStr
     * @since 1.0
     */
    public void setTimestampStr(String timestampStr) {
        this.timestampStr = timestampStr;
    }

    /**
     * Returns the sender's navigational status
     * @return the nav status or "unknown" if it is not known
     * @since 1.0
     */
    public String getNavStatus() {
        return "unknown";
    }

    /**
     * Returns the sender's speed. Overriden by children.
     * @return the speed or "unknown" if it is not known
     * @since 1.0
     */
    public float getSpeed() {
        return UNKNOWN;
    }

    /**
     * Returns the sender's course. Overriden by children.
     * @return the course or "unknown" if it is not known
     * @since 1.0
     */
    public int getCourse() {
        return UNKNOWN;
    }

    /**
     * Returns the sender's heading. Overriden by children.
     * @return the heading or "unknown" if it is not known
     * @since 1.0
     */
    public int getHeading() {
        return UNKNOWN;
    }

    /**
     * Returns the sender's Expected Time of Arrival (ETA)
     * Overriden by children.
     * @return the ETA or unknown if it is not known
     * @since 1.0
     */
    public String getEta() {
        return "unknown";
    }

    /**
     * Returns the type of cargo that the message sender is carrying.
     * Overriden by children.
     *
     * @return the cargo type or unknown if it is not known
     * @since 1.0
     */
    public String getCargoType() {
        return "unknown";
    }

    /**
     * Converts a binary integer string into an integer.
     *
     * @param str
     * @return
     * @since 1.0
     */
    private int bin2int(String str) {
        return (Integer.parseInt(str, 2));
    }
}
TOP

Related Classes of jaid.ais.message.AISMsg

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.