kopia lustrzana https://github.com/M0LTE/ft8spotter
Implement DecodeMessage.cs.
rodzic
aa00d3c905
commit
3459a27a6b
|
@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio Version 16
|
# Visual Studio Version 16
|
||||||
VisualStudioVersion = 16.0.29102.190
|
VisualStudioVersion = 16.0.29102.190
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ft8spotter", "ft8spotter\ft8spotter.csproj", "{C85CCBC8-5FA8-44A7-8AC0-C31CF99DDAAD}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ft8spotter", "ft8spotter\ft8spotter.csproj", "{C85CCBC8-5FA8-44A7-8AC0-C31CF99DDAAD}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ft8spotter.tests", "ft8spotter.tests\ft8spotter.tests.csproj", "{2AC13974-8A4A-43A8-B5AE-08C466D902E8}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
@ -15,6 +17,10 @@ Global
|
||||||
{C85CCBC8-5FA8-44A7-8AC0-C31CF99DDAAD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{C85CCBC8-5FA8-44A7-8AC0-C31CF99DDAAD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{C85CCBC8-5FA8-44A7-8AC0-C31CF99DDAAD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{C85CCBC8-5FA8-44A7-8AC0-C31CF99DDAAD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{C85CCBC8-5FA8-44A7-8AC0-C31CF99DDAAD}.Release|Any CPU.Build.0 = Release|Any CPU
|
{C85CCBC8-5FA8-44A7-8AC0-C31CF99DDAAD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{2AC13974-8A4A-43A8-B5AE-08C466D902E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{2AC13974-8A4A-43A8-B5AE-08C466D902E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{2AC13974-8A4A-43A8-B5AE-08C466D902E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{2AC13974-8A4A-43A8-B5AE-08C466D902E8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace ft8spotter.tests
|
||||||
|
{
|
||||||
|
public class DecodeMessageTests
|
||||||
|
{
|
||||||
|
// 081700 -12 0.3 367 ~ EC1AIJ US2YW KN28
|
||||||
|
string testData = @"ad bc cb da 00 00 00 02
|
||||||
|
00 00 00 02 00 00 00 06
|
||||||
|
57 53 4a 54 2d 58 01 01
|
||||||
|
c7 04 60 ff ff ff f4 3f
|
||||||
|
d3 33 33 40 00 00 00 00
|
||||||
|
00 01 6f 00 00 00 01 7e
|
||||||
|
00 00 00 11 45 43 31 41
|
||||||
|
49 4a 20 55 53 32 59 57
|
||||||
|
20 4b 4e 32 38 00 00";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ad bc cb da = magic number
|
||||||
|
* 00 00 00 02 = schema version
|
||||||
|
* 00 00 00 02 = message type 2 (decode)
|
||||||
|
* 00 00 00 06 = Id field: next 6 bytes are a string
|
||||||
|
* 57 53 4a 54 2d 58 = Id field: WSJT-X
|
||||||
|
* 01 = new field
|
||||||
|
* 01 c7 04 60 = 29,820,000ms since midnight
|
||||||
|
* ff ff ff f4 = snr -12 (big endian int32 - https://www.scadacore.com/tools/programming-calculators/online-hex-converter/)
|
||||||
|
* 3f d3 33 33 40 00 00 00 - delta time (double)
|
||||||
|
* 00 00 01 6f - delta frequency: 367
|
||||||
|
* 00 00 00 01 = mode field: next 1 byte is a string
|
||||||
|
* 7e = mode field = ~
|
||||||
|
* 00 00 00 11 = message field: next 0x11 / 17 bytes are a string
|
||||||
|
* 45 43 31 41 49 4a 20 55 53 32 59 57 20 4b 4e 32 38 = EC1AIJ US2YW KN28
|
||||||
|
* 00 = low confidence
|
||||||
|
* 00 = off air
|
||||||
|
*/
|
||||||
|
|
||||||
|
IEnumerable<byte> message
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
foreach (string line in testData.Split(Environment.NewLine))
|
||||||
|
{
|
||||||
|
foreach (string hexString in line.Split(' ', StringSplitOptions.RemoveEmptyEntries))
|
||||||
|
{
|
||||||
|
yield return byte.Parse(hexString, NumberStyles.HexNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SchemaVersion()
|
||||||
|
{
|
||||||
|
var data = message.ToArray();
|
||||||
|
|
||||||
|
Assert.Equal(ParseResult.Success, DecodeMessage.TryParse(data, out DecodeMessage decodeMessage));
|
||||||
|
|
||||||
|
Assert.Equal(2, decodeMessage.SchemaVersion);
|
||||||
|
Assert.Equal("WSJT-X", decodeMessage.Id);
|
||||||
|
Assert.True(decodeMessage.New);
|
||||||
|
Assert.Equal(TimeSpan.FromSeconds(29820), decodeMessage.SinceMidnight);
|
||||||
|
Assert.Equal(-12, decodeMessage.Snr);
|
||||||
|
Assert.Equal(0.3, Math.Round(decodeMessage.DeltaTime, 1));
|
||||||
|
Assert.Equal(367, decodeMessage.DeltaFrequency);
|
||||||
|
Assert.Equal("~", decodeMessage.Mode);
|
||||||
|
Assert.Equal("EC1AIJ US2YW KN28", decodeMessage.Message);
|
||||||
|
Assert.False(decodeMessage.LowConfidence);
|
||||||
|
Assert.False(decodeMessage.OffAir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<TargetFramework>netcoreapp2.2</TargetFramework>
|
||||||
|
<ApplicationIcon />
|
||||||
|
<StartupObject />
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="xunit" Version="2.4.1" />
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\ft8spotter\ft8spotter.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
|
@ -0,0 +1,214 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
|
namespace ft8spotter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A .NET type which parses the format of UDP datagrams emitted from WSJT-X on UDP port 2237,
|
||||||
|
/// for the Decode message type (the type emitted when WSJT-X decodes an FT8 frame)
|
||||||
|
/// </summary>
|
||||||
|
public class DecodeMessage
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Excerpt from NetworkMessage.hpp in WSJT-X source code:
|
||||||
|
*
|
||||||
|
* WSJT-X Message Formats
|
||||||
|
* ======================
|
||||||
|
*
|
||||||
|
* All messages are written or read using the QDataStream derivatives
|
||||||
|
* defined below, note that we are using the default for floating
|
||||||
|
* point precision which means all are double precision i.e. 64-bit
|
||||||
|
* IEEE format.
|
||||||
|
*
|
||||||
|
* Message is big endian format
|
||||||
|
*
|
||||||
|
* Header format:
|
||||||
|
*
|
||||||
|
* 32-bit unsigned integer magic number 0xadbccbda
|
||||||
|
* 32-bit unsigned integer schema number
|
||||||
|
*
|
||||||
|
* Payload format:
|
||||||
|
*
|
||||||
|
* As per the QDataStream format, see below for version used and
|
||||||
|
* here:
|
||||||
|
*
|
||||||
|
* http://doc.qt.io/qt-5/datastreamformat.html
|
||||||
|
*
|
||||||
|
* for the serialization details for each type, at the time of
|
||||||
|
* writing the above document is for Qt_5_0 format which is buggy
|
||||||
|
* so we use Qt_5_4 format, differences are:
|
||||||
|
*
|
||||||
|
* QDateTime:
|
||||||
|
* QDate qint64 Julian day number
|
||||||
|
* QTime quint32 Milli-seconds since midnight
|
||||||
|
* timespec quint8 0=local, 1=UTC, 2=Offset from UTC
|
||||||
|
* (seconds)
|
||||||
|
* 3=time zone
|
||||||
|
* offset qint32 only present if timespec=2
|
||||||
|
* timezone several-fields only present if timespec=3
|
||||||
|
*
|
||||||
|
* we will avoid using QDateTime fields with time zones for simplicity.
|
||||||
|
*
|
||||||
|
* Type utf8 is a utf-8 byte string formatted as a QByteArray for
|
||||||
|
* serialization purposes (currently a quint32 size followed by size
|
||||||
|
* bytes, no terminator is present or counted).
|
||||||
|
*
|
||||||
|
* The QDataStream format document linked above is not complete for
|
||||||
|
* the QByteArray serialization format, it is similar to the QString
|
||||||
|
* serialization format in that it differentiates between empty
|
||||||
|
* strings and null strings. Empty strings have a length of zero
|
||||||
|
* whereas null strings have a length field of 0xffffffff.
|
||||||
|
*
|
||||||
|
* Decode Out 2 quint32 4 bytes?
|
||||||
|
* Id (unique key) utf8 4 bytes, that number of chars, no terminator
|
||||||
|
* New bool 1 byte or bit?
|
||||||
|
* Time QTime quint32 Milliseconds since midnight (4 bytes?)
|
||||||
|
* snr qint32 4 bytes?
|
||||||
|
* Delta time (S) float (serialized as double) 8 bytes
|
||||||
|
* Delta frequency (Hz) quint32 4 bytes
|
||||||
|
* Mode utf8 4 bytes, that number of chars, no terminator
|
||||||
|
* Message utf8 4 bytes, that number of chars, no terminator
|
||||||
|
* Low confidence bool 1 byte or bit?
|
||||||
|
* Off air bool 1 byte or bit?
|
||||||
|
*
|
||||||
|
* The decode message is sent when a new decode is completed, in
|
||||||
|
* this case the 'New' field is true. It is also used in response
|
||||||
|
* to a "Replay" message where each old decode in the "Band
|
||||||
|
* activity" window, that has not been erased, is sent in order
|
||||||
|
* as a one of these messages with the 'New' field set to false.
|
||||||
|
* See the "Replay" message below for details of usage. Low
|
||||||
|
* confidence decodes are flagged in protocols where the decoder
|
||||||
|
* has knows that a decode has a higher than normal probability
|
||||||
|
* of being false, they should not be reported on publicly
|
||||||
|
* accessible services without some attached warning or further
|
||||||
|
* validation. Off air decodes are those that result from playing
|
||||||
|
* back a .WAV file.
|
||||||
|
*
|
||||||
|
* From MessageServer.cpp:
|
||||||
|
|
||||||
|
case NetworkMessage::Decode:
|
||||||
|
{
|
||||||
|
// unpack message
|
||||||
|
bool is_new {true};
|
||||||
|
QTime time;
|
||||||
|
qint32 snr;
|
||||||
|
float delta_time;
|
||||||
|
quint32 delta_frequency;
|
||||||
|
QByteArray mode;
|
||||||
|
QByteArray message;
|
||||||
|
bool low_confidence {false};
|
||||||
|
bool off_air {false};
|
||||||
|
in >> is_new >> time >> snr >> delta_time >> delta_frequency >> mode >> message >> low_confidence >> off_air;
|
||||||
|
if (check_status (in) != Fail)
|
||||||
|
{
|
||||||
|
Q_EMIT self_->decode (is_new, id, time, snr, delta_time, delta_frequency
|
||||||
|
, QString::fromUtf8 (mode), QString::fromUtf8 (message)
|
||||||
|
, low_confidence, off_air);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
public int SchemaVersion { get; set; }
|
||||||
|
public string Id { get; set; }
|
||||||
|
public bool New { get; set; }
|
||||||
|
public TimeSpan SinceMidnight { get; set; }
|
||||||
|
public int Snr { get; set; }
|
||||||
|
public double DeltaTime { get; set; }
|
||||||
|
public int DeltaFrequency { get; set; }
|
||||||
|
public string Mode { get; set; }
|
||||||
|
public string Message { get; set; }
|
||||||
|
public bool LowConfidence { get; set; }
|
||||||
|
public bool OffAir { get; set; }
|
||||||
|
|
||||||
|
private const int DECODE_MESSAGE_TYPE = 2;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int GetInt32(byte[] message, ref int cur)
|
||||||
|
{
|
||||||
|
int result = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(message, cur));
|
||||||
|
cur += sizeof(int);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double GetDouble(byte[] message, ref int cur)
|
||||||
|
{
|
||||||
|
double result;
|
||||||
|
if (BitConverter.IsLittleEndian)
|
||||||
|
{
|
||||||
|
// x64
|
||||||
|
result = BitConverter.ToDouble(message.Skip(cur).Take(sizeof(double)).Reverse().ToArray(), 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// who knows what
|
||||||
|
result = BitConverter.ToDouble(message, cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
cur += sizeof(double);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool GetBool(byte[] message, ref int cur)
|
||||||
|
{
|
||||||
|
bool result = message[cur] != 0;
|
||||||
|
cur += sizeof(bool);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetString(byte[] message, ref int cur)
|
||||||
|
{
|
||||||
|
int numBytesInField = GetInt32(message, ref cur);
|
||||||
|
|
||||||
|
char[] letters = new char[numBytesInField];
|
||||||
|
for (int i = 0; i < numBytesInField; i++)
|
||||||
|
{
|
||||||
|
letters[i] = (char)message[cur + i];
|
||||||
|
}
|
||||||
|
|
||||||
|
cur += numBytesInField;
|
||||||
|
|
||||||
|
return new string(letters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ParseResult
|
||||||
|
{
|
||||||
|
Success,
|
||||||
|
NotADecodeMessage,
|
||||||
|
InvalidMagicNumber
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,4 @@
|
||||||
using MySql.Data.MySqlClient;
|
using System;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
@ -57,6 +56,13 @@ namespace ft8spotter
|
||||||
Console.WriteLine("You need to provide a Cloudlog URL, e.g. https://mycloudloginstance.net");
|
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...");
|
Console.WriteLine("in order for ft8spotter to check spots against Cloudlog. Please provide it now...");
|
||||||
string url = Console.ReadLine();
|
string url = Console.ReadLine();
|
||||||
|
|
||||||
|
string dir = Path.GetDirectoryName(configFile);
|
||||||
|
if (!Directory.Exists(dir))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(dir);
|
||||||
|
}
|
||||||
|
|
||||||
File.WriteAllText(configFile, $"{urlKey}={url}");
|
File.WriteAllText(configFile, $"{urlKey}={url}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,9 +83,17 @@ namespace ft8spotter
|
||||||
var ipep = new IPEndPoint(IPAddress.Loopback, 0);
|
var ipep = new IPEndPoint(IPAddress.Loopback, 0);
|
||||||
|
|
||||||
byte[] msg = client.Receive(ref ipep);
|
byte[] msg = client.Receive(ref ipep);
|
||||||
if (msg[11] == 0x02)
|
|
||||||
{
|
if (ParseResult.Success != DecodeMessage.TryParse(msg, out DecodeMessage decodeMessage))
|
||||||
string heardCall = GetHeardCall(msg);
|
continue;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//if (msg[11] == 0x02)
|
||||||
|
//{
|
||||||
|
//string heardCall = GetHeardCall(msg);
|
||||||
|
|
||||||
|
string heardCall = GetHeardCall(decodeMessage.Message);
|
||||||
|
|
||||||
if (heardCall == null)
|
if (heardCall == null)
|
||||||
continue;
|
continue;
|
||||||
|
@ -125,9 +139,10 @@ namespace ft8spotter
|
||||||
}
|
}
|
||||||
WriteAtColumn(0, needed, 19);
|
WriteAtColumn(0, needed, 19);
|
||||||
WriteAtColumn(19, heardCall, 10);
|
WriteAtColumn(19, heardCall, 10);
|
||||||
WriteAtColumn(30, IsGrid(grid) ? grid : String.Empty, 4);
|
WriteAtColumn(30, decodeMessage.Snr, 4);
|
||||||
WriteAtColumn(35, entity?.Adif, 3);
|
WriteAtColumn(34, IsGrid(grid) ? grid : String.Empty, 4);
|
||||||
WriteAtColumn(39, (entity?.Entity) ?? "Unknown", 50);
|
WriteAtColumn(39, entity?.Adif, 3);
|
||||||
|
WriteAtColumn(43, (entity?.Entity) ?? "Unknown", 50);
|
||||||
|
|
||||||
Console.WriteLine();
|
Console.WriteLine();
|
||||||
Console.ForegroundColor = colBefore;
|
Console.ForegroundColor = colBefore;
|
||||||
|
@ -135,6 +150,43 @@ namespace ft8spotter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string GetHeardCall(string text)
|
||||||
|
{
|
||||||
|
string[] split = text.Split(' ');
|
||||||
|
|
||||||
|
string heard;
|
||||||
|
if (split.Length == 0)
|
||||||
|
{
|
||||||
|
heard = null;
|
||||||
|
}
|
||||||
|
else if (split.Length == 1)
|
||||||
|
{
|
||||||
|
heard = split[0];
|
||||||
|
}
|
||||||
|
else if (split.Length == 2)
|
||||||
|
{
|
||||||
|
heard = split[split.Length - 1];
|
||||||
|
}
|
||||||
|
else if (split.Length == 3)
|
||||||
|
{
|
||||||
|
heard = split[split.Length - 2];
|
||||||
|
}
|
||||||
|
else if (split.Length == 4)
|
||||||
|
{
|
||||||
|
heard = split[split.Length - 2];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
heard = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (heard != null)
|
||||||
|
{
|
||||||
|
heard = heard.Replace("<", "").Replace(">", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
return heard;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void WriteAtColumn(int col, object heardCall, int max)
|
private static void WriteAtColumn(int col, object heardCall, int max)
|
||||||
|
@ -160,6 +212,51 @@ namespace ft8spotter
|
||||||
Console.Write(toWrite);
|
Console.Write(toWrite);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int GetSnr(byte[] msg, string call)
|
||||||
|
{
|
||||||
|
Console.WriteLine(call);
|
||||||
|
|
||||||
|
int cur = 0;
|
||||||
|
foreach (var batch in msg.Batch(8))
|
||||||
|
{
|
||||||
|
Console.Write(cur.ToString("00") + " ");
|
||||||
|
foreach (var b in batch)
|
||||||
|
{
|
||||||
|
string bytestr = b.ToString("X").ToLower();
|
||||||
|
|
||||||
|
if (bytestr.Length == 1)
|
||||||
|
{
|
||||||
|
bytestr = "0" + bytestr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.Write(bytestr + " ");
|
||||||
|
}
|
||||||
|
Console.WriteLine();
|
||||||
|
|
||||||
|
Console.Write(" ");
|
||||||
|
foreach (var b in batch)
|
||||||
|
{
|
||||||
|
char ch = (char)b;
|
||||||
|
if (Char.IsLetterOrDigit(ch) || Char.IsPunctuation(ch) || Char.IsSymbol(ch) || (ch == ' '))
|
||||||
|
{
|
||||||
|
Console.Write(ch);
|
||||||
|
Console.Write(" ");
|
||||||
|
}
|
||||||
|
else if (ch == 0)
|
||||||
|
{
|
||||||
|
Console.Write(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Console.WriteLine();
|
||||||
|
Console.WriteLine();
|
||||||
|
cur += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
Debugger.Break();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
private static string GetGrid(byte[] msg)
|
private static string GetGrid(byte[] msg)
|
||||||
{
|
{
|
||||||
string text;
|
string text;
|
||||||
|
@ -241,18 +338,6 @@ namespace ft8spotter
|
||||||
}
|
}
|
||||||
|
|
||||||
static string configFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".ft8spotter", "config");
|
static string configFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".ft8spotter", "config");
|
||||||
static string cs;
|
|
||||||
static IDbConnection GetConnection()
|
|
||||||
{
|
|
||||||
if (cs == null)
|
|
||||||
{
|
|
||||||
Dictionary<string, string> configSettings = GetConfig();
|
|
||||||
|
|
||||||
cs = configSettings[connectionStringKey];
|
|
||||||
}
|
|
||||||
|
|
||||||
return new MySqlConnection(cs);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Dictionary<string, string> config;
|
private static Dictionary<string, string> config;
|
||||||
private static Dictionary<string, string> GetConfig()
|
private static Dictionary<string, string> GetConfig()
|
||||||
|
@ -545,38 +630,6 @@ namespace ft8spotter
|
||||||
|
|
||||||
static string GetHeardCall(byte[] msg)
|
static string GetHeardCall(byte[] msg)
|
||||||
{
|
{
|
||||||
/*int cur = 0;
|
|
||||||
foreach (var batch in msg.Batch(8))
|
|
||||||
{
|
|
||||||
Console.Write(cur.ToString("00") + " ");
|
|
||||||
foreach (var b in batch)
|
|
||||||
{
|
|
||||||
string bytestr = b.ToString("X").ToLower();
|
|
||||||
|
|
||||||
if (bytestr.Length == 1)
|
|
||||||
{
|
|
||||||
bytestr = "0" + bytestr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.Write(bytestr + " ");
|
|
||||||
}
|
|
||||||
Console.WriteLine();
|
|
||||||
|
|
||||||
Console.Write(" ");
|
|
||||||
foreach (var b in batch)
|
|
||||||
{
|
|
||||||
char ch = (char)b;
|
|
||||||
if (Char.IsLetterOrDigit(ch) || Char.IsPunctuation(ch) || Char.IsSymbol(ch) || (ch == ' '))
|
|
||||||
{
|
|
||||||
Console.Write(ch);
|
|
||||||
Console.Write(" ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Console.WriteLine();
|
|
||||||
Console.WriteLine();
|
|
||||||
cur += 8;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
string text;
|
string text;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -592,40 +645,7 @@ namespace ft8spotter
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
string[] split = text.Split(' ');
|
return GetHeardCall(text);
|
||||||
|
|
||||||
string heard;
|
|
||||||
if (split.Length == 0)
|
|
||||||
{
|
|
||||||
heard = null;
|
|
||||||
}
|
|
||||||
else if (split.Length == 1)
|
|
||||||
{
|
|
||||||
heard = split[0];
|
|
||||||
}
|
|
||||||
else if (split.Length == 2)
|
|
||||||
{
|
|
||||||
heard = split[split.Length - 1];
|
|
||||||
}
|
|
||||||
else if (split.Length == 3)
|
|
||||||
{
|
|
||||||
heard = split[split.Length - 2];
|
|
||||||
}
|
|
||||||
else if (split.Length == 4)
|
|
||||||
{
|
|
||||||
heard = split[split.Length - 2];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
heard = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (heard != null)
|
|
||||||
{
|
|
||||||
heard = heard.Replace("<", "").Replace(">", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
return heard;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,9 +15,4 @@
|
||||||
</Content>
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Dapper" Version="1.60.6" />
|
|
||||||
<PackageReference Include="MySql.Data" Version="8.0.16" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
Ładowanie…
Reference in New Issue