public static ParseResult TryParse(byte[] message, out DecodeMessage decodeMessage)
        {
            if (!Enumerable.SequenceEqual(message.Take(4), new byte[] { 0xad, 0xbc, 0xcb, 0xda }))
            {
                decodeMessage = null;
                return(ParseResult.InvalidMagicNumber);
            }

            decodeMessage = new DecodeMessage();

            int cur = 4; // length of magic number

            decodeMessage.SchemaVersion = GetInt32(message, ref cur);

            if (GetInt32(message, ref cur) != DECODE_MESSAGE_TYPE)
            {
                return(ParseResult.NotADecodeMessage);
            }

            decodeMessage.Id             = GetString(message, ref cur);
            decodeMessage.New            = GetBool(message, ref cur);
            decodeMessage.SinceMidnight  = TimeSpan.FromMilliseconds(GetInt32(message, ref cur));
            decodeMessage.Snr            = GetInt32(message, ref cur);
            decodeMessage.DeltaTime      = GetDouble(message, ref cur);
            decodeMessage.DeltaFrequency = GetInt32(message, ref cur);
            decodeMessage.Mode           = GetString(message, ref cur);
            decodeMessage.Message        = GetString(message, ref cur);
            decodeMessage.LowConfidence  = GetBool(message, ref cur);
            decodeMessage.OffAir         = GetBool(message, ref cur);

            return(ParseResult.Success);
        }
Exemple #2
0
        static void Main(string[] args)
        {
            bool all = args.Any(a => a == "--all");

            bool grids = args.Any(a => a == "--grids");

            string bandArg = args.SingleOrDefault(a => a.EndsWith("m"));

            if (string.IsNullOrWhiteSpace(bandArg) || !int.TryParse(bandArg.Substring(0, bandArg.Length - 1).Replace("--", ""), out int band))
            {
                band = 20;
            }

            Console.WriteLine($"Selected {band}m, specify (e.g.) --6m for another band");

            if (!all)
            {
                Console.WriteLine("Only showing needed spots. Pass --all for all spots.");
            }

            if (!grids)
            {
                Console.WriteLine("Not looking for unworked grids. Pass --grids to turn this on.");
            }

            if (args.Any(a => a == "--help" || a == "-h" || a == "/?"))
            {
                Console.WriteLine(@"A work in progress, that listens to udp://localhost:2237 for WSJT-X, works out the DXCC entity of every call 
heard using Clublog's cty.xml, then queries a Cloudlog instance via its API to see if it's a needed slot. If
it is, it highlights the call in red in the console window.");
                return;
            }

            if (!File.Exists(configFile) || File.ReadAllText(configFile).Contains(connectionStringKey))
            {
                Console.WriteLine("You need to provide a Cloudlog URL, e.g. https://mycloudloginstance.net");
                Console.WriteLine("in order for ft8spotter to check spots against Cloudlog. Please provide it now...");
                string url = Console.ReadLine();

                string dir = Path.GetDirectoryName(configFile);
                if (!Directory.Exists(dir))
                {
                    Directory.CreateDirectory(dir);
                }

                File.WriteAllText(configFile, $"{urlKey}={url}");
            }

            var config = GetConfig();

            cloudLogUri = new Uri(new Uri(config[urlKey]), "index.php/api/");

            var fi = new FileInfo("cty.xml");

            bool isFresh = false;

            if (DateTime.Now - fi.LastWriteTime > TimeSpan.FromDays(1))
            {
                var wc = new WebClient();
                wc.DownloadFile("https://cdn.clublog.org/cty.php?api=a11c3235cd74b88212ce726857056939d52372bd&zip=1", "cty_new.xml.zip");
                if (File.Exists("cty.xml.bak"))
                {
                    File.Delete("cty.xml.bak");
                }
                File.Move("cty.xml", "cty.xml.bak");
                ZipFile.ExtractToDirectory("cty_new.xml.zip", ".");
                isFresh = true;
                File.Delete("cty_new.xml.zip");
            }

            try
            {
                ctyXml = ClublogCtyXml.Parse(File.ReadAllText("cty.xml"));
            }
            catch (Exception ex)
            {
                if (isFresh)
                {
                    File.Delete("cty.xml");
                    File.Move("cty.xml.bak", "cty.xml");
                    Console.WriteLine("Failed to update cty.xml");
                    ctyXml = ClublogCtyXml.Parse(File.ReadAllText("cty.xml"));
                }
            }

            const int port = 2237;

            using (var client = new UdpClient(port, AddressFamily.InterNetwork))
            {
                Console.WriteLine($"Listening for WSJT-X on UDP port {port}");

                var sw = Stopwatch.StartNew();
                while (true)
                {
                    var ipep = new IPEndPoint(IPAddress.Loopback, 0);

                    byte[] msg = client.Receive(ref ipep);

                    if (ParseResult.Success != DecodeMessage.TryParse(msg, out DecodeMessage decodeMessage))
                    {
                        continue;
                    }



                    //if (msg[11] == 0x02)
                    //{
                    //string heardCall = GetHeardCall(msg);

                    string heardCall = GetHeardCall(decodeMessage.Message);

                    if (heardCall == null)
                    {
                        continue;
                    }

                    var entity = GetEntity(heardCall);

                    string grid = GetGrid(msg);

                    var needed = entity == null ? Needed.No : GetNeeded(band, entity.Adif, grids ? grid : null, "ft8");

                    if (all || !Needed.No.Equals(needed))
                    {
                        if (sw.Elapsed > TimeSpan.FromSeconds(5))
                        {
                            Console.WriteLine($"---  {DateTime.Now:HH:mm:ss}  --------------------------");
                            sw.Restart();
                        }

                        var colBefore = Console.ForegroundColor;
                        if (needed.NewCountryOnAnyBand)
                        {
                            Console.ForegroundColor = ConsoleColor.Green;
                        }
                        else if (needed.NewCountryOnBand)
                        {
                            Console.ForegroundColor = ConsoleColor.Yellow;
                        }
                        else if (needed.NewCountryOnBandOnMode)
                        {
                            Console.ForegroundColor = ConsoleColor.DarkYellow;
                        }
                        else if (needed.NewGridOnAnyBand)
                        {
                            Console.ForegroundColor = ConsoleColor.Red;
                        }
                        else if (needed.NewGridOnBand)
                        {
                            Console.ForegroundColor = ConsoleColor.Magenta;
                        }
                        else if (needed.NewGridOnBandOnMode)
                        {
                            Console.ForegroundColor = ConsoleColor.DarkRed;
                        }
                        WriteAtColumn(0, needed, 19);
                        WriteAtColumn(19, heardCall, 10);
                        WriteAtColumn(30, decodeMessage.Snr, 4);
                        WriteAtColumn(34, IsGrid(grid) ? grid : String.Empty, 4);
                        WriteAtColumn(39, entity?.Adif, 3);
                        WriteAtColumn(43, (entity?.Entity) ?? "Unknown", 50);

                        Console.WriteLine();
                        Console.ForegroundColor = colBefore;
                    }
                }
            }
        }