From b15bcf4f5de9ae6df596fea3ff3bb7fe40cf2d14 Mon Sep 17 00:00:00 2001 From: Christopher Young Date: Mon, 14 Dec 2015 22:41:47 -0500 Subject: [PATCH] Some JSON output. --- getairmet.go | 132 +++++++++++++++++++++++++++++++++++++------ uatparse/uatdata.go | 4 +- uatparse/uatparse.go | 30 +++++++--- 3 files changed, 139 insertions(+), 27 deletions(-) diff --git a/getairmet.go b/getairmet.go index 9474ec92..6edd7686 100644 --- a/getairmet.go +++ b/getairmet.go @@ -1,33 +1,129 @@ package main import ( - "fmt" "./uatparse" + "bufio" + "encoding/json" + "flag" + "fmt" + "os" + "strconv" + "strings" ) -func main() { - s := "+3cc0978aa66ca3a02100002d3f29688210000000ff0dc45e1e00000000efd305071c142d071d0300bef1e3f1900abdf823bc440abe9ee394a80ac088439a980abfefa3e45c0abef1e3f1900a248000353f6a002210000000ff003e51987c4d5060cb9cb1c30833df2c78cf87f2d74c307d77cf7c10893053857f1d70df2e72c70c1fc75c37cb9cb2cf07f3c707f3c707c17d97df7df780260000353f6a002210000000ff004146247c4d5060cb9cb1c30833df2cf3df07f2d35c307d77cf7d7b71e3881420f3417f1d70df2e72c70c1fc75c37cf0c35d797f0c307f2d707c17d97df7df780648000213c66b022102c45170000bec0487c38f50136d1202c4517bb0defcf0da0c77c79cb26a0844517830defcf0da01145e05176605f1b205f3b205f4b205f6b205176605e00943a0497660e52bf2dcc8013848145d9817c6c8145d980a80250e8145d98178013848125d98334afcb132c8145d981680250e8145d981780138480140322014e120497660cb74ac8145d981780250e8145d9810d2004e1205176605f68033131203075048013848020524890c1105120c75c37c77c79cb2b71d71c31df0cf0c054d47800;rs=31;" -// s := "+3c2643887cdca4802100002d3f29688210000000ff0dc45e1e00000000efd305071c142d071d0300bef1e3f1900abdf823bc440abe9ee394a80ac088439a980abfefa3e45c0abef1e3f1900a248000353f6a002210000000ff003e51987c4d5060cb9cb1c30833df2c78cf87f2d74c307d77cf7c10893053857f1d70df2e72c70c1fc75c37cb9cb2cf07f3c707f3c707c17d97df7df7806c80002d3f29682210000000ff00ce11787c04948d15480b0c8260cb8cb0d358032094e05c1832e32c34d5e04948d1548132454920605501148348063d280919281604c24481539424c832e70cf0c1e04948d154809192baeb8d3a024180d3e05c980931e1923cd833c138050558143e0cb039780430c8143e0d304d31600841a050f833c0538580948b8143e0d703858044cd7943e0cf04e014155e0c91e008c5e0c31c2f5894e008c5e0cd336040340ebc24ae8033ce11380458c407830c2dc336ae8033ce1138033ce507782644830cda814212560c3969e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;rs=17;" +type UATFrame struct { + FISB_month uint32 + FISB_day uint32 + FISB_hours uint32 + FISB_minutes uint32 + FISB_seconds uint32 -// s := "+3bb40f8953d8b1b0360000353f54002210000000ff006185947c4d5060cb9c70c30833df0d78d707f2e72d5f5df49fcf4c3105fc75c37cb9c70c307f1d70df3c30df0c1fc30c1fcb2c1f05f65f7f3d30c417d2cf4c3105f0545054825526604854c549616018f48315381448e1e0052141b2024e78006c80002d3f29682210000000ff00ce11787c04948d15480b0c8260cb8cb0d358032094e05c1832e32c34d5e04948d1548132454920605501148348063d280919281604c24481539424c832e70cf0c1e04948d154809192baeb8d3a024180d3e05c980931e1923cd833c138050558143e0cb039780430c8143e0d304d31600841a050f833c0538580948b8143e0d703858044cd7943e0cf04e014155e0c91e008c5e0c31c2f5894e008c5e0cd336040340ebc24ae8033ce11380458c407830c2dc336ae8033ce1138033ce507782644830cda814212560c3969e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;rs=29;" + Product_id uint32 + // Text data, if applicable. + Text_data []string -// s := "+3c2643887cdcb780480000213e955822102cc5c1000085bb887c38f50136d1202cc5c1bb0defc30ca0cb6c70d336a084c5c1830defc30ca03170603c24d48143d715280c1d48280534a0c72c34e30ca9834cb2c33c2ec303b0e36c38d38bb1c17828d2ee4e360160317069831c31d6ec46520a33cf1bb01948011cca603d55203c68131525890c5831d70df2db1c34cedc75c38c70c70d3378005700002d3f29688210000000ff28c4631e00000000efd317071c142d071d0300ce1a242695a4ce03a3e63da4cc01039cbda4ca5f633345a4c93ca31db1a4c899034aa1a4c8328379fda4c73fe39e15a4c75fa3d24da4cac703fe89a4ccf3840731a4ce1a242695a4ce1a24269540ce03a3e63d40cc01039cbd40ca5f63334540c93ca31db140c899034aa140c8328379fd40c73fe39e1540c75fa3d24d40cac703fe8940ccf384073140ce1a24269540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;" + // For AIRMET/NOTAM. + //FIXME: Temporary. + Points []uatparse.GeoPoint + ReportNumber uint16 + ReportYear uint16 + LocationIdentifier string + RecordFormat uint8 +} - msg, err := uatparse.New(s) +var reports map[string]UATFrame - if err != nil { - fmt.Printf("err: %s\n", err.Error()) +func updateReport(f *uatparse.UATFrame) { + if f.ReportNumber == 0 || f.ReportYear == 0 || f.RecordFormat == 0 { return } + s := strconv.Itoa(int(f.ReportNumber)) + "-" + strconv.Itoa(int(f.ReportYear)) + f.LocationIdentifier = strings.Replace(f.LocationIdentifier, "\x03", "", -1) + if len(f.Points) == 0 && len(f.Text_data) == 0 { + return + } + if p, ok := reports[s]; ok { + if len(f.Points) > 0 { + p.Points = f.Points + reports[s] = p + } + if len(f.Text_data) > 0 { + p.Text_data = f.Text_data + reports[s] = p + } + } else { + var z UATFrame + z.FISB_month = f.FISB_month + z.FISB_day = f.FISB_day + z.FISB_hours = f.FISB_hours + z.FISB_minutes = f.FISB_minutes + z.FISB_seconds = f.FISB_seconds + z.Product_id = f.Product_id + z.Points = f.Points + z.ReportNumber = f.ReportNumber + z.ReportYear = f.ReportYear + z.LocationIdentifier = f.LocationIdentifier + z.RecordFormat = f.RecordFormat - - msg.DecodeUplink() - - - for _, frame := range msg.Frames { - fmt.Printf("Frame_type: %d\n", frame.Frame_type) - fmt.Printf("Product_id: %d\n", frame.Product_id) - fmt.Printf("FISB_hours: %d\n", frame.FISB_hours) - fmt.Printf("FISB_minutes: %d\n", frame.FISB_minutes) + reports[s] = z } } + +func main() { + reports = make(map[string]UATFrame) + s := "+3cc0978aa66ca3a02100002d3f29688210000000ff0dc45e1e00000000efd305071c142d071d0300bef1e3f1900abdf823bc440abe9ee394a80ac088439a980abfefa3e45c0abef1e3f1900a248000353f6a002210000000ff003e51987c4d5060cb9cb1c30833df2c78cf87f2d74c307d77cf7c10893053857f1d70df2e72c70c1fc75c37cb9cb2cf07f3c707f3c707c17d97df7df780260000353f6a002210000000ff004146247c4d5060cb9cb1c30833df2cf3df07f2d35c307d77cf7d7b71e3881420f3417f1d70df2e72c70c1fc75c37cf0c35d797f0c307f2d707c17d97df7df780648000213c66b022102c45170000bec0487c38f50136d1202c4517bb0defcf0da0c77c79cb26a0844517830defcf0da01145e05176605f1b205f3b205f4b205f6b205176605e00943a0497660e52bf2dcc8013848145d9817c6c8145d980a80250e8145d98178013848125d98334afcb132c8145d981680250e8145d981780138480140322014e120497660cb74ac8145d981780250e8145d9810d2004e1205176605f68033131203075048013848020524890c1105120c75c37c77c79cb2b71d71c31df0cf0c054d47800;rs=31;" + // s := "+3c2643887cdca4802100002d3f29688210000000ff0dc45e1e00000000efd305071c142d071d0300bef1e3f1900abdf823bc440abe9ee394a80ac088439a980abfefa3e45c0abef1e3f1900a248000353f6a002210000000ff003e51987c4d5060cb9cb1c30833df2c78cf87f2d74c307d77cf7c10893053857f1d70df2e72c70c1fc75c37cb9cb2cf07f3c707f3c707c17d97df7df7806c80002d3f29682210000000ff00ce11787c04948d15480b0c8260cb8cb0d358032094e05c1832e32c34d5e04948d1548132454920605501148348063d280919281604c24481539424c832e70cf0c1e04948d154809192baeb8d3a024180d3e05c980931e1923cd833c138050558143e0cb039780430c8143e0d304d31600841a050f833c0538580948b8143e0d703858044cd7943e0cf04e014155e0c91e008c5e0c31c2f5894e008c5e0cd336040340ebc24ae8033ce11380458c407830c2dc336ae8033ce1138033ce507782644830cda814212560c3969e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;rs=17;" + + // s := "+3bb40f8953d8b1b0360000353f54002210000000ff006185947c4d5060cb9c70c30833df0d78d707f2e72d5f5df49fcf4c3105fc75c37cb9c70c307f1d70df3c30df0c1fc30c1fcb2c1f05f65f7f3d30c417d2cf4c3105f0545054825526604854c549616018f48315381448e1e0052141b2024e78006c80002d3f29682210000000ff00ce11787c04948d15480b0c8260cb8cb0d358032094e05c1832e32c34d5e04948d1548132454920605501148348063d280919281604c24481539424c832e70cf0c1e04948d154809192baeb8d3a024180d3e05c980931e1923cd833c138050558143e0cb039780430c8143e0d304d31600841a050f833c0538580948b8143e0d703858044cd7943e0cf04e014155e0c91e008c5e0c31c2f5894e008c5e0cd336040340ebc24ae8033ce11380458c407830c2dc336ae8033ce1138033ce507782644830cda814212560c3969e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;rs=29;" + + // s := "+3c2643887cdcb780480000213e955822102cc5c1000085bb887c38f50136d1202cc5c1bb0defc30ca0cb6c70d336a084c5c1830defc30ca03170603c24d48143d715280c1d48280534a0c72c34e30ca9834cb2c33c2ec303b0e36c38d38bb1c17828d2ee4e360160317069831c31d6ec46520a33cf1bb01948011cca603d55203c68131525890c5831d70df2db1c34cedc75c38c70c70d3378005700002d3f29688210000000ff28c4631e00000000efd317071c142d071d0300ce1a242695a4ce03a3e63da4cc01039cbda4ca5f633345a4c93ca31db1a4c899034aa1a4c8328379fda4c73fe39e15a4c75fa3d24da4cac703fe89a4ccf3840731a4ce1a242695a4ce1a24269540ce03a3e63d40cc01039cbd40ca5f63334540c93ca31db140c899034aa140c8328379fd40c73fe39e1540c75fa3d24d40cac703fe8940ccf384073140ce1a24269540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;" + + replayUATFilename := flag.Bool("stdin", false, "Read from stdin") + + flag.Parse() + + if *replayUATFilename == true { + reader := bufio.NewReader(os.Stdin) + for { + text, err := reader.ReadString('\n') + if err != nil { + break + } + msg, err := uatparse.New(text) + if err != nil { + // fmt.Printf("err: %s\n", err.Error()) + // return + continue + } + msg.DecodeUplink() + for _, frame := range msg.Frames { + updateReport(frame) + } + } + } else { + + msg, err := uatparse.New(s) + + if err != nil { + fmt.Printf("err: %s\n", err.Error()) + return + } + + msg.DecodeUplink() + + for _, frame := range msg.Frames { + updateReport(frame) + } + } + + r := make([]UATFrame, 0) + for _, p := range reports { + if len(p.Points) > 0 && len(p.Text_data) > 0 { + r = append(r, p) + } + } + + j, _ := json.Marshal(&r) + fmt.Printf("%s\n", j) + +} diff --git a/uatparse/uatdata.go b/uatparse/uatdata.go index f04dbf18..cc274105 100644 --- a/uatparse/uatdata.go +++ b/uatparse/uatdata.go @@ -15,14 +15,14 @@ const ( ) // Points can be in 3D - take care that altitude is used correctly. -type GeoPoints struct { +type GeoPoint struct { Lat float64 Lon float64 Alt int32 } type UATAirmet struct { - Points []GeoPoints // Points + Points []GeoPoint // Points } type UATMsgDecoded struct { diff --git a/uatparse/uatparse.go b/uatparse/uatparse.go index f21bcb85..cb829f96 100644 --- a/uatparse/uatparse.go +++ b/uatparse/uatparse.go @@ -49,6 +49,14 @@ type UATFrame struct { g_f bool p_f bool s_f bool //TODO: Segmentation. + + // For AIRMET/NOTAM. + //FIXME: Temporary. + Points []GeoPoint + ReportNumber uint16 + ReportYear uint16 + LocationIdentifier string + RecordFormat uint8 } type UATMsg struct { @@ -176,19 +184,15 @@ func (f *UATFrame) decodeAirmet() { // APDU header: 48 bits (3-3) - assume no segmentation. record_format := (uint8(f.FISB_data[0]) & 0xF0) >> 4 - //FIXME: temp. - if record_format != 8 { - return - } - - fmt.Printf("%s\n", hex.Dump(f.FISB_data)) - + f.RecordFormat = record_format fmt.Printf("record_format=%d\n", record_format) product_version := (uint8(f.FISB_data[0]) & 0x0F) fmt.Printf("product_version=%d\n", product_version) record_count := (uint8(f.FISB_data[1]) & 0xF0) >> 4 fmt.Printf("record_count=%d\n", record_count) location_identifier := dlac_decode(f.FISB_data[2:], 3) + fmt.Printf("%s\n", hex.Dump(f.FISB_data)) + f.LocationIdentifier = location_identifier fmt.Printf("location_identifier=%s\n", location_identifier) record_reference := (uint8(f.FISB_data[5])) //FIXME: Special values. 0x00 means "use location_identifier". 0xFF means "use different reference". (4-3). fmt.Printf("record_reference=%d\n", record_reference) @@ -221,8 +225,10 @@ func (f *UATFrame) decodeAirmet() { fmt.Printf("record_length=%d\n", record_length) // Report identifier = report number + report year. report_number := (uint16(f.FISB_data[8]) << 6) | ((uint16(f.FISB_data[9]) & 0xFC) >> 2) + f.ReportNumber = report_number fmt.Printf("report_number=%d\n", report_number) report_year := ((uint16(f.FISB_data[9]) & 0x03) << 5) | ((uint16(f.FISB_data[10]) & 0xF8) >> 3) + f.ReportYear = report_year fmt.Printf("report_year=%d\n", report_year) report_status := (uint8(f.FISB_data[10]) & 0x04) >> 2 //TODO: 0 = cancelled, 1 = active. fmt.Printf("report_status=%d\n", report_status) @@ -230,6 +236,7 @@ func (f *UATFrame) decodeAirmet() { text_data_len := record_length - 5 text_data := dlac_decode(f.FISB_data[11:], uint32(text_data_len)) fmt.Printf("text_data=%s\n", text_data) + f.Text_data = []string{text_data} case 8: // (6-1). (6.22 - Graphical Overlay Record Format). record_data := f.FISB_data[6:] // Start after the record header. @@ -237,8 +244,10 @@ func (f *UATFrame) decodeAirmet() { fmt.Printf("record_length=%d\n", record_length) // Report identifier = report number + report year. report_number := ((uint16(record_data[1]) & 0x3F) << 8) | uint16(record_data[2]) + f.ReportNumber = report_number fmt.Printf("report_number=%d\n", report_number) report_year := (uint16(record_data[3]) & 0xFE) >> 1 + f.ReportYear = report_year fmt.Printf("report_year=%d\n", report_year) overlay_record_identifier := ((uint8(record_data[4]) & 0x1E) >> 1) + 1 // Document instructs to add 1. fmt.Printf("overlay_record_identifier=%d\n", overlay_record_identifier) @@ -309,6 +318,7 @@ func (f *UATFrame) decodeAirmet() { // Now we have the vertices. if geometry_overlay_options == 3 { // Extended Range 3D Polygon (MSL). + points := make([]GeoPoint, 0) // Slice containing all of the points. //FIXME: Off by one vertex. fmt.Printf("%d\n", len(record_data)) for i := 0; i < int(overlay_vertices_count); i++ { @@ -328,7 +338,13 @@ func (f *UATFrame) decodeAirmet() { alt := alt_raw * 100 fmt.Printf("lat=%f,lng=%f,alt=%d\n", lat, lng, alt) fmt.Printf("coord:%f,%f\n", lat, lng) + var point GeoPoint + point.Lat = lat + point.Lon = lng + point.Alt = alt + points = append(points, point) } + f.Points = points } fmt.Printf("\n\n\n")