diff --git a/.gitignore b/.gitignore index a73078c..a7b008d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ .idea /bin -/obj \ No newline at end of file +/obj +*.user +.vscode \ No newline at end of file diff --git a/App.axaml b/App.axaml index 6d831cd..68d2f27 100644 --- a/App.axaml +++ b/App.axaml @@ -3,6 +3,7 @@ xmlns:behaviors="clr-namespace:SenhaixFreqWriter.Behaviors" xmlns:m="clr-namespace:SenhaixFreqWriter.DataModels.Shx8x00" xmlns:mgt12="clr-namespace:SenhaixFreqWriter.DataModels.Gt12" + xmlns:mShx8800Pro="clr-namespace:SenhaixFreqWriter.DataModels.Shx8800Pro" x:Class="SenhaixFreqWriter.App" RequestedThemeVariant="Default"> @@ -66,5 +67,6 @@ + \ No newline at end of file diff --git a/Constants/Common/SHX_DEVICE.cs b/Constants/Common/SHX_DEVICE.cs index 4b51c80..1267ac4 100644 --- a/Constants/Common/SHX_DEVICE.cs +++ b/Constants/Common/SHX_DEVICE.cs @@ -3,6 +3,7 @@ public enum SHX_DEVICE { SHX8800, + SHX8800PRO, SHX8600, SHX8600PRO, GT12 diff --git a/Constants/Shx8800Pro/CHAN_CHOICE.cs b/Constants/Shx8800Pro/CHAN_CHOICE.cs new file mode 100644 index 0000000..eebedab --- /dev/null +++ b/Constants/Shx8800Pro/CHAN_CHOICE.cs @@ -0,0 +1,68 @@ +using System.Collections.ObjectModel; + +namespace SenhaixFreqWriter.Constants.Shx8800Pro; + +public class ChanChoice +{ + public static ObservableCollection Power = new() + { + "高", "中", "低" + }; + + public static ObservableCollection Bandwidth = new() + { + "宽", "窄" + }; + + public static ObservableCollection Scanadd = new() + { + "删除", "添加" + }; + + public static ObservableCollection BusyLock = new() + { + "关", "开" + }; + + public static ObservableCollection Pttid = new() + { + "无", "按下PTT", "松开PTT", "按下和松开PTT" + }; + + public static ObservableCollection SigGrp = new() + { + "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", + "14", "15" + }; + + public static ObservableCollection Qtdqt = new() + { + "OFF", "67.0", "69.3", "71.9", "74.4", "77.0", "79.7", "82.5", "85.4", "88.5", + "91.5", "94.8", "97.4", "100.0", "103.5", "107.2", "110.9", "114.8", "118.8", "123.0", + "127.3", "131.8", "136.5", "141.3", "146.2", "151.4", "156.7", "159.8", "162.2", "165.5", + "167.9", "171.3", "173.8", "177.3", "179.9", "183.5", "186.2", "189.9", "192.8", "196.6", + "199.5", "203.5", "206.5", "210.7", "218.1", "225.7", "229.1", "233.6", "241.8", "250.3", + "254.1", "D023N", "D025N", "D026N", "D031N", "D032N", "D036N", "D043N", "D047N", "D051N", + "D053N", "D054N", "D065N", "D071N", "D072N", "D073N", "D074N", "D114N", "D115N", "D116N", + "D122N", "D125N", "D131N", "D132N", "D134N", "D143N", "D145N", "D152N", "D155N", "D156N", + "D162N", "D165N", "D172N", "D174N", "D205N", "D212N", "D223N", "D225N", "D226N", "D243N", + "D244N", "D245N", "D246N", "D251N", "D252N", "D255N", "D261N", "D263N", "D265N", "D266N", + "D271N", "D274N", "D306N", "D311N", "D315N", "D325N", "D331N", "D332N", "D343N", "D346N", + "D351N", "D356N", "D364N", "D365N", "D371N", "D411N", "D412N", "D413N", "D423N", "D431N", + "D432N", "D445N", "D446N", "D452N", "D454N", "D455N", "D462N", "D464N", "D465N", "D466N", + "D503N", "D506N", "D516N", "D523N", "D526N", "D532N", "D546N", "D565N", "D606N", "D612N", + "D624N", "D627N", "D631N", "D632N", "D645N", "D654N", "D662N", "D664N", "D703N", "D712N", + "D723N", "D731N", "D732N", "D734N", "D743N", "D754N", "D023I", "D025I", "D026I", "D031I", + "D032I", "D036I", "D043I", "D047I", "D051I", "D053I", "D054I", "D065I", "D071I", "D072I", + "D073I", "D074I", "D114I", "D115I", "D116I", "D122I", "D125I", "D131I", "D132I", "D134I", + "D143I", "D145I", "D152I", "D155I", "D156I", "D162I", "D165I", "D172I", "D174I", "D205I", + "D212I", "D223I", "D225I", "D226I", "D243I", "D244I", "D245I", "D246I", "D251I", "D252I", + "D255I", "D261I", "D263I", "D265I", "D266I", "D271I", "D274I", "D306I", "D311I", "D315I", + "D325I", "D331I", "D332I", "D343I", "D346I", "D351I", "D356I", "D364I", "D365I", "D371I", + "D411I", "D412I", "D413I", "D423I", "D431I", "D432I", "D445I", "D446I", "D452I", "D454I", + "D455I", "D462I", "D464I", "D465I", "D466I", "D503I", "D506I", "D516I", "D523I", "D526I", + "D532I", "D546I", "D565I", "D606I", "D612I", "D624I", "D627I", "D631I", "D632I", "D645I", + "D654I", "D662I", "D664I", "D703I", "D712I", "D723I", "D731I", "D732I", "D734I", "D743I", + "D754I" + }; +} \ No newline at end of file diff --git a/Constants/Shx8800Pro/FREQ.cs b/Constants/Shx8800Pro/FREQ.cs new file mode 100644 index 0000000..ebc21dc --- /dev/null +++ b/Constants/Shx8800Pro/FREQ.cs @@ -0,0 +1,7 @@ +namespace SenhaixFreqWriter.Constants.Shx8800Pro; + +public class Freq +{ + public static int MaxFreq = 520; + public static int MinFreq = 100; +} \ No newline at end of file diff --git a/Constants/Shx8800Pro/VFO_CHOICE.cs b/Constants/Shx8800Pro/VFO_CHOICE.cs new file mode 100644 index 0000000..cfbeb59 --- /dev/null +++ b/Constants/Shx8800Pro/VFO_CHOICE.cs @@ -0,0 +1,74 @@ +using System.Collections.ObjectModel; + +namespace SenhaixFreqWriter.Constants.Shx8800Pro; + +public class VfoChoice +{ + public static ObservableCollection Qtdqt = new() + { + "OFF", "67.0", "69.3", "71.9", "74.4", "77.0", "79.7", "82.5", "85.4", "88.5", + "91.5", "94.8", "97.4", "100.0", "103.5", "107.2", "110.9", "114.8", "118.8", "123.0", + "127.3", "131.8", "136.5", "141.3", "146.2", "151.4", "156.7", "159.8", "162.2", "165.5", + "167.9", "171.3", "173.8", "177.3", "179.9", "183.5", "186.2", "189.9", "192.8", "196.6", + "199.5", "203.5", "206.5", "210.7", "218.1", "225.7", "229.1", "233.6", "241.8", "250.3", + "254.1", "D023N", "D025N", "D026N", "D031N", "D032N", "D036N", "D043N", "D047N", "D051N", + "D053N", "D054N", "D065N", "D071N", "D072N", "D073N", "D074N", "D114N", "D115N", "D116N", + "D122N", "D125N", "D131N", "D132N", "D134N", "D143N", "D145N", "D152N", "D155N", "D156N", + "D162N", "D165N", "D172N", "D174N", "D205N", "D212N", "D223N", "D225N", "D226N", "D243N", + "D244N", "D245N", "D246N", "D251N", "D252N", "D255N", "D261N", "D263N", "D265N", "D266N", + "D271N", "D274N", "D306N", "D311N", "D315N", "D325N", "D331N", "D332N", "D343N", "D346N", + "D351N", "D356N", "D364N", "D365N", "D371N", "D411N", "D412N", "D413N", "D423N", "D431N", + "D432N", "D445N", "D446N", "D452N", "D454N", "D455N", "D462N", "D464N", "D465N", "D466N", + "D503N", "D506N", "D516N", "D523N", "D526N", "D532N", "D546N", "D565N", "D606N", "D612N", + "D624N", "D627N", "D631N", "D632N", "D645N", "D654N", "D662N", "D664N", "D703N", "D712N", + "D723N", "D731N", "D732N", "D734N", "D743N", "D754N", "D023I", "D025I", "D026I", "D031I", + "D032I", "D036I", "D043I", "D047I", "D051I", "D053I", "D054I", "D065I", "D071I", "D072I", + "D073I", "D074I", "D114I", "D115I", "D116I", "D122I", "D125I", "D131I", "D132I", "D134I", + "D143I", "D145I", "D152I", "D155I", "D156I", "D162I", "D165I", "D172I", "D174I", "D205I", + "D212I", "D223I", "D225I", "D226I", "D243I", "D244I", "D245I", "D246I", "D251I", "D252I", + "D255I", "D261I", "D263I", "D265I", "D266I", "D271I", "D274I", "D306I", "D311I", "D315I", + "D325I", "D331I", "D332I", "D343I", "D346I", "D351I", "D356I", "D364I", "D365I", "D371I", + "D411I", "D412I", "D413I", "D423I", "D431I", "D432I", "D445I", "D446I", "D452I", "D454I", + "D455I", "D462I", "D464I", "D465I", "D466I", "D503I", "D506I", "D516I", "D523I", "D526I", + "D532I", "D546I", "D565I", "D606I", "D612I", "D624I", "D627I", "D631I", "D632I", "D645I", + "D654I", "D662I", "D664I", "D703I", "D712I", "D723I", "D731I", "D732I", "D734I", "D743I", + "D754I" + }; + + public static ObservableCollection BusyLock = new() + { + "关", "开" + }; + + public static ObservableCollection Direction = new() + { + "OFF", "+", "-" + }; + + public static ObservableCollection SigGroup = new() + { + "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", + "11", "12", "13", "14", "15" + }; + + public static ObservableCollection Step = new() + { + "2.5 KHz", "5.0 KHz", "6.25 KHz", "10.0 KHz", "12.5 KHz", "20.0 KHz", "25.0 KHz", "50.0 KHz" + }; + + public static ObservableCollection Bandwidth = new() + { + "宽", "窄" + }; + + public static ObservableCollection Power = new() + { + "高", "中", "低" + }; + + + public static ObservableCollection Pttid = new() + { + "无", "发射开始", "发射结束", "两者" + }; +} \ No newline at end of file diff --git a/DataModels/Shx8800Pro/AppData.cs b/DataModels/Shx8800Pro/AppData.cs new file mode 100644 index 0000000..afa73cc --- /dev/null +++ b/DataModels/Shx8800Pro/AppData.cs @@ -0,0 +1,92 @@ +using System; +using System.IO; +using System.Text; +using MsBox.Avalonia; +using Newtonsoft.Json; + +namespace SenhaixFreqWriter.DataModels.Shx8800Pro; + +public class AppData +{ + [JsonIgnore] public static AppData Instance; + + public string[] BankName = new string[30] + { + "区域一", "区域二", "区域三", "区域四", "区域五", "区域六", "区域七", "区域八", "区域九", "区域十", + "区域十一", "区域十二", "区域十三", "区域十四", "区域十五", "区域十六", "区域十七", "区域十八", "区域十九", "区域二十", + "区域二十一", "区域二十二", "区域二十三", "区域二十四", "区域二十五", "区域二十六", "区域二十七", "区域二十八", "区域二十九", "区域三十" + };// + + public Channel[][] ChannelList = new Channel[8][];// + public Dtmf Dtmfs = new();// + public FmChannel Fms = new();// + public Function FunCfgs = new();// + public Mdc1200 Mdcs = new();// + public VfoInfos Vfos = new();// + + public AppData() + { + for (var i = 0; i < 8; i++) + { + ChannelList[i] = new Channel[64]; + for (var j = 0; j < 64; j++) + { + var rmp = new Channel(); + rmp.Id = j + 1; + ChannelList[i][j] = rmp; + } + } + } + + public static AppData GetInstance() + { + if (Instance != null) return Instance; + + Instance = new AppData(); + return Instance; + } + + public static AppData ForceNewInstance() + { + Instance = new AppData(); + return Instance; + } + + public void SaveToFile(Stream s) + { + var serializer = new JsonSerializer(); + serializer.Formatting = Formatting.Indented; + using (var streamWriter = new StreamWriter(s, Encoding.UTF8)) + { + serializer.Serialize(streamWriter, Instance); + } + } + + + public static void CreatObjFromFile(Stream s) + { + using (var streamReader = new StreamReader(s, Encoding.UTF8)) + { + var res = streamReader.ReadToEnd(); + AppData tmp; + try + { + var jsonSerializer = new JsonSerializer(); + var stringReader = new JsonTextReader(new StringReader(res)); + tmp = jsonSerializer.Deserialize(stringReader); + Instance.Dtmfs = tmp.Dtmfs; + Instance.FunCfgs = tmp.FunCfgs; + Instance.Fms = tmp.Fms; + Instance.Mdcs = tmp.Mdcs; + Instance.Vfos = tmp.Vfos; + Instance.BankName = tmp.BankName; + Instance.ChannelList = tmp.ChannelList; + } + catch (Exception e) + { + // DebugWindow.GetInstance().updateDebugContent(e.Message); + MessageBoxManager.GetMessageBoxStandard("注意", "无效的文件").ShowAsync(); + } + } + } +} \ No newline at end of file diff --git a/DataModels/Shx8800Pro/Channel.cs b/DataModels/Shx8800Pro/Channel.cs new file mode 100644 index 0000000..d6ff709 --- /dev/null +++ b/DataModels/Shx8800Pro/Channel.cs @@ -0,0 +1,63 @@ +using System.IO; +using System.Xml.Serialization; +using CommunityToolkit.Mvvm.ComponentModel; + +namespace SenhaixFreqWriter.DataModels.Shx8800Pro; + +public partial class Channel : ObservableObject +{ + [ObservableProperty] private int _bandwide;// + + [ObservableProperty] + // Useless member: id + private int _id; // + + [XmlIgnore] [ObservableProperty] private bool _isVisable; + + [ObservableProperty] private string _name = "";// + [ObservableProperty] private int _pttid;// + [ObservableProperty] private string _rxFreq = "";// + [ObservableProperty] private int _scanAdd;// + [ObservableProperty] private int _signalGroup;// + [ObservableProperty] private int _busyLock; + [ObservableProperty] private string _strRxCtsDcs = "OFF";// + [ObservableProperty] private string _strTxCtsDcs = "OFF";// + [ObservableProperty] private string _txFreq = "";// + [ObservableProperty] private int _txPower;// + + public Channel() + { + } + + public Channel(int id, string rxFreq, string rxCts, string txFreq, string txCts, int power, int bandwide, + int scanAdd, int busyLock, int pttid, int signal, string name) + { + _id = id; + _rxFreq = rxFreq; + _strRxCtsDcs = rxCts; + _txFreq = txFreq; + _strTxCtsDcs = txCts; + _txPower = power; + _bandwide = bandwide; + _scanAdd = scanAdd; + _pttid = pttid; + _signalGroup = signal; + _busyLock = busyLock; + _name = name; + } + + public Channel DeepCopy() + { + Channel rel; + using (var ms = new MemoryStream()) + { + var xml = new XmlSerializer(typeof(Channel)); + xml.Serialize(ms, this); + ms.Seek(0, SeekOrigin.Begin); + rel = (Channel)xml.Deserialize(ms); + ms.Close(); + } + + return rel; + } +} \ No newline at end of file diff --git a/DataModels/Shx8800Pro/DTMF.cs b/DataModels/Shx8800Pro/DTMF.cs new file mode 100644 index 0000000..a91bb72 --- /dev/null +++ b/DataModels/Shx8800Pro/DTMF.cs @@ -0,0 +1,64 @@ +using CommunityToolkit.Mvvm.ComponentModel; + +namespace SenhaixFreqWriter.DataModels.Shx8800Pro; + +public partial class Dtmf : ObservableObject +{ + [ObservableProperty] private string[] _group = new string[20]; + [ObservableProperty] private string[] _groupName = new string[20]; + [ObservableProperty] private int _idleTime = 1; + [ObservableProperty] private string _localId = "100"; + [ObservableProperty] private int _wordTime = 1; + [ObservableProperty] private int pttid = 0; + + public Dtmf() + { + Group[0] = "101"; + GroupName[0] = "成员1"; + Group[1] = "102"; + GroupName[1] = "成员2"; + Group[2] = "103"; + GroupName[2] = "成员3"; + Group[3] = "104"; + GroupName[3] = "成员4"; + Group[4] = "105"; + GroupName[4] = "成员5"; + Group[5] = "106"; + GroupName[5] = "成员6"; + Group[6] = "107"; + GroupName[6] = "成员7"; + Group[7] = "108"; + GroupName[7] = "成员8"; + Group[8] = "109"; + GroupName[8] = "成员9"; + Group[9] = "110"; + GroupName[9] = "成员10"; + Group[10] = "111"; + GroupName[10] = "成员11"; + Group[11] = "112"; + GroupName[11] = "成员12"; + Group[12] = "113"; + GroupName[12] = "成员13"; + Group[13] = "114"; + GroupName[13] = "成员14"; + Group[14] = "115"; + GroupName[14] = "成员15"; + Group[15] = "116"; + GroupName[15] = "成员16"; + Group[16] = "117"; + GroupName[16] = "成员17"; + Group[17] = "118"; + GroupName[17] = "成员18"; + Group[18] = "119"; + GroupName[18] = "成员19"; + Group[19] = "120"; + GroupName[19] = "成员20"; + } +} + +public partial class DtmpObject : ObservableObject +{ + [ObservableProperty] private string _group; + [ObservableProperty] private string _groupName; + [ObservableProperty] private string _id; +} \ No newline at end of file diff --git a/DataModels/Shx8800Pro/FMChannel.cs b/DataModels/Shx8800Pro/FMChannel.cs new file mode 100644 index 0000000..2603d6f --- /dev/null +++ b/DataModels/Shx8800Pro/FMChannel.cs @@ -0,0 +1,15 @@ +using CommunityToolkit.Mvvm.ComponentModel; + +namespace SenhaixFreqWriter.DataModels.Shx8800Pro; + +public partial class FmChannel : ObservableObject +{ + [ObservableProperty] private int[] _channels = new int[15]; + [ObservableProperty] private int _curFreq = 904; +} + +public partial class FmObject : ObservableObject +{ + [ObservableProperty] private string _freq = ""; + [ObservableProperty] private int _id; +} \ No newline at end of file diff --git a/DataModels/Shx8800Pro/Function.cs b/DataModels/Shx8800Pro/Function.cs new file mode 100644 index 0000000..edf2fdc --- /dev/null +++ b/DataModels/Shx8800Pro/Function.cs @@ -0,0 +1,45 @@ +using CommunityToolkit.Mvvm.ComponentModel; + +namespace SenhaixFreqWriter.DataModels.Shx8800Pro; + +public partial class Function : ObservableObject +{ + [ObservableProperty] private int _alarmMode;// + [ObservableProperty] private int _autoLock = 2;// + [ObservableProperty] private int _backlight = 5;// + [ObservableProperty] private int _beep = 1;// + [ObservableProperty] private int _bluetoothAudioGain = 2;// + [ObservableProperty] private int _btMicGain = 2;// + [ObservableProperty] private string _callSign = "";// + [ObservableProperty] private int _chADisType;// + [ObservableProperty] private int _chAWorkmode;// + [ObservableProperty] private int _chBDisType;// + [ObservableProperty] private int _chBWorkmode;// + [ObservableProperty] private int _curBankA;// + [ObservableProperty] private int _curBankB;// + [ObservableProperty] private int _dualStandby;// + [ObservableProperty] private int _fmEnable;// + [ObservableProperty] private int _key2Long = 1;// + [ObservableProperty] private int _key2Short;// + [ObservableProperty] private int _keyLock;// + [ObservableProperty] private int _localSosTone = 1;// + [ObservableProperty] private int _menuQuitTime = 1;// + [ObservableProperty] private int _micGain = 1;// + [ObservableProperty] private int _powerOnDisType;// + [ObservableProperty] private int _pwrOnDlyTime;// + [ObservableProperty] private int _pttDly = 4;// + [ObservableProperty] private int _roger;// + [ObservableProperty] private int _rptTailClear = 5;// + [ObservableProperty] private int _rptTailDet = 5;// + [ObservableProperty] private int _saveMode = 1;// + [ObservableProperty] private int _scanMode = 1;// + [ObservableProperty] private int _sideTone;// + [ObservableProperty] private int _sql = 3;// + [ObservableProperty] private int _tailClear = 1;// + [ObservableProperty] private int _tone = 2;// + [ObservableProperty] private int _tot = 2;// + [ObservableProperty] private int _voiceSw = 1;// + [ObservableProperty] private int _vox = 1;// + [ObservableProperty] private int _voxDlyTime = 5;// + [ObservableProperty] private int _voxSw;// +} \ No newline at end of file diff --git a/DataModels/Shx8800Pro/MDC1200.cs b/DataModels/Shx8800Pro/MDC1200.cs new file mode 100644 index 0000000..b9b6906 --- /dev/null +++ b/DataModels/Shx8800Pro/MDC1200.cs @@ -0,0 +1,10 @@ +using CommunityToolkit.Mvvm.ComponentModel; + +namespace SenhaixFreqWriter.DataModels.Shx8800Pro; + +public partial class Mdc1200 : ObservableObject +{ + [ObservableProperty] private string _callId = ""; + [ObservableProperty] private string _group = "111"; + [ObservableProperty] private string _id = "1111"; +} \ No newline at end of file diff --git a/DataModels/Shx8800Pro/VFOInfos.cs b/DataModels/Shx8800Pro/VFOInfos.cs new file mode 100644 index 0000000..9516dcb --- /dev/null +++ b/DataModels/Shx8800Pro/VFOInfos.cs @@ -0,0 +1,34 @@ +using CommunityToolkit.Mvvm.ComponentModel; + +namespace SenhaixFreqWriter.DataModels.Shx8800Pro; + +public partial class VfoInfos : ObservableObject +{ + [ObservableProperty] private int _pttid;// + [ObservableProperty] private string _strVfoaRxCtsDcs = "OFF";// + [ObservableProperty] private string _strVfoaTxCtsDcs = "OFF";// + [ObservableProperty] private string _strVfobRxCtsDcs = "OFF";// + [ObservableProperty] private string _strVfobTxCtsDcs = "OFF";// + [ObservableProperty] private int _vfoABandwide;// + [ObservableProperty] private int _vfoABusyLock;// + [ObservableProperty] private int _vfoADir;// + [ObservableProperty] private string _vfoAFreq = "440.62500";// + [ObservableProperty] private string _vfoAOffset = "00.0000";// + [ObservableProperty] private int _vfoAScram;// + [ObservableProperty] private int _vfoASignalGroup;// + [ObservableProperty] private int _vfoASignalSystem;// + [ObservableProperty] private int _vfoAsqMode;// + [ObservableProperty] private int _vfoAStep;// + [ObservableProperty] private int _vfoATxPower;// + [ObservableProperty] private int _vfoBBandwide;// + [ObservableProperty] private int _vfoBBusyLock;// + [ObservableProperty] private int _vfoBDir;// + [ObservableProperty] private string _vfoBFreq = "145.62500";// + [ObservableProperty] private string _vfoBOffset = "00.0000";// + [ObservableProperty] private int _vfoBScram;// + [ObservableProperty] private int _vfoBSignalGroup;// + [ObservableProperty] private int _vfoBSignalSystem;// + [ObservableProperty] private int _vfoBsqMode;// + [ObservableProperty] private int _vfoBStep;// + [ObservableProperty] private int _vfoBTxPower;// +} \ No newline at end of file diff --git a/DataModels/Shx8x00/readme b/DataModels/Shx8x00/readme new file mode 100644 index 0000000..219ecf7 --- /dev/null +++ b/DataModels/Shx8x00/readme @@ -0,0 +1 @@ +This is for shx8800/shx8600/shx8600pro --- they're almost same in the data structure! \ No newline at end of file diff --git a/Views/Common/DeviceSelectWindow.axaml b/Views/Common/DeviceSelectWindow.axaml index 3733fc8..85450cf 100644 --- a/Views/Common/DeviceSelectWindow.axaml +++ b/Views/Common/DeviceSelectWindow.axaml @@ -8,6 +8,7 @@ + diff --git a/Views/Common/DeviceSelectWindow.axaml.cs b/Views/Common/DeviceSelectWindow.axaml.cs index 867afe3..fd1e7d5 100644 --- a/Views/Common/DeviceSelectWindow.axaml.cs +++ b/Views/Common/DeviceSelectWindow.axaml.cs @@ -43,6 +43,10 @@ private async void Device_OnClick(object? sender, RoutedEventArgs e) new MainWindow(SHX_DEVICE.SHX8800).Show(); break; case 1: + DebugWindow.GetInstance().updateDebugContent("用户选择森海克斯8800新版"); + new Shx8800Pro.MainWindow().Show(); + break; + case 2: ChanChoice.TxPwr.Clear(); ChanChoice.TxPwr.Add("L"); ChanChoice.TxPwr.Add("H"); @@ -54,7 +58,7 @@ private async void Device_OnClick(object? sender, RoutedEventArgs e) DebugWindow.GetInstance().updateDebugContent("用户选择森海克斯8600"); new MainWindow(SHX_DEVICE.SHX8600).Show(); break; - case 2: + case 3: ChanChoice.TxPwr.Clear(); ChanChoice.TxPwr.Add("L"); ChanChoice.TxPwr.Add("M"); @@ -67,7 +71,7 @@ private async void Device_OnClick(object? sender, RoutedEventArgs e) DebugWindow.GetInstance().updateDebugContent("用户选择森海克斯8600新版"); new MainWindow(SHX_DEVICE.SHX8600PRO).Show(); break; - case 3: + case 4: DebugWindow.GetInstance().updateDebugContent("用户选择森海克斯GT12"); new Gt12.MainWindow().Show(); break; diff --git a/Views/Shx8800Pro/MainWindow.axaml b/Views/Shx8800Pro/MainWindow.axaml new file mode 100644 index 0000000..426b834 --- /dev/null +++ b/Views/Shx8800Pro/MainWindow.axaml @@ -0,0 +1,310 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Views/Shx8800Pro/MainWindow.axaml.cs b/Views/Shx8800Pro/MainWindow.axaml.cs new file mode 100644 index 0000000..efb6a74 --- /dev/null +++ b/Views/Shx8800Pro/MainWindow.axaml.cs @@ -0,0 +1,511 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Avalonia.Controls; +using Avalonia.Interactivity; +using Avalonia.Platform.Storage; +using Avalonia.Styling; +using Avalonia.Threading; +using MsBox.Avalonia; +using MsBox.Avalonia.Enums; +using SenhaixFreqWriter.Constants.Common; +using SenhaixFreqWriter.Constants.Shx8800Pro; +using SenhaixFreqWriter.DataModels.Shx8800Pro; +using SenhaixFreqWriter.Utils.BLE.Interfaces; +using SenhaixFreqWriter.Views.Common; +using SenhaixFreqWriter.Views.Plugin; +#if WINDOWS +using SenhaixFreqWriter.Utils.BLE.Platforms.Windows; +#endif + +namespace SenhaixFreqWriter.Views.Shx8800Pro; + +public partial class MainWindow : Window +{ + private Channel _copiedChannel; + + private bool _devSwitchFlag; + + private string _filePath = ""; + + private IBluetooth _osBle; + + public int CurrentArea; + + private CancellationTokenSource cancelTips; + + public MainWindow() + { + InitializeComponent(); + cancelTips = new CancellationTokenSource(); + Task.Run(() => updateTips(cancelTips.Token)); + DataContext = this; + SetArea(0); + ListItems.CollectionChanged += CollectionChangedHandler; + Closed += OnWindowClosed; + } + + public ObservableCollection ListItems { get; set; } = new(); + + private async void updateTips(CancellationToken token) + { + while (!token.IsCancellationRequested) + { + Dispatcher.UIThread.Invoke(() => { tipBlock.Text = TIPS.TipList[new Random().Next(TIPS.TipList.Count)]; }); + await Task.Delay(5000, CancellationToken.None); + } + } + + private void About_OnClick(object? sender, RoutedEventArgs e) + { + var aboutWindow = new AboutWindow(); + aboutWindow.ShowDialog(this); + } + + private void OnWindowClosed(object? sender, EventArgs e) + { + Close(); + if (!_devSwitchFlag) Environment.Exit(0); + } + + private void CollectionChangedHandler(object sender, NotifyCollectionChangedEventArgs e) + { + // if (e.Action.Equals(NotifyCollectionChangedAction.Add) || + // e.Action.Equals(NotifyCollectionChangedAction.Remove)) + // { + CalcSeq(); + AppData.GetInstance().ChannelList[CurrentArea] = ListItems.ToArray(); + // } + } + + private void CalcSeq() + { + for (var i = 0; i < ListItems.Count; i++) ListItems[i].Id = i + 1; + } + + private string CalcNameSize(string name) + { + var num = 0; + var num2 = 0; + var text = name; + var bytes = Encoding.GetEncoding("gb2312").GetBytes(text); + if (bytes.Length > 12) + { + var num3 = 0; + while (num3 < 12) + if (bytes[num3] >= 47 && bytes[num3] < 127) + { + num++; + num3++; + } + else + { + num2++; + num3 += 2; + } + + text = num % 2 == 0 + ? Encoding.GetEncoding("gb2312").GetString(bytes, 0, 12) + : Encoding.GetEncoding("gb2312").GetString(bytes, 0, 11); + } + + return text; + } + + private void SetArea(int area) + { + CurrentArea = area; + var tmpChannel = AppData.GetInstance().ChannelList[area]; + ListItems.Clear(); + for (var i = 0; i < tmpChannel.Length; i++) ListItems.Add(tmpChannel[i]); + areaName.Text = AppData.GetInstance().BankName[area]; + areaLabel.Content = $"{area + 1}/8"; + } + + private async void readChannel_OnClick(object? sender, RoutedEventArgs e) + { + // await new ProgressBarWindow(OpType.Read).ShowDialog(this); + // SetArea(0); + } + + private async void writeChannel_OnClick(object? sender, RoutedEventArgs e) + { + // await new ProgressBarWindow(OpType.Write).ShowDialog(this); + // SetArea(0); + } + + private void foreChan_OnClick(object? sender, RoutedEventArgs e) + { + if (CurrentArea > 0) SetArea(CurrentArea - 1); + } + + private void nextChan_OnClick(object? sender, RoutedEventArgs e) + { + if (CurrentArea < 7) SetArea(CurrentArea + 1); + } + + private void jumpChan_OnClick(object? sender, RoutedEventArgs e) + { + var tarChan = jumpTextBox.Text; + int res; + if (int.TryParse(tarChan, out res)) + if (res is > 0 and < 9) + SetArea(res - 1); + + jumpTextBox.Text = ""; + } + + private void Light_OnClick(object? sender, RoutedEventArgs e) + { + RequestedThemeVariant = ThemeVariant.Light; + } + + private void Dark_OnClick(object? sender, RoutedEventArgs e) + { + RequestedThemeVariant = ThemeVariant.Dark; + } + + private void AreaName_OnLostFocus(object? sender, RoutedEventArgs e) + { + if (string.IsNullOrEmpty(areaName.Text)) + { + areaName.Text = AppData.GetInstance().BankName[CurrentArea]; + return; + } + + areaName.Text = CalcNameSize(areaName.Text); + AppData.GetInstance().BankName[CurrentArea] = CalcNameSize(areaName.Text); + } + + private string FreqChecker(string text) + { + var num = 0; + // 检查频率范围 + if (!double.TryParse(text, out _)) + { + MessageBoxManager.GetMessageBoxStandard("注意", "输入频率格式有误").ShowWindowDialogAsync(this); + return "-1"; + } + + var array = text.Split('.'); + var list = new List(); + for (var j = 0; j < array.Length; j++) list.Add(int.Parse(array[j])); + + if (list[0] < Freq.MinFreq || list[0] >= Freq.MaxFreq) + { + MessageBoxManager.GetMessageBoxStandard("注意", "输入频率格式有误").ShowWindowDialogAsync(this); + return "-1"; + } + + num = list[0] * 100000; + if (list.Count > 1) + { + var num5 = 5 - array[1].Length; + if (num5 > 0) + for (var k = 0; k < num5; k++) + list[1] *= 10; + + num += list[1]; + } + + if (num % 125 != 0) + { + num /= 125; + num *= 125; + } + + return num.ToString().Insert(3, "."); + } + + + private void txFreq_OnLostFocus(object? sender, RoutedEventArgs e) + { + var textBox = (TextBox)sender; + var dataContext = textBox.DataContext as Channel; + var id = dataContext.Id; + if (string.IsNullOrEmpty(dataContext.TxFreq)) return; + + var parsed = FreqChecker(dataContext.TxFreq); + if (parsed.Equals("-1")) + { + dataContext.TxFreq = ""; + ListItems[id - 1] = dataContext; + return; + } + + dataContext.TxFreq = parsed; + ListItems[id - 1] = dataContext; + } + + private void rxfreq_OnLostFocus(object? sender, RoutedEventArgs e) + { + var textBox = (TextBox)sender; + var dataContext = textBox.DataContext as Channel; + var id = dataContext.Id; + if (string.IsNullOrEmpty(dataContext.RxFreq)) return; + + var parsed = FreqChecker(dataContext.RxFreq); + if (parsed.Equals("-1")) + { + dataContext.RxFreq = ""; + ListItems[id - 1] = dataContext; + return; + } + + // 写入默认值 + if (!dataContext.IsVisable) + { + var data = new Channel + { + Id = id, + RxFreq = parsed, + StrRxCtsDcs = "OFF", + TxFreq = parsed, + StrTxCtsDcs = "OFF", + TxPower = 0, + Bandwide = 0, + ScanAdd = 0, + SignalGroup = 0, + BusyLock = 0, + Pttid = 0, + IsVisable = true + }; + ListItems[id - 1] = data; + } + else + { + dataContext.RxFreq = parsed; + ListItems[id - 1] = dataContext; + } + } + + private void SwitchDevice_OnClick(object? sender, RoutedEventArgs e) + { + _devSwitchFlag = true; + new DeviceSelectWindow().Show(); + Close(); + } + + private void MenuCopyChannel_OnClick(object? sender, RoutedEventArgs e) + { + var selected = channelDataGrid.SelectedIndex; + _copiedChannel = ListItems[selected]; + } + + private void MenuCutChannel_OnClick(object? sender, RoutedEventArgs e) + { + var selected = channelDataGrid.SelectedIndex; + _copiedChannel = ListItems[selected].DeepCopy(); + ListItems[selected] = new Channel(); + CalcSeq(); + } + + private void MenuPasteChannel_OnClick(object? sender, RoutedEventArgs e) + { + if (_copiedChannel == null) return; + var selected = channelDataGrid.SelectedIndex; + ListItems[selected] = _copiedChannel.DeepCopy(); + CalcSeq(); + } + + private void MenuClrChannel_OnClick(object? sender, RoutedEventArgs e) + { + var selected = new List(); + foreach (var selectedItem in channelDataGrid.SelectedItems) selected.Add(((Channel)selectedItem).Id - 1); + foreach (var o in selected) ListItems[o] = new Channel(); + // var selected = channelDataGrid.SelectedIndex; + // ListItems[selected] = new Channel(); + CalcSeq(); + } + + private void MenuDelChannel_OnClick(object? sender, RoutedEventArgs e) + { + var selected = channelDataGrid.SelectedIndex; + for (var i = selected; i < 63; i++) ListItems[i] = ListItems[i + 1]; + ListItems[63] = new Channel(); + CalcSeq(); + } + + private void MenuInsChannel_OnClick(object? sender, RoutedEventArgs e) + { + var selected = channelDataGrid.SelectedIndex; + if (ListItems[63].IsVisable) + { + MessageBoxManager.GetMessageBoxStandard("注意", "信道64不为空无法插入!").ShowWindowDialogAsync(this); + return; + } + + var lastEmp = 0; + for (var i = 0; i < 63; i++) + if (ListItems[i].IsVisable) + lastEmp = i; + + for (var i = lastEmp; i > selected; i--) ListItems[i + 1] = ListItems[i]; + + ListItems[selected + 1] = new Channel(); + CalcSeq(); + } + + private void MenuComChannel_OnClick(object? sender, RoutedEventArgs e) + { + var cachedChannel = new ObservableCollection(); + for (var i = 0; i < 32; i++) cachedChannel.Add(new Channel()); + var channelCursor = 0; + for (var i = 0; i < 32; i++) + if (ListItems[i].IsVisable) + cachedChannel[channelCursor++] = ListItems[i].DeepCopy(); + + for (var i = 0; i < channelCursor; i++) ListItems[i] = cachedChannel[i].DeepCopy(); + + for (var i = channelCursor; i < 32; i++) ListItems[i] = new Channel(); + CalcSeq(); + } + + private void VfoMenuItem_OnClick(object? sender, RoutedEventArgs e) + { + new VfoModeWindow().ShowDialog(this); + } + + + private void OptionalMenuItem_OnClick(object? sender, RoutedEventArgs e) + { + // new OptionalWindow().ShowDialog(this); + } + + private void FMMenuItem_OnClick(object? sender, RoutedEventArgs e) + { + // new FmWindow().ShowDialog(this); + } + + private void DTMFMenuItem_OnClick(object? sender, RoutedEventArgs e) + { + // new DtmfWindow().ShowDialog(this); + } + + private async void NewFileMenuItem_OnClick(object? sender, RoutedEventArgs e) + { + var box = MessageBoxManager + .GetMessageBoxStandard("注意", "该操作将清空编辑中的信道,确定继续?", + ButtonEnum.YesNo); + + var result = await box.ShowWindowDialogAsync(this); + if (result == ButtonResult.No) return; + AppData.ForceNewInstance(); + SetArea(0); + } + + private void SaveFileMenuItem_OnClick(object? sender, RoutedEventArgs e) + { + if (!string.IsNullOrEmpty(_filePath)) + { + Stream stream = new FileStream(_filePath, FileMode.OpenOrCreate); + stream.Seek(0L, SeekOrigin.Begin); + stream.SetLength(0L); + AppData.GetInstance().SaveToFile(stream); + stream.Close(); + } + else + { + SaveAsMenuItem_OnClick(null, null); + } + } + + private async void SaveAsMenuItem_OnClick(object? sender, RoutedEventArgs e) + { + var ts = DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss"); + var topLevel = GetTopLevel(this); + var file = await topLevel.StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions + { + Title = "保存配置文件", + SuggestedFileName = "Backup-GT12-" + ts + ".dat" + }); + if (file is not null) + { + _filePath = file.Path.LocalPath; + await using var stream = await file.OpenWriteAsync(); + stream.Seek(0L, SeekOrigin.Begin); + stream.SetLength(0L); + AppData.GetInstance().SaveToFile(stream); + stream.Close(); + } + } + + private void ExitMenuItem_OnClick(object? sender, RoutedEventArgs e) + { + Close(); + Environment.Exit(0); + } + + private async void OpenFileMenuItem_OnClick(object? sender, RoutedEventArgs e) + { + var topLevel = GetTopLevel(this); + var files = await topLevel.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions + { + Title = "打开备份", + AllowMultiple = false + }); + if (files.Count > 0) + { + await using var stream = await files[0].OpenReadAsync(); + AppData.CreatObjFromFile(stream); + SetArea(0); + } + } + + private void BootImageMenuItem_OnClick(object? sender, RoutedEventArgs e) + { + new BootImageImportWindow(SHX_DEVICE.GT12).ShowDialog(this); + } + + private void SatMenuItem_OnClick(object? sender, RoutedEventArgs e) + { + new SatelliteHelperWindow(InsertNewChannel).ShowDialog(this); + } + + private void InsertNewChannel(string rx, string dec, string tx, string enc, string name) + { + var lastEmptyIndex = -1; + for (var i = ListItems.Count - 1; i >= 0; i--) + if (!ListItems[i].IsVisable) + lastEmptyIndex = i; + else + break; + + if (lastEmptyIndex == -1) throw new IndexOutOfRangeException("信道空间已满,无法插入!"); + + var data = new Channel + { + Id = lastEmptyIndex, + RxFreq = rx, + StrRxCtsDcs = dec, + TxFreq = tx, + StrTxCtsDcs = enc, + TxPower = 0, + Bandwide = 0, + ScanAdd = 0, + SignalGroup = 0, + BusyLock = 0, + Pttid = 0, + IsVisable = true, + Name = name + }; + ListItems[lastEmptyIndex] = data; + } + + private async void BLEMenuItem_OnClick(object? sender, RoutedEventArgs e) + { + await MessageBoxManager.GetMessageBoxStandard("注意", "GT12的蓝牙写频真的超慢,不知道为啥:(建议用写频线").ShowWindowDialogAsync(this); + new BluetoothDeviceSelectionWindow(SHX_DEVICE.GT12).ShowDialog(this); + } + + private void DebugWindowMenuItem_OnClick(object? sender, RoutedEventArgs e) + { + DebugWindow.GetInstance().Show(); + } +} \ No newline at end of file diff --git a/Views/Shx8800Pro/VfoModeWindow.axaml b/Views/Shx8800Pro/VfoModeWindow.axaml new file mode 100644 index 0000000..00282bd --- /dev/null +++ b/Views/Shx8800Pro/VfoModeWindow.axaml @@ -0,0 +1,98 @@ + + + + + \ No newline at end of file diff --git a/Views/Shx8800Pro/VfoModeWindow.axaml.cs b/Views/Shx8800Pro/VfoModeWindow.axaml.cs new file mode 100644 index 0000000..4d992d4 --- /dev/null +++ b/Views/Shx8800Pro/VfoModeWindow.axaml.cs @@ -0,0 +1,208 @@ +using System.Collections.Generic; +using Avalonia.Controls; +using Avalonia.Interactivity; +using MsBox.Avalonia; +using SenhaixFreqWriter.Constants.Shx8800Pro; +using SenhaixFreqWriter.DataModels.Shx8800Pro; + +namespace SenhaixFreqWriter.Views.Shx8800Pro; + +public partial class VfoModeWindow : Window +{ + public VfoModeWindow() + { + InitializeComponent(); + DataContext = this; + } + + public VfoInfos VfoInfos { get; set; } = AppData.GetInstance().Vfos; + + private void currentFreq_OnLostFocus(object? sender, RoutedEventArgs e) + { + var num = 0; + var textBox = (TextBox)sender; + var flag = false; + var text = textBox.Text; + if (text == "") + { + MessageBoxManager.GetMessageBoxStandard("注意", "不能为空!").ShowWindowDialogAsync(this); + textBox.Text = "440.62500"; + return; + } + + if (text.Replace(".", "").Length > 8) + { + MessageBoxManager.GetMessageBoxStandard("注意", "精度过高!").ShowWindowDialogAsync(this); + textBox.Text = "440.62500"; + return; + } + + if (text != "") + { + var text2 = text; + foreach (var c in text2) + { + if (c != '.') continue; + + if (!flag) + { + flag = true; + continue; + } + + MessageBoxManager.GetMessageBoxStandard("注意", "频率格式错误!").ShowWindowDialogAsync(this); + textBox.Text = "440.62500"; + break; + } + } + + if (!(text != "")) return; + + var array = text.Split('.'); + var list = new List(); + for (var j = 0; j < array.Length; j++) + { + int res; + if (!int.TryParse(array[j], out res)) + { + MessageBoxManager.GetMessageBoxStandard("注意", "格式错误" + Freq.MinFreq + "--" + Freq.MaxFreq) + .ShowWindowDialogAsync(this); + textBox.Text = "440.62500"; + return; + } + + list.Add(res); + } + + ; + + if (list[0] < Freq.MinFreq || list[0] >= Freq.MaxFreq) + { + MessageBoxManager.GetMessageBoxStandard("注意", "频率错误!\n频率范围:" + Freq.MinFreq + "--" + Freq.MaxFreq) + .ShowWindowDialogAsync(this); + textBox.Text = "440.62500"; + return; + } + + num = list[0] * 100000; + if (list.Count > 1) + { + var num2 = 5 - array[1].Length; + if (num2 > 0) + for (var k = 0; k < num2; k++) + list[1] *= 10; + + num += list[1]; + } + + if (num % 125 != 0) + { + num /= 125; + num *= 125; + } + + textBox.Text = num.ToString().Insert(3, "."); + } + + private void freqOffset_OnLostFocus(object? sender, RoutedEventArgs e) + { + var flag = false; + var num = 0; + var textBox = (TextBox)sender; + var text = textBox.Text; + var text2 = ""; + if (text == "") + { + MessageBoxManager.GetMessageBoxStandard("注意", "不能为空!").ShowWindowDialogAsync(this); + textBox.Text = "00.0000"; + return; + } + + if (text.Replace(".", "").Length > 6) + { + MessageBoxManager.GetMessageBoxStandard("注意", "精度过高!").ShowWindowDialogAsync(this); + textBox.Text = "00.0000"; + return; + } + + if (text != "") + { + var text3 = text; + foreach (var c in text3) + { + if (c != '.') continue; + + if (!flag) + { + flag = true; + continue; + } + + MessageBoxManager.GetMessageBoxStandard("注意", "频率格式错误!").ShowWindowDialogAsync(this); + textBox.Text = "00.0000"; + break; + } + } + + if (!(text != "")) return; + + var array = text.Split('.'); + var list = new List(); + for (var j = 0; j < array.Length; j++) + { + int res; + if (!int.TryParse(array[j], out res)) + { + MessageBoxManager.GetMessageBoxStandard("注意", "格式错误" + Freq.MinFreq + "--" + Freq.MaxFreq) + .ShowWindowDialogAsync(this); + textBox.Text = "440.62500"; + return; + } + + list.Add(res); + } + + ; + + if (list[0] >= 100) + { + MessageBoxManager.GetMessageBoxStandard("注意", "频率错误!\n频率范围:" + Freq.MinFreq + "--" + Freq.MaxFreq) + .ShowWindowDialogAsync(this); + textBox.Text = "00.0000"; + return; + } + + num = list[0] * 10000; + if (list.Count > 1) + { + var num2 = 4 - array[1].Length; + if (num2 > 0) + for (var k = 0; k < num2; k++) + list[1] *= 10; + + num += list[1]; + } + + if (num % 5 != 0) + { + num /= 5; + num *= 5; + } + + text2 = num.ToString(); + text2 = num >= 100000 + ? text2.Insert(2, ".") + : num <= 0 + ? "00.0000" + : num >= 10000 + ? "0" + text2.Insert(1, ".") + : num >= 1000 + ? "00." + text2 + : num >= 100 + ? "00.0" + text2 + : num < 10 + ? "00.000" + text2 + : "00.00" + text2; + textBox.Text = text2; + } +} \ No newline at end of file diff --git a/Views/Shx8x00/MainWindow.axaml b/Views/Shx8x00/MainWindow.axaml index 0de151d..a4cfeda 100644 --- a/Views/Shx8x00/MainWindow.axaml +++ b/Views/Shx8x00/MainWindow.axaml @@ -116,10 +116,15 @@ - + + + + + +