javAPRS
Home Page

Mic-E Parser


    private Report parseMic (Report theReport, int infoIndex, String theString)
    {
        int i = infoIndex, j, k;
        // theReport is a structure with fields
        // for parts of a packet
        theReport.reportType = "Mic";
        
        // theReport.theData is the packet received
        String toField = theReport.toField;
        int lastdash = toField.lastIndexOf('-');
        if (lastdash == 6)
            toField = toField.substring(0, lastdash);
        else if (lastdash >= 0)
            return null;
        if (toField.length() != 6) return null;
        
        // Get message and validate to field
        int micmsg = 0;
        for (j = 0; j < 3; j++)
        {
            micmsg <<= 1;
            micmsg |= getMessageBit(toField, j);
            if (micmsg == -1) return null;
        }
        if (micmsg > 7)
        {
            // Custom message
            micmsg &= 0x07;
            micmsg |= 0x08;
        }
        for (; j < 6; j++)
        {
            if (!isValidDest(toField.charAt(j))) return null;
        }
        
        // Parse the "TO" field
        int c = cnvtDest(toField.charAt(0));
        int d = (c & 0xf) * 10;
        // Degrees
        c = cnvtDest(toField.charAt(1));
        d += (c & 0xf);
        c = cnvtDest(toField.charAt(2));
        int m = (c & 0xf) * 10;
        // Minutes
        c = cnvtDest(toField.charAt(3));
        boolean north = (c >= 0x20);
        m += (c & 0xf);
        c = cnvtDest(toField.charAt(4));
        boolean hund = (c >= 0x20);
        int s = (c & 0xf) * 10;
        // Hundredths of minutes
        c = cnvtDest(toField.charAt(5));
        boolean west = (c >= 0x20);
        s += (c & 0xf);
        theReport.position.lat = d + m / 60.0 + s / 6000.0;
        // javAPRS stores southern latitudes as negative
        if (!north) theReport.position.lat *= -1.0;
        
        // Parse the Icon
        theReport.icon = theString.charAt(i + 7) - ' ';
        char ch = theString.charAt(i + 8);
        theReport.altIcons = (ch != '/');
        if (isLetterOrDigit(ch)) theReport.overlay = ch - ' ';
        
        // Parse the longitude
        d = theString.charAt(i + 1) - 28;
        m = theString.charAt(i + 2) - 28;
        s = theString.charAt(i + 3) - 28;
        if (d < 0 || d > 99 || m < 0 || m > 99 || s < 0 || s > 99) return null;
        // Adjust the degrees value
        if (hund) d += 100;
        if (d >= 190)
            d -= 190;
        else if (d >= 180)
            d -= 80;
        
        // Adjust minutes 0-9 to proper spot
        if (m >= 60) m -= 60;
        theReport.position.lon = d + m / 60.0 + s / 6000.0;
        if (west) theReport.position.lon *= -1.0;
        
        // Parse the Speed/Course (s/d)
        m = theString.charAt(i + 5) - 28;
        // DC+28
        if (m < 0 || m > 97) return null;
        s = theString.charAt(i + 4) - 28;
        if (s < 0 || s > 99) return null;
        s = (s * 10) + (m / 10);
        
        //Speed (Knots)
        d = theString.charAt(i + 6) - 28;
        if (d < 0 || d > 99) return null;
        d = ((m % 10) * 100) + d;
        
        // Course
        // Specification decoding method
        if (s >= 800) s -= 800;
        if (d >= 400) d -= 400;
        if (d > 0)
        {
            theReport.course = d;
            theReport.speed = s;
        }
        theReport.MicEInfo = MicEMsgs[micmsg];
        if (theString.length() > i + 9)
        {
            theReport.comments = i + 9;
            // Look for altitude
            j = theString.indexOf('}', theReport.comments);
            if (j >= theReport.comments + 3)
            theReport.altitude = (int) Math.round(((((((theString.charAt(j - 3) - 33) * 91) + (theString.charAt(j - 2) - 33)) * 91) + (theString.charAt(j - 1) - 33)) - 10000) * 3.28084);
            switch (theReport.theData[i])
            {
            case (byte) '\'':
                if (theString.charAt(i + 9) == ']')
                {
                    theReport.MicEInfo += " D700";
                    break;
                }
            case (byte) '`':
                if (theString.charAt(i + 9) == '>')
                    theReport.MicEInfo += " D7";
            }
        }
        return theReport;
    }

    protected final static String MicEMsgs[] = {"EMERGENCY",
                                                "Priority",
                                                "Special",
                                                "Committed",
                                                "Returning",
                                                "In Service",
                                                "En Route",
                                                "Off Duty",
                                                "",
                                                "Custom 6",
                                                "Custom 5",
                                                "Custom 4",
                                                "Custom 3",
                                                "Custom 2",
                                                "Custom 1",
                                                "Custom 0"};

    protected final int getMessageBit(String toField, int index)
    {
        char testchar = toField.charAt(index);
        if ((testchar >= '0' && testchar <= '9') || testchar == 'L') return 0;
        if (testchar >= 'A' && testchar <= 'K') return 9;
        if (testchar >= 'P' && testchar <= 'Z') return 1;
        return -1;
    }

    protected final boolean isValidDest(char testchar)
    {
        return ((testchar >= '0' && testchar <= '9') || testchar == 'L' || (testchar >= 'P' && testchar <= 'Z'));
    }