kopia lustrzana https://github.com/cyoung/stratux
Add decoding of Canadian tail numbers
rodzic
efaaa8777d
commit
6d19f57e0e
173
main/traffic.go
173
main/traffic.go
|
@ -352,7 +352,7 @@ func parseDownlinkReport(s string, signalLevel int) {
|
|||
ti.Icao_addr = icao_addr
|
||||
ti.ExtrapolatedPosition = false
|
||||
|
||||
thisReg, validReg := icao2faa(icao_addr)
|
||||
thisReg, validReg := icao2reg(icao_addr)
|
||||
if validReg {
|
||||
ti.Reg = thisReg
|
||||
ti.Tail = thisReg
|
||||
|
@ -659,7 +659,7 @@ func esListen() {
|
|||
ti.ExtrapolatedPosition = false
|
||||
ti.Last_source = TRAFFIC_SOURCE_1090ES
|
||||
|
||||
thisReg, validReg := icao2faa(icao)
|
||||
thisReg, validReg := icao2reg(icao)
|
||||
if validReg {
|
||||
ti.Reg = thisReg
|
||||
ti.Tail = thisReg
|
||||
|
@ -1015,100 +1015,143 @@ func updateDemoTraffic(icao uint32, tail string, relAlt float32, gs float64, off
|
|||
}
|
||||
|
||||
/*
|
||||
icao2faa() : Converts 24-bit Mode S addresses to N-numbers.
|
||||
icao2reg() : Converts 24-bit Mode S addresses to N-numbers and C-numbers.
|
||||
|
||||
Input: uint32 representing the Mode S address. Valid range for
|
||||
translation is 0xA00001 - 0xADF7C7, inclusive.
|
||||
|
||||
Values outside the range A000001-AFFFFFF are flagged as non-US.
|
||||
Values outside the range A000001-AFFFFFF or C00001-C3FFFF
|
||||
are flagged as foreign.
|
||||
|
||||
Values between ADF7C8 - AFFFFF are allocated to the United States,
|
||||
but are not used for aicraft on the civil registry. These could be
|
||||
military, other public aircraft, or (future use) temporary
|
||||
anonymous addresses.
|
||||
military, other public aircraft, or future use.
|
||||
|
||||
|
||||
Values between C0CDF9 - C3FFFF are allocated to Canada,
|
||||
but are not used for aicraft on the civil registry. These could be
|
||||
military, other public aircraft, or future use.
|
||||
|
||||
Output:
|
||||
string: String containing the decoded tail number (if decoding succeeded),
|
||||
"NON-US" (for non-US allocation), and "MIL" for non-civil US allocation.
|
||||
"NON-NA" (for non-US / non Canada allocation), and "US-MIL" or "CA-MIL" for non-civil US / Canada allocation.
|
||||
|
||||
bool: True if the Mode S address successfully translated to an
|
||||
N number. False for all other conditions.
|
||||
*/
|
||||
|
||||
func icao2faa(icao_addr uint32) (string, bool) {
|
||||
func icao2reg(icao_addr uint32) (string, bool) {
|
||||
// Initialize local variables
|
||||
base34alphabet := string("ABCDEFGHJKLMNPQRSTUVWXYZ0123456789")
|
||||
faaOffset := uint32(0xA00001)
|
||||
nationalOffset := uint32(0xA00001) // default is US
|
||||
tail := ""
|
||||
nation := ""
|
||||
|
||||
// Discard non-US ICAO codes
|
||||
if (icao_addr < 0xA00001) || (icao_addr > 0xAFFFFF) {
|
||||
//fmt.Printf("%X is a non-US address.\n", icao_addr)
|
||||
return "NON-US", false
|
||||
// Determine nationality
|
||||
if (icao_addr >= 0xA00001) && (icao_addr <= 0xAFFFFF) {
|
||||
nation = "US"
|
||||
} else if (icao_addr >= 0xC00001) && (icao_addr <= 0xC3FFFF) {
|
||||
nation = "CA"
|
||||
} else {
|
||||
// future national decoding is TO-DO
|
||||
return "NON-NA", false
|
||||
}
|
||||
|
||||
// Discard addresses that are not assigned to aircraft on the civil registry (public aircraft: USAF, USN, USMC, USCG, ANG, FBI, etc.)
|
||||
if icao_addr > 0xADF7C7 {
|
||||
//fmt.Printf("%X is a US aircraft, but not on the civil registry.\n", icao_addr)
|
||||
return "MIL", false
|
||||
}
|
||||
|
||||
serial := int32(icao_addr - faaOffset)
|
||||
// First digit
|
||||
a := (serial / 101711) + 1
|
||||
|
||||
// Second digit
|
||||
a_remainder := serial % 101711
|
||||
b := ((a_remainder + 9510) / 10111) - 1
|
||||
|
||||
// Third digit
|
||||
b_remainder := (a_remainder + 9510) % 10111
|
||||
c := ((b_remainder + 350) / 951) - 1
|
||||
|
||||
// This next bit is more convoluted. First, figure out if we're using the "short" method of
|
||||
// decoding the last two digits (two letters, one letter and one blank, or two blanks).
|
||||
// This will be the case if digit "B" or "C" are calculated as negative, or if c_remainder
|
||||
// is less than 601.
|
||||
|
||||
c_remainder := (b_remainder + 350) % 951
|
||||
var d, e int32
|
||||
|
||||
if (b >= 0) && (c >= 0) && (c_remainder > 600) { // alphanumeric decoding method
|
||||
d = 24 + (c_remainder-601)/35
|
||||
e = (c_remainder - 601) % 35
|
||||
|
||||
} else { // two-letter decoding method
|
||||
if (b < 0) || (c < 0) {
|
||||
c_remainder -= 350 // otherwise " " == 350, "A " == 351, "AA" == 352, etc.
|
||||
if nation == "CA" { // Canada decoding
|
||||
// First, discard addresses that are not assigned to aircraft on the civil registry
|
||||
if icao_addr > 0xC0CDF8 {
|
||||
//fmt.Printf("%X is a Canada aircraft, but not a CF-, CG-, or CI- registration.\n", icao_addr)
|
||||
return "CA-MIL", false
|
||||
}
|
||||
|
||||
d = (c_remainder - 1) / 25
|
||||
e = (c_remainder - 1) % 25
|
||||
nationalOffset := uint32(0xC00001)
|
||||
serial := int32(icao_addr - nationalOffset)
|
||||
|
||||
if e < 0 {
|
||||
d -= 1
|
||||
e += 25
|
||||
// Fifth letter
|
||||
e := serial % 26
|
||||
|
||||
// Fourth letter
|
||||
d := (serial / 26) % 26
|
||||
|
||||
// Third letter
|
||||
c := (serial / 676) % 26 // 676 == 26*26
|
||||
|
||||
// Second letter
|
||||
b := (serial / 17576) % 26 // 17576 == 26*26*26
|
||||
|
||||
b_str := "FGI"
|
||||
|
||||
//fmt.Printf("B = %d, C = %d, D = %d, E = %d\n",b,c,d,e)
|
||||
tail = fmt.Sprintf("C%c%c%c%c", b_str[b], c+65, d+65, e+65)
|
||||
}
|
||||
|
||||
if nation == "US" { // FAA decoding
|
||||
// First, discard addresses that are not assigned to aircraft on the civil registry
|
||||
if icao_addr > 0xADF7C7 {
|
||||
//fmt.Printf("%X is a US aircraft, but not on the civil registry.\n", icao_addr)
|
||||
return "US-MIL", false
|
||||
}
|
||||
}
|
||||
|
||||
a_char := fmt.Sprintf("%d", a)
|
||||
var b_char, c_char, d_char, e_char string
|
||||
serial := int32(icao_addr - nationalOffset)
|
||||
// First digit
|
||||
a := (serial / 101711) + 1
|
||||
|
||||
if b >= 0 {
|
||||
b_char = fmt.Sprintf("%d", b)
|
||||
}
|
||||
// Second digit
|
||||
a_remainder := serial % 101711
|
||||
b := ((a_remainder + 9510) / 10111) - 1
|
||||
|
||||
if b >= 0 && c >= 0 {
|
||||
c_char = fmt.Sprintf("%d", c)
|
||||
}
|
||||
// Third digit
|
||||
b_remainder := (a_remainder + 9510) % 10111
|
||||
c := ((b_remainder + 350) / 951) - 1
|
||||
|
||||
if d > -1 {
|
||||
d_char = string(base34alphabet[d])
|
||||
if e > 0 {
|
||||
e_char = string(base34alphabet[e-1])
|
||||
// This next bit is more convoluted. First, figure out if we're using the "short" method of
|
||||
// decoding the last two digits (two letters, one letter and one blank, or two blanks).
|
||||
// This will be the case if digit "B" or "C" are calculated as negative, or if c_remainder
|
||||
// is less than 601.
|
||||
|
||||
c_remainder := (b_remainder + 350) % 951
|
||||
var d, e int32
|
||||
|
||||
if (b >= 0) && (c >= 0) && (c_remainder > 600) { // alphanumeric decoding method
|
||||
d = 24 + (c_remainder-601)/35
|
||||
e = (c_remainder - 601) % 35
|
||||
|
||||
} else { // two-letter decoding method
|
||||
if (b < 0) || (c < 0) {
|
||||
c_remainder -= 350 // otherwise " " == 350, "A " == 351, "AA" == 352, etc.
|
||||
}
|
||||
|
||||
d = (c_remainder - 1) / 25
|
||||
e = (c_remainder - 1) % 25
|
||||
|
||||
if e < 0 {
|
||||
d -= 1
|
||||
e += 25
|
||||
}
|
||||
}
|
||||
|
||||
a_char := fmt.Sprintf("%d", a)
|
||||
var b_char, c_char, d_char, e_char string
|
||||
|
||||
if b >= 0 {
|
||||
b_char = fmt.Sprintf("%d", b)
|
||||
}
|
||||
|
||||
if b >= 0 && c >= 0 {
|
||||
c_char = fmt.Sprintf("%d", c)
|
||||
}
|
||||
|
||||
if d > -1 {
|
||||
d_char = string(base34alphabet[d])
|
||||
if e > 0 {
|
||||
e_char = string(base34alphabet[e-1])
|
||||
}
|
||||
}
|
||||
|
||||
tail = "N" + a_char + b_char + c_char + d_char + e_char
|
||||
|
||||
}
|
||||
|
||||
tail = "N" + a_char + b_char + c_char + d_char + e_char
|
||||
return tail, true
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
|
||||
icao2reg: Converts a 24-bit numeric value to a tail number of FAA
|
||||
or Canadian registry.
|
||||
|
||||
(c) 2016 AvSquirrel
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func main() {
|
||||
icao := uint32(0xAC82EC)
|
||||
args := os.Args
|
||||
if len(args) > 1 {
|
||||
code, err := strconv.ParseInt(args[1], 16, 32)
|
||||
if err != nil {
|
||||
fmt.Printf("Error parsing argument %s. Input should be 24-bit hexadecimal, e.g. 'A00001'\n", args[1])
|
||||
fmt.Printf("Showing example decoding for Mode S code %X,\n", icao)
|
||||
} else {
|
||||
icao = uint32(code)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("Usage: ./icao2faa [code], where [code] is a 24-bit hexadecimal string, e.g. A00001\n")
|
||||
fmt.Printf("Showing example decoding for Mode S code %X,\n", icao)
|
||||
}
|
||||
|
||||
tail, valid := icao2reg(icao)
|
||||
|
||||
if valid {
|
||||
fmt.Printf("ICAO %X successfully decodes as %s\n", icao, tail)
|
||||
} else {
|
||||
fmt.Printf("ICAO %X did not successfully decode. Response is `%s`\n", icao, tail)
|
||||
}
|
||||
}
|
||||
|
||||
func icao2reg(icao_addr uint32) (string, bool) {
|
||||
// Initialize local variables
|
||||
base34alphabet := string("ABCDEFGHJKLMNPQRSTUVWXYZ0123456789")
|
||||
nationalOffset := uint32(0xA00001) // default is US
|
||||
tail := ""
|
||||
nation := ""
|
||||
|
||||
|
||||
// Determine nationality
|
||||
if (icao_addr >= 0xA00001) && (icao_addr <= 0xAFFFFF) {
|
||||
nation = "US"
|
||||
} else if (icao_addr >= 0xC00001) && (icao_addr <= 0xC3FFFF) {
|
||||
nation = "CA"
|
||||
} else {
|
||||
// future national decoding is TO-DO
|
||||
return "NON-NA", false
|
||||
}
|
||||
|
||||
if (nation =="CA") { // Canada decoding
|
||||
// First, discard addresses that are not assigned to aircraft on the civil registry
|
||||
if icao_addr > 0xC0CDF8 {
|
||||
//fmt.Printf("%X is a Canada aircraft, but not a CF-, CG-, or CI- registration.\n", icao_addr)
|
||||
return "CA-MIL", false
|
||||
}
|
||||
|
||||
nationalOffset := uint32(0xC00001)
|
||||
serial := int32(icao_addr - nationalOffset)
|
||||
|
||||
// Fifth letter
|
||||
e := serial % 26
|
||||
|
||||
// Fourth letter
|
||||
d := (serial/26) % 26
|
||||
|
||||
// Third letter
|
||||
c := (serial/676) % 26 // 676 == 26*26
|
||||
|
||||
// Second letter
|
||||
b := (serial/17576) % 26 // 17576 == 26*26*26
|
||||
|
||||
b_str :="FGI"
|
||||
|
||||
fmt.Printf("B = %d, C = %d, D = %d, E = %d\n",b,c,d,e)
|
||||
tail = fmt.Sprintf("C%c%c%c%c",b_str[b],c+65,d+65,e+65)
|
||||
}
|
||||
|
||||
if (nation == "US") { // FAA decoding
|
||||
// First, discard addresses that are not assigned to aircraft on the civil registry
|
||||
if icao_addr > 0xADF7C7 {
|
||||
//fmt.Printf("%X is a US aircraft, but not on the civil registry.\n", icao_addr)
|
||||
return "US-MIL", false
|
||||
}
|
||||
|
||||
|
||||
serial := int32(icao_addr - nationalOffset)
|
||||
// First digit
|
||||
a := (serial / 101711) + 1
|
||||
|
||||
// Second digit
|
||||
a_remainder := serial % 101711
|
||||
b := ((a_remainder + 9510) / 10111) - 1
|
||||
|
||||
// Third digit
|
||||
b_remainder := (a_remainder + 9510) % 10111
|
||||
c := ((b_remainder + 350) / 951) - 1
|
||||
|
||||
// This next bit is more convoluted. First, figure out if we're using the "short" method of
|
||||
// decoding the last two digits (two letters, one letter and one blank, or two blanks).
|
||||
// This will be the case if digit "B" or "C" are calculated as negative, or if c_remainder
|
||||
// is less than 601.
|
||||
|
||||
c_remainder := (b_remainder + 350) % 951
|
||||
var d, e int32
|
||||
|
||||
if (b >= 0) && (c >= 0) && (c_remainder > 600) { // alphanumeric decoding method
|
||||
d = 24 + (c_remainder-601)/35
|
||||
e = (c_remainder - 601) % 35
|
||||
|
||||
} else { // two-letter decoding method
|
||||
if (b < 0) || (c < 0) {
|
||||
c_remainder -= 350 // otherwise " " == 350, "A " == 351, "AA" == 352, etc.
|
||||
}
|
||||
|
||||
d = (c_remainder - 1) / 25
|
||||
e = (c_remainder - 1) % 25
|
||||
|
||||
if e < 0 {
|
||||
d -= 1
|
||||
e += 25
|
||||
}
|
||||
}
|
||||
|
||||
a_char := fmt.Sprintf("%d", a)
|
||||
var b_char, c_char, d_char, e_char string
|
||||
|
||||
if b >= 0 {
|
||||
b_char = fmt.Sprintf("%d", b)
|
||||
}
|
||||
|
||||
if b >= 0 && c >= 0 {
|
||||
c_char = fmt.Sprintf("%d", c)
|
||||
}
|
||||
|
||||
if d > -1 {
|
||||
d_char = string(base34alphabet[d])
|
||||
if e > 0 {
|
||||
e_char = string(base34alphabet[e-1])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
tail = "N" + a_char + b_char + c_char + d_char + e_char
|
||||
|
||||
}
|
||||
|
||||
|
||||
return tail, true
|
||||
}
|
Ładowanie…
Reference in New Issue