Example #1
0
func DecodeCompressedPositionReport(c string) (geospatial.Point, rune, rune, string, error) {
	// Example:    =/5L!!<*e7OS]S

	var err error
	var matches []string

	p := geospatial.Point{}

	pr := regexp.MustCompile(`[=!]([\\\/])(.{4})(.{4})(.)(..)(.)(.*)$`)

	remains := pr.ReplaceAllString(c, "")

	p.Time = time.Now()

	if matches = pr.FindStringSubmatch(c); len(matches) > 0 {

		if len(matches[7]) > 0 {
			remains = matches[7]
		}

		symTable := rune(matches[1][0])
		symCode := rune(matches[4][0])

		p.Lat, err = DecodeBase91Lat([]byte(matches[2]))
		if err != nil {
			return p, ' ', ' ', remains, fmt.Errorf("Could not decode compressed latitude: %v\n", err)
		}

		p.Lon, err = DecodeBase91Lon([]byte(matches[3]))
		if err != nil {
			return p, ' ', ' ', remains, fmt.Errorf("Could not decode compressed longitude: %v\n", err)
		}

		// A space in this position indicates that the report includes no altitude, speed/course, or radio range.
		if matches[5][0] != ' ' {

			// First we look at the Compression Byte ("T" in the spec) and check for a GGA NMEA source.
			// If the GGA bits are set, we decode an altitude reading.  Otherwise, try to decode a course/
			// speed reading or a radio range reading
			if (byte(matches[6][0])-33)&0x18 == 0x10 {
				// This report has an encoded altitude reading
				p.Altitude, err = DecodeBase91Altitude([]byte(matches[5]))
				if err != nil {
					return p, ' ', ' ', remains, fmt.Errorf("Could not decode compressed altitude: %v\n", err)
				}
			} else if (byte(matches[5][0])-33) >= 0 && (byte(matches[5][0])-33) <= 89 {
				p.Heading, p.Speed, err = DecodeBase91CourseSpeed([]byte(matches[5]))
			} else if matches[5][0] == '{' {
				p.RadioRange = DecodeBase91RadioRange(byte(matches[5][1]))
			}
		}

		return p, symTable, symCode, remains, nil

	}
	return p, ' ', ' ', remains, nil
}
Example #2
0
func DecodeUncompressedPositionReportWithTimestamp(c string) (geospatial.Point, rune, rune, string, error) {
	// Example:   @092345z4903.50N/07201.75W>

	var matches []string
	p := geospatial.Point{}

	if len(c) >= 27 {

		pr := regexp.MustCompile(`([\/\@])(\d{6})(.)([\d\.\s]{7})([NSns])(.)([\d\.\s]{8})([EWew])(.)(.*)$`)

		remains := pr.ReplaceAllString(c, "")

		if matches = pr.FindStringSubmatch(c); len(matches) > 0 {

			if len(matches[10]) > 0 {
				remains = matches[10]
			}

			if matches[1][0] == '@' {
				p.MessageCapable = true
			}

			switch matches[3][0] {
			case 'z':
				day, _ := strconv.ParseInt(matches[2][0:2], 10, 0)
				hours, _ := strconv.ParseInt(matches[2][2:4], 10, 0)
				minutes, _ := strconv.ParseInt(matches[2][4:6], 10, 0)
				now := time.Now()
				p.Time = time.Date(now.Year(), now.Month(), int(day), int(hours), int(minutes), 0, 0, time.UTC)
			case '/':
				day, _ := strconv.ParseInt(matches[2][0:2], 10, 0)
				hours, _ := strconv.ParseInt(matches[2][2:4], 10, 0)
				minutes, _ := strconv.ParseInt(matches[2][4:6], 10, 0)
				now := time.Now()
				p.Time = time.Date(now.Year(), now.Month(), int(day), int(hours), int(minutes), 0, 0, time.Local)
			case 'h':
				hours, _ := strconv.ParseInt(matches[2][0:2], 10, 0)
				minutes, _ := strconv.ParseInt(matches[2][2:4], 10, 0)
				seconds, _ := strconv.ParseInt(matches[2][4:6], 10, 0)
				now := time.Now()
				p.Time = time.Date(now.Year(), now.Month(), now.Day(), int(hours), int(minutes), int(seconds), 0, time.UTC)
			default:
				p.Time = time.Now()
			}

			symTable := rune(matches[6][0])
			symCode := rune(matches[9][0])

			la1, err := strconv.ParseFloat(matches[4][0:2], 64)
			if err != nil {
				return p, symTable, symCode, remains, err
			}
			la2, err := strconv.ParseFloat(matches[4][2:7], 64)
			if err != nil {
				return p, symTable, symCode, remains, err
			}

			lat := la1 + la2/60
			if matches[5][0] == 'S' {
				lat = 0 - lat
			}

			lo1, err := strconv.ParseFloat(matches[7][0:3], 64)
			if err != nil {
				return p, symTable, symCode, remains, err
			}
			lo2, err := strconv.ParseFloat(matches[7][3:8], 64)
			if err != nil {
				return p, symTable, symCode, remains, err
			}

			lon := lo1 + lo2/60

			if matches[8][0] == 'W' {
				lon = 0 - lon
			}

			p.Lat = lat
			p.Lon = lon

			return p, symTable, symCode, remains, nil

		}

	}

	return p, ' ', ' ', c, nil

}
Example #3
0
func DecodeUncompressedPositionReportWithoutTimestamp(c string) (geospatial.Point, rune, rune, string, error) {
	// Example:   !4903.50N/07201.75W-

	var matches []string
	p := geospatial.Point{}

	if len(c) >= 20 {

		pr := regexp.MustCompile(`([\=\!])([\d\.\s]{7})([NSns])(.)([\d\.\s]{8})([EWew])(.)(.*)$`)

		remains := pr.ReplaceAllString(c, "")

		p.Time = time.Now()

		if matches = pr.FindStringSubmatch(c); len(matches) > 0 {

			if len(matches[8]) > 0 {
				remains = matches[8]
			}

			if matches[1][0] == '=' {
				p.MessageCapable = true
			}

			symTable := rune(matches[4][0])
			symCode := rune(matches[7][0])

			la1, err := strconv.ParseFloat(matches[2][0:2], 64)
			if err != nil {
				return p, symTable, symCode, remains, err
			}
			la2, err := strconv.ParseFloat(matches[2][2:7], 64)
			if err != nil {
				return p, symTable, symCode, remains, err
			}

			lat := la1 + la2/60
			if matches[3][0] == 'S' {
				lat = 0 - lat
			}

			lo1, err := strconv.ParseFloat(matches[5][0:3], 64)
			if err != nil {
				return p, symTable, symCode, remains, err
			}
			lo2, err := strconv.ParseFloat(matches[5][3:8], 64)
			if err != nil {
				return p, symTable, symCode, remains, err
			}

			lon := lo1 + lo2/60

			if matches[6][0] == 'W' {
				lon = 0 - lon
			}

			p.Lat = lat
			p.Lon = lon

			return p, symTable, symCode, remains, nil

		}

	}

	return p, ' ', ' ', c, nil

}