原始导入

This commit is contained in:
pxzleo 2017-02-27 02:02:19 +08:00
commit ce44e595ff
269 changed files with 60566 additions and 0 deletions

240
Plane.Sdk3.sln Normal file
View File

@ -0,0 +1,240 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "PlaneGcsSdk_Shared", "PlaneGcsSdk_Shared\PlaneGcsSdk_Shared.shproj", "{2BE393DC-21A4-48B3-83FD-F21CBE8B038B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlaneGcsSdk_UWP", "PlaneGcsSdk_UWP\PlaneGcsSdk_UWP.csproj", "{B0226F52-8D27-4C05-8C04-536E0BCC3B99}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlaneGcsSdk_Private_NET45", "PlaneGcsSdk_Private_NET45\PlaneGcsSdk_Private_NET45.csproj", "{2CE7006F-C1DF-4A15-9E68-A63A3255FE88}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlaneGcsSdk_Private_NET46", "PlaneGcsSdk_Private_NET46\PlaneGcsSdk_Private_NET46.csproj", "{0111EB6E-72E3-499C-A3BA-022F5BBC4CAF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlaneGcsSdk_NET46", "PlaneGcsSdk_NET46\PlaneGcsSdk_NET46.csproj", "{331C28E1-5BA3-42CE-8A4A-BC468E692FED}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlaneGcsSdk.Contract", "PlaneGcsSdk.Contract\PlaneGcsSdk.Contract.csproj", "{18ECD88E-5D74-43E8-8BC2-D28F6DB13A47}"
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "PlaneGcsSdk.Contract_Shared", "PlaneGcsSdk.Contract_Shared\PlaneGcsSdk.Contract_Shared.shproj", "{695733D7-99FF-4707-8C89-474E949CADCB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlaneGcsSdk.Contract_Private", "PlaneGcsSdk.Contract_Private\PlaneGcsSdk.Contract_Private.csproj", "{47141894-ECE3-48CA-8DCF-CA751BDA231E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlaneGcsSdk.Contract.EhNetUWP", "PlaneGcsSdk.Contract.EhNetUWP\PlaneGcsSdk.Contract.EhNetUWP.csproj", "{D7D21B2B-6F73-4939-B720-FE51DA1C04C0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlaneGcsSdk.Contract.DtuClient_UWP", "PlaneGcsSdk.Contract.DtuClient_UWP\PlaneGcsSdk.Contract.DtuClient_UWP.csproj", "{2079C6FC-8EBA-4BD8-A965-EC9FB473C314}"
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "PlaneGcsSdk.Contract.DtuClient_Shared", "PlaneGcsSdk.Contract.DtuClient_Shared\PlaneGcsSdk.Contract.DtuClient_Shared.shproj", "{83D6BB5F-1643-4B9F-B3E4-D4D08CEA2733}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlaneGcsSdk.Contract.DtuClient_NET", "PlaneGcsSdk.Contract.DtuClient_NET\PlaneGcsSdk.Contract.DtuClient_NET.csproj", "{089FA525-1773-47A5-8A0A-832AB179E2D9}"
EndProject
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "PLClass", "..\myPLClass\ClassLibrary2\PLClass.vbproj", "{92E63872-4938-4F0C-9FD8-BDFE3388EEB3}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Contract", "Contract", "{4617084D-65A3-4354-B97F-1DF9254AA183}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Implementation", "Implementation", "{CDCDFD04-CD05-4CAA-BBA4-6166A5119495}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Document", "Document", "{CD21427C-22BF-4D7C-86EF-23B1E594A7B7}"
ProjectSection(SolutionItems) = preProject
README_Private.md = README_Private.md
EndProjectSection
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
PlaneGcsSdk_Shared\PlaneGcsSdk_Shared.projitems*{0111eb6e-72e3-499c-a3ba-022f5bbc4caf}*SharedItemsImports = 4
PlaneGcsSdk.Contract.DtuClient_Shared\PlaneGcsSdk.Contract.DtuClient_Shared.projitems*{089fa525-1773-47a5-8a0a-832ab179e2d9}*SharedItemsImports = 4
PlaneGcsSdk.Contract_Shared\PlaneGcsSdk.Contract_Shared.projitems*{18ecd88e-5d74-43e8-8bc2-d28f6db13a47}*SharedItemsImports = 4
PlaneGcsSdk.Contract.DtuClient_Shared\PlaneGcsSdk.Contract.DtuClient_Shared.projitems*{2079c6fc-8eba-4bd8-a965-ec9fb473c314}*SharedItemsImports = 4
PlaneGcsSdk_Shared\PlaneGcsSdk_Shared.projitems*{2be393dc-21a4-48b3-83fd-f21cbe8b038b}*SharedItemsImports = 13
PlaneGcsSdk_Shared\PlaneGcsSdk_Shared.projitems*{2ce7006f-c1df-4a15-9e68-a63a3255fe88}*SharedItemsImports = 4
PlaneGcsSdk_Shared\PlaneGcsSdk_Shared.projitems*{331c28e1-5ba3-42ce-8a4a-bc468e692fed}*SharedItemsImports = 4
PlaneGcsSdk.Contract_Shared\PlaneGcsSdk.Contract_Shared.projitems*{47141894-ece3-48ca-8dcf-ca751bda231e}*SharedItemsImports = 4
PlaneGcsSdk.Contract_Shared\PlaneGcsSdk.Contract_Shared.projitems*{695733d7-99ff-4707-8c89-474e949cadcb}*SharedItemsImports = 13
PlaneGcsSdk.Contract.DtuClient_Shared\PlaneGcsSdk.Contract.DtuClient_Shared.projitems*{83d6bb5f-1643-4b9f-b3e4-d4d08cea2733}*SharedItemsImports = 13
PlaneGcsSdk_Shared\PlaneGcsSdk_Shared.projitems*{b0226f52-8d27-4c05-8c04-536e0bcc3b99}*SharedItemsImports = 4
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|ARM = Debug|ARM
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|ARM = Release|ARM
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B0226F52-8D27-4C05-8C04-536E0BCC3B99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B0226F52-8D27-4C05-8C04-536E0BCC3B99}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B0226F52-8D27-4C05-8C04-536E0BCC3B99}.Debug|ARM.ActiveCfg = Debug|ARM
{B0226F52-8D27-4C05-8C04-536E0BCC3B99}.Debug|ARM.Build.0 = Debug|ARM
{B0226F52-8D27-4C05-8C04-536E0BCC3B99}.Debug|x64.ActiveCfg = Debug|x64
{B0226F52-8D27-4C05-8C04-536E0BCC3B99}.Debug|x64.Build.0 = Debug|x64
{B0226F52-8D27-4C05-8C04-536E0BCC3B99}.Debug|x86.ActiveCfg = Debug|x86
{B0226F52-8D27-4C05-8C04-536E0BCC3B99}.Debug|x86.Build.0 = Debug|x86
{B0226F52-8D27-4C05-8C04-536E0BCC3B99}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B0226F52-8D27-4C05-8C04-536E0BCC3B99}.Release|Any CPU.Build.0 = Release|Any CPU
{B0226F52-8D27-4C05-8C04-536E0BCC3B99}.Release|ARM.ActiveCfg = Release|ARM
{B0226F52-8D27-4C05-8C04-536E0BCC3B99}.Release|ARM.Build.0 = Release|ARM
{B0226F52-8D27-4C05-8C04-536E0BCC3B99}.Release|x64.ActiveCfg = Release|x64
{B0226F52-8D27-4C05-8C04-536E0BCC3B99}.Release|x64.Build.0 = Release|x64
{B0226F52-8D27-4C05-8C04-536E0BCC3B99}.Release|x86.ActiveCfg = Release|x86
{B0226F52-8D27-4C05-8C04-536E0BCC3B99}.Release|x86.Build.0 = Release|x86
{2CE7006F-C1DF-4A15-9E68-A63A3255FE88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2CE7006F-C1DF-4A15-9E68-A63A3255FE88}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2CE7006F-C1DF-4A15-9E68-A63A3255FE88}.Debug|ARM.ActiveCfg = Debug|Any CPU
{2CE7006F-C1DF-4A15-9E68-A63A3255FE88}.Debug|ARM.Build.0 = Debug|Any CPU
{2CE7006F-C1DF-4A15-9E68-A63A3255FE88}.Debug|x64.ActiveCfg = Debug|Any CPU
{2CE7006F-C1DF-4A15-9E68-A63A3255FE88}.Debug|x64.Build.0 = Debug|Any CPU
{2CE7006F-C1DF-4A15-9E68-A63A3255FE88}.Debug|x86.ActiveCfg = Debug|Any CPU
{2CE7006F-C1DF-4A15-9E68-A63A3255FE88}.Debug|x86.Build.0 = Debug|Any CPU
{2CE7006F-C1DF-4A15-9E68-A63A3255FE88}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2CE7006F-C1DF-4A15-9E68-A63A3255FE88}.Release|Any CPU.Build.0 = Release|Any CPU
{2CE7006F-C1DF-4A15-9E68-A63A3255FE88}.Release|ARM.ActiveCfg = Release|Any CPU
{2CE7006F-C1DF-4A15-9E68-A63A3255FE88}.Release|ARM.Build.0 = Release|Any CPU
{2CE7006F-C1DF-4A15-9E68-A63A3255FE88}.Release|x64.ActiveCfg = Release|Any CPU
{2CE7006F-C1DF-4A15-9E68-A63A3255FE88}.Release|x64.Build.0 = Release|Any CPU
{2CE7006F-C1DF-4A15-9E68-A63A3255FE88}.Release|x86.ActiveCfg = Release|Any CPU
{2CE7006F-C1DF-4A15-9E68-A63A3255FE88}.Release|x86.Build.0 = Release|Any CPU
{0111EB6E-72E3-499C-A3BA-022F5BBC4CAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0111EB6E-72E3-499C-A3BA-022F5BBC4CAF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0111EB6E-72E3-499C-A3BA-022F5BBC4CAF}.Debug|ARM.ActiveCfg = Debug|Any CPU
{0111EB6E-72E3-499C-A3BA-022F5BBC4CAF}.Debug|ARM.Build.0 = Debug|Any CPU
{0111EB6E-72E3-499C-A3BA-022F5BBC4CAF}.Debug|x64.ActiveCfg = Debug|Any CPU
{0111EB6E-72E3-499C-A3BA-022F5BBC4CAF}.Debug|x64.Build.0 = Debug|Any CPU
{0111EB6E-72E3-499C-A3BA-022F5BBC4CAF}.Debug|x86.ActiveCfg = Debug|Any CPU
{0111EB6E-72E3-499C-A3BA-022F5BBC4CAF}.Debug|x86.Build.0 = Debug|Any CPU
{0111EB6E-72E3-499C-A3BA-022F5BBC4CAF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0111EB6E-72E3-499C-A3BA-022F5BBC4CAF}.Release|Any CPU.Build.0 = Release|Any CPU
{0111EB6E-72E3-499C-A3BA-022F5BBC4CAF}.Release|ARM.ActiveCfg = Release|Any CPU
{0111EB6E-72E3-499C-A3BA-022F5BBC4CAF}.Release|ARM.Build.0 = Release|Any CPU
{0111EB6E-72E3-499C-A3BA-022F5BBC4CAF}.Release|x64.ActiveCfg = Release|Any CPU
{0111EB6E-72E3-499C-A3BA-022F5BBC4CAF}.Release|x64.Build.0 = Release|Any CPU
{0111EB6E-72E3-499C-A3BA-022F5BBC4CAF}.Release|x86.ActiveCfg = Release|Any CPU
{0111EB6E-72E3-499C-A3BA-022F5BBC4CAF}.Release|x86.Build.0 = Release|Any CPU
{331C28E1-5BA3-42CE-8A4A-BC468E692FED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{331C28E1-5BA3-42CE-8A4A-BC468E692FED}.Debug|Any CPU.Build.0 = Debug|Any CPU
{331C28E1-5BA3-42CE-8A4A-BC468E692FED}.Debug|ARM.ActiveCfg = Debug|Any CPU
{331C28E1-5BA3-42CE-8A4A-BC468E692FED}.Debug|ARM.Build.0 = Debug|Any CPU
{331C28E1-5BA3-42CE-8A4A-BC468E692FED}.Debug|x64.ActiveCfg = Debug|Any CPU
{331C28E1-5BA3-42CE-8A4A-BC468E692FED}.Debug|x64.Build.0 = Debug|Any CPU
{331C28E1-5BA3-42CE-8A4A-BC468E692FED}.Debug|x86.ActiveCfg = Debug|Any CPU
{331C28E1-5BA3-42CE-8A4A-BC468E692FED}.Debug|x86.Build.0 = Debug|Any CPU
{331C28E1-5BA3-42CE-8A4A-BC468E692FED}.Release|Any CPU.ActiveCfg = Release|Any CPU
{331C28E1-5BA3-42CE-8A4A-BC468E692FED}.Release|Any CPU.Build.0 = Release|Any CPU
{331C28E1-5BA3-42CE-8A4A-BC468E692FED}.Release|ARM.ActiveCfg = Release|Any CPU
{331C28E1-5BA3-42CE-8A4A-BC468E692FED}.Release|ARM.Build.0 = Release|Any CPU
{331C28E1-5BA3-42CE-8A4A-BC468E692FED}.Release|x64.ActiveCfg = Release|Any CPU
{331C28E1-5BA3-42CE-8A4A-BC468E692FED}.Release|x64.Build.0 = Release|Any CPU
{331C28E1-5BA3-42CE-8A4A-BC468E692FED}.Release|x86.ActiveCfg = Release|Any CPU
{331C28E1-5BA3-42CE-8A4A-BC468E692FED}.Release|x86.Build.0 = Release|Any CPU
{18ECD88E-5D74-43E8-8BC2-D28F6DB13A47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{18ECD88E-5D74-43E8-8BC2-D28F6DB13A47}.Debug|Any CPU.Build.0 = Debug|Any CPU
{18ECD88E-5D74-43E8-8BC2-D28F6DB13A47}.Debug|ARM.ActiveCfg = Debug|Any CPU
{18ECD88E-5D74-43E8-8BC2-D28F6DB13A47}.Debug|ARM.Build.0 = Debug|Any CPU
{18ECD88E-5D74-43E8-8BC2-D28F6DB13A47}.Debug|x64.ActiveCfg = Debug|Any CPU
{18ECD88E-5D74-43E8-8BC2-D28F6DB13A47}.Debug|x64.Build.0 = Debug|Any CPU
{18ECD88E-5D74-43E8-8BC2-D28F6DB13A47}.Debug|x86.ActiveCfg = Debug|Any CPU
{18ECD88E-5D74-43E8-8BC2-D28F6DB13A47}.Debug|x86.Build.0 = Debug|Any CPU
{18ECD88E-5D74-43E8-8BC2-D28F6DB13A47}.Release|Any CPU.ActiveCfg = Release|Any CPU
{18ECD88E-5D74-43E8-8BC2-D28F6DB13A47}.Release|Any CPU.Build.0 = Release|Any CPU
{18ECD88E-5D74-43E8-8BC2-D28F6DB13A47}.Release|ARM.ActiveCfg = Release|Any CPU
{18ECD88E-5D74-43E8-8BC2-D28F6DB13A47}.Release|ARM.Build.0 = Release|Any CPU
{18ECD88E-5D74-43E8-8BC2-D28F6DB13A47}.Release|x64.ActiveCfg = Release|Any CPU
{18ECD88E-5D74-43E8-8BC2-D28F6DB13A47}.Release|x64.Build.0 = Release|Any CPU
{18ECD88E-5D74-43E8-8BC2-D28F6DB13A47}.Release|x86.ActiveCfg = Release|Any CPU
{18ECD88E-5D74-43E8-8BC2-D28F6DB13A47}.Release|x86.Build.0 = Release|Any CPU
{47141894-ECE3-48CA-8DCF-CA751BDA231E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{47141894-ECE3-48CA-8DCF-CA751BDA231E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{47141894-ECE3-48CA-8DCF-CA751BDA231E}.Debug|ARM.ActiveCfg = Debug|Any CPU
{47141894-ECE3-48CA-8DCF-CA751BDA231E}.Debug|ARM.Build.0 = Debug|Any CPU
{47141894-ECE3-48CA-8DCF-CA751BDA231E}.Debug|x64.ActiveCfg = Debug|Any CPU
{47141894-ECE3-48CA-8DCF-CA751BDA231E}.Debug|x64.Build.0 = Debug|Any CPU
{47141894-ECE3-48CA-8DCF-CA751BDA231E}.Debug|x86.ActiveCfg = Debug|Any CPU
{47141894-ECE3-48CA-8DCF-CA751BDA231E}.Debug|x86.Build.0 = Debug|Any CPU
{47141894-ECE3-48CA-8DCF-CA751BDA231E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{47141894-ECE3-48CA-8DCF-CA751BDA231E}.Release|Any CPU.Build.0 = Release|Any CPU
{47141894-ECE3-48CA-8DCF-CA751BDA231E}.Release|ARM.ActiveCfg = Release|Any CPU
{47141894-ECE3-48CA-8DCF-CA751BDA231E}.Release|ARM.Build.0 = Release|Any CPU
{47141894-ECE3-48CA-8DCF-CA751BDA231E}.Release|x64.ActiveCfg = Release|Any CPU
{47141894-ECE3-48CA-8DCF-CA751BDA231E}.Release|x64.Build.0 = Release|Any CPU
{47141894-ECE3-48CA-8DCF-CA751BDA231E}.Release|x86.ActiveCfg = Release|Any CPU
{47141894-ECE3-48CA-8DCF-CA751BDA231E}.Release|x86.Build.0 = Release|Any CPU
{D7D21B2B-6F73-4939-B720-FE51DA1C04C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D7D21B2B-6F73-4939-B720-FE51DA1C04C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D7D21B2B-6F73-4939-B720-FE51DA1C04C0}.Debug|ARM.ActiveCfg = Debug|ARM
{D7D21B2B-6F73-4939-B720-FE51DA1C04C0}.Debug|ARM.Build.0 = Debug|ARM
{D7D21B2B-6F73-4939-B720-FE51DA1C04C0}.Debug|x64.ActiveCfg = Debug|x64
{D7D21B2B-6F73-4939-B720-FE51DA1C04C0}.Debug|x64.Build.0 = Debug|x64
{D7D21B2B-6F73-4939-B720-FE51DA1C04C0}.Debug|x86.ActiveCfg = Debug|x86
{D7D21B2B-6F73-4939-B720-FE51DA1C04C0}.Debug|x86.Build.0 = Debug|x86
{D7D21B2B-6F73-4939-B720-FE51DA1C04C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D7D21B2B-6F73-4939-B720-FE51DA1C04C0}.Release|Any CPU.Build.0 = Release|Any CPU
{D7D21B2B-6F73-4939-B720-FE51DA1C04C0}.Release|ARM.ActiveCfg = Release|ARM
{D7D21B2B-6F73-4939-B720-FE51DA1C04C0}.Release|ARM.Build.0 = Release|ARM
{D7D21B2B-6F73-4939-B720-FE51DA1C04C0}.Release|x64.ActiveCfg = Release|x64
{D7D21B2B-6F73-4939-B720-FE51DA1C04C0}.Release|x64.Build.0 = Release|x64
{D7D21B2B-6F73-4939-B720-FE51DA1C04C0}.Release|x86.ActiveCfg = Release|x86
{D7D21B2B-6F73-4939-B720-FE51DA1C04C0}.Release|x86.Build.0 = Release|x86
{2079C6FC-8EBA-4BD8-A965-EC9FB473C314}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2079C6FC-8EBA-4BD8-A965-EC9FB473C314}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2079C6FC-8EBA-4BD8-A965-EC9FB473C314}.Debug|ARM.ActiveCfg = Debug|ARM
{2079C6FC-8EBA-4BD8-A965-EC9FB473C314}.Debug|ARM.Build.0 = Debug|ARM
{2079C6FC-8EBA-4BD8-A965-EC9FB473C314}.Debug|x64.ActiveCfg = Debug|x64
{2079C6FC-8EBA-4BD8-A965-EC9FB473C314}.Debug|x64.Build.0 = Debug|x64
{2079C6FC-8EBA-4BD8-A965-EC9FB473C314}.Debug|x86.ActiveCfg = Debug|x86
{2079C6FC-8EBA-4BD8-A965-EC9FB473C314}.Debug|x86.Build.0 = Debug|x86
{2079C6FC-8EBA-4BD8-A965-EC9FB473C314}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2079C6FC-8EBA-4BD8-A965-EC9FB473C314}.Release|Any CPU.Build.0 = Release|Any CPU
{2079C6FC-8EBA-4BD8-A965-EC9FB473C314}.Release|ARM.ActiveCfg = Release|ARM
{2079C6FC-8EBA-4BD8-A965-EC9FB473C314}.Release|ARM.Build.0 = Release|ARM
{2079C6FC-8EBA-4BD8-A965-EC9FB473C314}.Release|x64.ActiveCfg = Release|x64
{2079C6FC-8EBA-4BD8-A965-EC9FB473C314}.Release|x64.Build.0 = Release|x64
{2079C6FC-8EBA-4BD8-A965-EC9FB473C314}.Release|x86.ActiveCfg = Release|x86
{2079C6FC-8EBA-4BD8-A965-EC9FB473C314}.Release|x86.Build.0 = Release|x86
{089FA525-1773-47A5-8A0A-832AB179E2D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{089FA525-1773-47A5-8A0A-832AB179E2D9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{089FA525-1773-47A5-8A0A-832AB179E2D9}.Debug|ARM.ActiveCfg = Debug|Any CPU
{089FA525-1773-47A5-8A0A-832AB179E2D9}.Debug|ARM.Build.0 = Debug|Any CPU
{089FA525-1773-47A5-8A0A-832AB179E2D9}.Debug|x64.ActiveCfg = Debug|Any CPU
{089FA525-1773-47A5-8A0A-832AB179E2D9}.Debug|x64.Build.0 = Debug|Any CPU
{089FA525-1773-47A5-8A0A-832AB179E2D9}.Debug|x86.ActiveCfg = Debug|Any CPU
{089FA525-1773-47A5-8A0A-832AB179E2D9}.Debug|x86.Build.0 = Debug|Any CPU
{089FA525-1773-47A5-8A0A-832AB179E2D9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{089FA525-1773-47A5-8A0A-832AB179E2D9}.Release|Any CPU.Build.0 = Release|Any CPU
{089FA525-1773-47A5-8A0A-832AB179E2D9}.Release|ARM.ActiveCfg = Release|Any CPU
{089FA525-1773-47A5-8A0A-832AB179E2D9}.Release|ARM.Build.0 = Release|Any CPU
{089FA525-1773-47A5-8A0A-832AB179E2D9}.Release|x64.ActiveCfg = Release|Any CPU
{089FA525-1773-47A5-8A0A-832AB179E2D9}.Release|x64.Build.0 = Release|Any CPU
{089FA525-1773-47A5-8A0A-832AB179E2D9}.Release|x86.ActiveCfg = Release|Any CPU
{089FA525-1773-47A5-8A0A-832AB179E2D9}.Release|x86.Build.0 = Release|Any CPU
{92E63872-4938-4F0C-9FD8-BDFE3388EEB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{92E63872-4938-4F0C-9FD8-BDFE3388EEB3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{92E63872-4938-4F0C-9FD8-BDFE3388EEB3}.Debug|ARM.ActiveCfg = Debug|Any CPU
{92E63872-4938-4F0C-9FD8-BDFE3388EEB3}.Debug|ARM.Build.0 = Debug|Any CPU
{92E63872-4938-4F0C-9FD8-BDFE3388EEB3}.Debug|x64.ActiveCfg = Debug|Any CPU
{92E63872-4938-4F0C-9FD8-BDFE3388EEB3}.Debug|x64.Build.0 = Debug|Any CPU
{92E63872-4938-4F0C-9FD8-BDFE3388EEB3}.Debug|x86.ActiveCfg = Debug|Any CPU
{92E63872-4938-4F0C-9FD8-BDFE3388EEB3}.Debug|x86.Build.0 = Debug|Any CPU
{92E63872-4938-4F0C-9FD8-BDFE3388EEB3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{92E63872-4938-4F0C-9FD8-BDFE3388EEB3}.Release|Any CPU.Build.0 = Release|Any CPU
{92E63872-4938-4F0C-9FD8-BDFE3388EEB3}.Release|ARM.ActiveCfg = Release|Any CPU
{92E63872-4938-4F0C-9FD8-BDFE3388EEB3}.Release|ARM.Build.0 = Release|Any CPU
{92E63872-4938-4F0C-9FD8-BDFE3388EEB3}.Release|x64.ActiveCfg = Release|Any CPU
{92E63872-4938-4F0C-9FD8-BDFE3388EEB3}.Release|x64.Build.0 = Release|Any CPU
{92E63872-4938-4F0C-9FD8-BDFE3388EEB3}.Release|x86.ActiveCfg = Release|Any CPU
{92E63872-4938-4F0C-9FD8-BDFE3388EEB3}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{2BE393DC-21A4-48B3-83FD-F21CBE8B038B} = {CDCDFD04-CD05-4CAA-BBA4-6166A5119495}
{B0226F52-8D27-4C05-8C04-536E0BCC3B99} = {CDCDFD04-CD05-4CAA-BBA4-6166A5119495}
{2CE7006F-C1DF-4A15-9E68-A63A3255FE88} = {CDCDFD04-CD05-4CAA-BBA4-6166A5119495}
{0111EB6E-72E3-499C-A3BA-022F5BBC4CAF} = {CDCDFD04-CD05-4CAA-BBA4-6166A5119495}
{331C28E1-5BA3-42CE-8A4A-BC468E692FED} = {CDCDFD04-CD05-4CAA-BBA4-6166A5119495}
{18ECD88E-5D74-43E8-8BC2-D28F6DB13A47} = {4617084D-65A3-4354-B97F-1DF9254AA183}
{695733D7-99FF-4707-8C89-474E949CADCB} = {4617084D-65A3-4354-B97F-1DF9254AA183}
{47141894-ECE3-48CA-8DCF-CA751BDA231E} = {4617084D-65A3-4354-B97F-1DF9254AA183}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,75 @@
using PLClass;
using System;
using System.ComponentModel;
using System.Threading.Tasks;
namespace PlaneGcsSdk.Contract.DtuClient
{
partial class EhNetLoginMgr
{
#region Fileds
private PLNet _PLNet;
private PLNet.LoginState _loginState;
#endregion
#region Private Methods
private void InstanceEhNetObject()
{
_PLNet = new PLNet(AsyncOperationManager.CreateOperation(null));
}
private async Task EhNetStart(string ehNetServerIp, string username, string pwd)
{
_PLNet.Start(ehNetServerIp, username, pwd);
}
private bool CheckIfLogined()
{
return _loginState == PLNet.LoginState.LoginOk;
}
private void ResetLoginStatus()
{
_loginState = PLNet.LoginState.LoginNoUser;
}
private async Task SendCommandToDtuServer(string msg)
{
_PLNet.SendCommand(DtuServerUsername, msg);
}
#endregion
#region Event Handlers
private void _ehNet_Login(PLNet.LoginState loginState)
{
_loginState = loginState;
if (_loginState == PLNet.LoginState.LoginOk)
{
NickName = _PLNet.MyNick;
_loginEnNet.Set();
}
}
//private void _ehNet_ExceptionThrown(object sender, PLNet.UWP.ExceptionThrownEventArgs e)
//{
// RaiseExceptionThrown(e.Exception);
//}
private void _ehNet_DiscoveredOneUser(PLNet.UserProperty userProperty)
{
}
private void _ehNet_Disconnect(PLNet e)
{
_loginState = PLNet.LoginState.LoginOtherError;
NickName = null;
}
private void _ehNet_CommandArrival(string friendID, string msg)
{
AcceptProtocolCommand(friendID, msg);
Console.WriteLine(msg);
}
#endregion
}
}

View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{089FA525-1773-47A5-8A0A-832AB179E2D9}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>PlaneGcsSdk.Contract.DtuClient_NET</RootNamespace>
<AssemblyName>PlaneGcsSdk.Contract.DtuClient_NET</AssemblyName>
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="EhNetLoginMgr_Net.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\myPLClass\ClassLibrary2\PLClass.vbproj">
<Project>{92e63872-4938-4f0c-9fd8-bdfe3388eeb3}</Project>
<Name>PLClass</Name>
</ProjectReference>
<ProjectReference Include="..\PlaneGcsSdk.Contract\PlaneGcsSdk.Contract.csproj">
<Project>{18ecd88e-5d74-43e8-8bc2-d28f6db13a47}</Project>
<Name>PlaneGcsSdk.Contract</Name>
</ProjectReference>
<ProjectReference Include="..\PlaneGcsSdk.Contract_Private\PlaneGcsSdk.Contract_Private.csproj">
<Project>{47141894-ece3-48ca-8dcf-ca751bda231e}</Project>
<Name>PlaneGcsSdk.Contract_Private</Name>
</ProjectReference>
<ProjectReference Include="..\PlaneGcsSdk_Private_NET45\PlaneGcsSdk_Private_NET45.csproj">
<Project>{2ce7006f-c1df-4a15-9e68-a63a3255fe88}</Project>
<Name>PlaneGcsSdk_Private_NET45</Name>
</ProjectReference>
</ItemGroup>
<Import Project="..\PlaneGcsSdk.Contract.DtuClient_Shared\PlaneGcsSdk.Contract.DtuClient_Shared.projitems" Label="Shared" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("PlaneGcsSdk.Contract.DtuClient_NET")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("PlaneGcsSdk.Contract.DtuClient_NET")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
//将 ComVisible 设置为 false 将使此程序集中的类型
//对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("089fa525-1773-47a5-8a0a-832ab179e2d9")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
// 方法是按如下所示使用“*”: :
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,71 @@
using Plane.Communication;
using System.Text;
using System.Threading.Tasks;
namespace PlaneGcsSdk.Contract.DtuClient
{
/// <summary>
/// 基于PLNet的用户登录体系的Udp连接实体类。
/// <para>具体登陆流程1利用用户名和密码登陆PLNet获取随机码2利用随机码登陆Dtu透传服务器</para>
/// </summary>
public partial class BasedOnEhNetUdpDtuServiceConnection : UdpThroughDtuServiceConnection
{
#region Fields
public int _randCode;
#endregion
#region Properties
#endregion
/// <summary>
/// 基于PLNet的用户登录体系的Udp连接实体类。
/// <para>具体登陆流程1利用用户名和密码登陆PLNet获取随机码2利用随机码登陆Dtu透传服务器</para>
/// </summary>
/// <param name="dtuServiceIp"></param>
/// <param name="dtuServicePort"></param>
/// <param name="randCode">用户随机数</param>
public BasedOnEhNetUdpDtuServiceConnection(string dtuServiceIp, int dtuServicePort, int randCode)
: base(dtuServiceIp, dtuServicePort)
{
FLAG_DTU_HANDSHAKE_HEAD = "ehnetrnd";
_randCode = randCode;
}
protected override byte[] ConstructHandShakeDatagramToDTUService()
{
return Encoding.ASCII.GetBytes($"{FLAG_DTU_HANDSHAKE_HEAD}{_randCode}");
}
/// <summary>
/// 分析由DTU服务端返回的握手包
/// </summary>
/// <param name="buffer"></param>
/// <returns></returns>
protected override DTUHandShakeResult AnalyzeHandShakeDatagramFromDTUService(byte[] buffer)
{
var strResult = Encoding.ASCII.GetString(buffer);//返回的格式为“ehnetrndxxxx”
if (strResult.StartsWith(FLAG_DTU_HANDSHAKE_HEAD))
{
return DTUHandShakeResult.Successful;
}
return DTUHandShakeResult.Unknown;
}
public override async Task<int> ReadAsync(byte[] buffer, int offset, int count)
{
var iRet = await base.ReadAsync(buffer, offset, count);
//解密数据
buffer.DecryptByKey((byte)(_randCode % byte.MaxValue), offset, count);
return iRet;
}
public override Task WriteAsync(byte[] buffer, int offset, int count)
{
//加密数据
buffer.EncryptByKey((byte)(_randCode % byte.MaxValue), offset, count);
var iRet = base.WriteAsync(buffer, offset, count);
return iRet;
}
}
}

View File

@ -0,0 +1,33 @@
#if !NETFX_CORE
using System;
using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace EHangGcsSdk.Contract.DtuClient
{
public partial class BasedOnEhNetUdpDtuServiceConnection
{
private TcpClient _tcpClient;
/// <summary>
/// 登陆到EhNet获取随机码后再登陆Dtu透传服务端。
/// </summary>
/// <returns></returns>
public override async Task OpenAsync()
{
//
}
public override void Close()
{
_tcpClient.Close();
base.Close();
}
}
}
#endif

View File

@ -0,0 +1,11 @@
namespace PlaneGcsSdk.Contract.DtuClient
{
/// <summary>
/// 表示飞机实体类
/// </summary>
public class CopterEntity
{
public string ID { get; set; }
public string Name { get; set; }
}
}

View File

@ -0,0 +1,68 @@
namespace PlaneGcsSdk.Contract.DtuClient
{
/// <summary>
/// 进行数据透传时利用随机码对MavLink数据包进行加密和解密的辅助类。
/// </summary>
public static class DataEncryptHelper
{
/// <summary>
/// 对数据进行加密处理。
/// </summary>
/// <param name="data"></param>
/// <param name="key">密钥</param>
/// <param name="offset"></param>
/// <param name="size"></param>
public static void EncryptByKey(this byte[] data, byte key, int offset = 0, int size = -1)
{
int count;
if (size == -1)
{
count = data.Length - offset;
}
else
{
count = size + offset;
}
for (var i = offset; i < count; i++)
{
//下面算法实现高低位调转
var ch = data[i];
ch >>= 4;
data[i] <<= 4;
data[i] |= ch;
//根据Key进行异或处理
//data[i] ^= key;
}
}
/// <summary>
/// 对数据进行解密处理。
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
public static void DecryptByKey(this byte[] data, byte key, int offset = 0, int size = -1)
{
int count;
if (size == -1)
{
count = data.Length - offset;
}
else
{
count = size + offset;
}
for (var i = offset; i < count; i++)
{
//根据Key进行异或处理
//data[i] ^= key;
//下面算法实现高低位调转
var ch = data[i];
ch >>= 4;
data[i] <<= 4;
data[i] |= ch;
}
}
}
}

View File

@ -0,0 +1,278 @@
using System;
using System.Threading;
using System.Threading.Tasks;
namespace PlaneGcsSdk.Contract.DtuClient
{
public partial class EhNetLoginMgr
{
#region Fields
private AutoResetEvent _loginEnNet;
private AutoResetEvent _sendRndCodeSignal;
private AutoResetEvent _sendBindCopterIDSignal;
private AutoResetEvent _sendUpdHandshakeSignal;
private AutoResetEvent _requestCopterListSignal;
private const string Protocol_SendRandCode = "J001"; //表示向服务器请求“发送随机码”的协议号
private const string Protocol_SendRandCode_Reply = "J002"; //表示服务端返回“请求发送随机码”的应答协议号
private const string Protocol_BindCopterID = "J003"; //表示向服务器请求“绑定飞机”的协议号
private const string Protocol_BindCopterID_Reply = "J004"; //表示服务端返回“请求绑定飞机”的应答协议号
private const string Protocol_RequestCopterList = "J007"; //表示向服务器请求“飞机列表”的请求协议号
private const string Protocol_ReceivedCopterItem = "J008"; //表示服务端返回“飞机列表中的一个飞机”的推送协议号
private const string Protocol_RecievedCopterInvailed = "J206";//表示由服务端通告“您所绑定的飞机已无效”的推送协议好
private string _errorCode; //请求过程由服务端返回的错误码的缓存变量
private string _errorCodeForRequestCopterList; //专为缓存“请求飞机列表”结果的错误号变量
private const string ErrorCode_Succeed = "0000"; //表示执行成功的错误码
private const string ErrorCode_EndCopterList = "0003"; //表示服务端返回“飞机列表完毕”的协议号
private CopterEntity _nextCopter; //当前请求的飞机实体
private string _usersname; //当前登录的账号
private const string DtuServerUsername = "10000"; // 在PLNet登陆体系里Dtu服务端的用户名
#endregion
#region Properties
/// <summary>
/// 在PLNet登陆体系里的用户别名
/// </summary>
public string NickName { get; protected set; }
/// <summary>
/// PLNet服务端的IP
/// </summary>
public string ServerIp { get; set; }
/// <summary>
/// PLNet服务端的监听端口
/// </summary>
public int ServerPort { get; set; }
/// <summary>
/// 表示当前所处的PLNet-Dtu连接状态比如已登录PLNet但没有建立Dtu透传管道
/// </summary>
public ProcessStep ProcessSetp { get; protected set; }
/// <summary>
/// 登陆后获得的随机码
/// </summary>
public int RandCode { get; protected set; }
/// <summary>
/// 用于建立透传管道的Udp端口。
/// </summary>
public const int DTU_USER_PORT = 5250;
#endregion
/// <summary>
/// 当前已绑定的飞机变为无效状态的事件
/// </summary>
public event EventHandler CopterLost;
public EhNetLoginMgr()
{
_loginEnNet = new AutoResetEvent(false);
_sendBindCopterIDSignal = new AutoResetEvent(false);
_sendRndCodeSignal = new AutoResetEvent(false);
_sendUpdHandshakeSignal = new AutoResetEvent(false);
_requestCopterListSignal = new AutoResetEvent(false);
InstanceEhNetObject();
_PLNet.CommandArrival += _ehNet_CommandArrival;
_PLNet.Disconnect += _ehNet_Disconnect;
_PLNet.DiscoveredOneUser += _ehNet_DiscoveredOneUser;
//_ehNet.ExceptionThrown += _ehNet_ExceptionThrown;
_PLNet.Login += _ehNet_Login;
}
public void Dispose()
{
_PLNet.CommandArrival -= _ehNet_CommandArrival;
_PLNet.Disconnect -= _ehNet_Disconnect;
_PLNet.DiscoveredOneUser -= _ehNet_DiscoveredOneUser;
//_ehNet.ExceptionThrown -= _ehNet_ExceptionThrown;
_PLNet.Login -= _ehNet_Login;
}
#region Public Methods
/// <summary>
/// 登陆到PLNet网络第三个参数决定是否在登陆成功后发起获取飞机列表的请求
/// </summary>
/// <param name="username"></param>
/// <param name="pwd"></param>
/// <param name="gotCopterCallBack">获得得到的飞机事件</param>
public async Task Login(string username, string pwd, string ehNetServerIp,
Action<CopterEntity> gotCopterCallBack = null)
{
if (CheckIfLogined())
{
return;
}
_usersname = username;
await Task.Run(async () =>
{
await EhNetStart(ehNetServerIp, username, pwd);
if (!_loginEnNet.WaitOne(TimeSpan.FromSeconds(10)))
{
throw new Exception("登陆无响应失败!");
}
ProcessSetp = ProcessStep.EhNetLogin;
if (!string.IsNullOrEmpty(_PLNet.MyRND))
{
int value;
int.TryParse(_PLNet.MyRND, out value);
RandCode = value;
//发送随机码到Dtu服务端
await SendCommandToDtuServer($"{Protocol_SendRandCode};{username};{_PLNet.MyRND}");
if (!_sendRndCodeSignal.WaitOne(TimeSpan.FromSeconds(10)))
{
throw new Exception("发送随机码超时!");
}
else if (_errorCode != ErrorCode_Succeed)
{
throw new Exception("发送随机码失败:" + _errorCode);
}
ProcessSetp = ProcessStep.SendRandCode;
}
if (gotCopterCallBack != null)
{
int index = 0;
while (true)
{
await SendCommandToDtuServer($"{Protocol_RequestCopterList};{username};{index}");
if (_requestCopterListSignal.WaitOne(TimeSpan.FromSeconds(10)))
{
if (_errorCodeForRequestCopterList == ErrorCode_Succeed)
{
if (_nextCopter != null)
{
gotCopterCallBack.Invoke(_nextCopter);
}
//加1后继续请求
index++;
}
else if (_errorCodeForRequestCopterList == ErrorCode_EndCopterList)
{
//正常结束请求
break;
}
else
{
throw new Exception($"请求获取飞机列表错误:{_errorCode}");
}
}
else
{
throw new Exception("请求获取飞机列表超时!");
}
}
}
}).ConfigureAwait(false);
}
/// <summary>
/// 退出PLNet网络
/// </summary>
public void Logout()
{
_PLNet.Close();
ResetLoginStatus();
ProcessSetp = ProcessStep.None;
}
/// <summary>
/// 获取飞机列表
/// </summary>
public async Task GetCopterList(Action<CopterEntity> gotCopterCallBack)
{
await Task.Run(async () =>
{
int index = 0;
while (true)
{
await SendCommandToDtuServer($"{Protocol_RequestCopterList};{_usersname};{index}");
if (_requestCopterListSignal.WaitOne(TimeSpan.FromSeconds(10)))
{
if (_errorCodeForRequestCopterList == ErrorCode_Succeed)
{
if (_nextCopter != null)
{
gotCopterCallBack.Invoke(_nextCopter);
}
//加1后继续请求
index++;
}
else if (_errorCodeForRequestCopterList == ErrorCode_EndCopterList)
{
//正常结束请求
break;
}
else
{
//throw new Exception($"请求获取飞机列表错误:{_errorCode}");
}
}
else
{
//throw new Exception("请求获取飞机列表超时!");
}
}
}).ConfigureAwait(false);
}
/// <summary>
/// 申请绑定飞机
/// </summary>
public async Task AssignBindingCopter(string copterID)
{
//向Dtu服务端申请绑定飞机
await SendCommandToDtuServer($"{Protocol_BindCopterID};{_usersname};{copterID}");
if (!_sendBindCopterIDSignal.WaitOne(TimeSpan.FromSeconds(10)))
{
throw new Exception("申请绑定超时!");
}
else if (_errorCode != ErrorCode_Succeed)
{
throw new Exception("申请绑定失败:" + _errorCode);
}
ProcessSetp = ProcessStep.AssignCopter;
}
#endregion
#region Private Methods
private void AcceptProtocolCommand(string userIDFrom, string msg)
{
if (!string.IsNullOrEmpty(msg) && userIDFrom == DtuServerUsername)
{
var strList = msg.Split(';');
if (strList.Length >= 3)
{
switch (strList[0])
{
case Protocol_SendRandCode_Reply:
_errorCode = strList[2];
_sendRndCodeSignal.Set();
break;
case Protocol_BindCopterID_Reply:
_errorCode = strList[2];
_sendBindCopterIDSignal.Set();
break;
case Protocol_ReceivedCopterItem:
_errorCodeForRequestCopterList = strList[2];
if (strList.Length >= 5)
{
_nextCopter = new CopterEntity { ID = strList[3], Name = strList[4] };
}
else
{
_nextCopter = null;
}
_requestCopterListSignal.Set();
break;
case Protocol_RecievedCopterInvailed:
CopterLost?.Invoke(this, EventArgs.Empty);
break;
}
}
}
}
#endregion
}
}

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
<HasSharedItems>true</HasSharedItems>
<SharedGUID>83d6bb5f-1643-4b9f-b3e4-d4d08cea2733</SharedGUID>
</PropertyGroup>
<PropertyGroup Label="Configuration">
<Import_RootNamespace>EHangGcsSdk.Contract.DtuClient_Shared</Import_RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)BasedOnEhNetUdpDtuServiceConnection.cs" />
<Compile Include="$(MSBuildThisFileDirectory)CopterEntity.cs" />
<Compile Include="$(MSBuildThisFileDirectory)DataEncryptHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)EhNetLoginMgr.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ProcessStep.cs" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<ProjectGuid>83d6bb5f-1643-4b9f-b3e4-d4d08cea2733</ProjectGuid>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
<PropertyGroup />
<Import Project="PlaneGcsSdk.Contract.DtuClient_Shared.projitems" Label="Shared" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
</Project>

View File

@ -0,0 +1,29 @@
namespace PlaneGcsSdk.Contract.DtuClient
{
/// <summary>
/// 与DTU服务端建立通信的流程枚举
/// </summary>
public enum ProcessStep
{
/// <summary>
/// 默认值
/// </summary>
None,
/// <summary>
/// 【第一步】已登陆PLNet服务端
/// </summary>
EhNetLogin,
/// <summary>
/// 【第二步】已发送登陆随机码到DTU服务端
/// </summary>
SendRandCode,
/// <summary>
/// 【第三步】已向DTU服务端绑定飞机
/// </summary>
AssignCopter,
/// <summary>
/// 【第四步】已向DTU建立飞控透传管道
/// </summary>
HandShakeToDTU,
}
}

View File

@ -0,0 +1,75 @@
using PlaneGcsSdk.Contract.EhNetUWP;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
namespace PlaneGcsSdk.Contract.DtuClient
{
partial class EhNetLoginMgr
{
#region Fields
private PLNet _PLNet;
private LoginState _loginState;
#endregion
#region Private Methods
private void InstanceEhNetObject()
{
_PLNet = new PLNet();
}
private async Task EhNetStart(string ehNetServerIp, string username, string pwd)
{
await _PLNet.Start(ehNetServerIp, username, pwd);
}
private bool CheckIfLogined()
{
return _loginState == LoginState.LoginOk;
}
private void ResetLoginStatus()
{
_loginState = LoginState.LoginNoUser;
}
private async Task SendCommandToDtuServer(string msg)
{
await _PLNet.SendCommand(DtuServerUsername, msg);
}
#endregion
#region Event Handlers
private void _ehNet_Login(object sender, LoginEventArgs e)
{
_loginState = e.LoginState;
if (_loginState == LoginState.LoginOk)
{
NickName = _PLNet.MyNick;
_loginEnNet.Set();
}
}
//private void _ehNet_ExceptionThrown(object sender, PLNet.UWP.ExceptionThrownEventArgs e)
//{
// RaiseExceptionThrown(e.Exception);
//}
private void _ehNet_DiscoveredOneUser(object sender, DiscoveredOneUserEventArgs e)
{
}
private void _ehNet_Disconnect(object sender, EventArgs e)
{
_loginState = LoginState.LoginOtherError;
NickName = null;
}
private void _ehNet_CommandArrival(object sender, CommandArrivalEventArgs e)
{
AcceptProtocolCommand(e.FriendID, e.CmdMessage);
Debug.WriteLine(e.CmdMessage);
}
#endregion
}
}

View File

@ -0,0 +1,141 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{2079C6FC-8EBA-4BD8-A965-EC9FB473C314}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>PlaneGcsSdk.Contract.DtuClient</RootNamespace>
<AssemblyName>PlaneGcsSdk.Contract.DtuClient</AssemblyName>
<DefaultLanguage>zh-CN</DefaultLanguage>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<TargetPlatformVersion>10.0.10586.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion>
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
<PlatformTarget>ARM</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\ARM\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>ARM</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
<PlatformTarget>ARM</PlatformTarget>
<OutputPath>bin\ARM\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>ARM</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<PlatformTarget>x64</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<PlatformTarget>x64</PlatformTarget>
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<PlatformTarget>x86</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<PlatformTarget>x86</PlatformTarget>
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<!-- A reference to the entire .Net Framework and Windows SDK are automatically included -->
<None Include="project.json" />
</ItemGroup>
<ItemGroup>
<Compile Include="EhNetLoginMgr_UWP.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Content Include="Properties\PlaneGcsSdk.Contract.DtuClient.rd.xml" />
<Content Include="Readme.txt" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PlaneGcsSdk.Contract.EhNetUWP\PlaneGcsSdk.Contract.EhNetUWP.csproj">
<Project>{d7d21b2b-6f73-4939-b720-fe51da1c04c0}</Project>
<Name>PlaneGcsSdk.Contract.EhNetUWP</Name>
</ProjectReference>
<ProjectReference Include="..\PlaneGcsSdk.Contract\PlaneGcsSdk.Contract.csproj">
<Project>{18ecd88e-5d74-43e8-8bc2-d28f6db13a47}</Project>
<Name>PlaneGcsSdk.Contract</Name>
</ProjectReference>
<ProjectReference Include="..\PlaneGcsSdk_UWP\PlaneGcsSdk_UWP.csproj">
<Project>{b0226f52-8d27-4c05-8c04-536e0bcc3b99}</Project>
<Name>PlaneGcsSdk_UWP</Name>
</ProjectReference>
</ItemGroup>
<Import Project="..\PlaneGcsSdk.Contract.DtuClient_Shared\PlaneGcsSdk.Contract.DtuClient_Shared.projitems" Label="Shared" />
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' ">
<VisualStudioVersion>14.0</VisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -0,0 +1,29 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("PlaneGcsSdk.Contract.DtuClient")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("PlaneGcsSdk.Contract.DtuClient")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: ComVisible(false)]

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
This file contains Runtime Directives, specifications about types your application accesses
through reflection and other dynamic code patterns. Runtime Directives are used to control the
.NET Native optimizer and ensure that it does not remove code accessed by your library. If your
library does not do any reflection, then you generally do not need to edit this file. However,
if your library reflects over types, especially types passed to it or derived from its types,
then you should write Runtime Directives.
The most common use of reflection in libraries is to discover information about types passed
to the library. Runtime Directives have three ways to express requirements on types passed to
your library.
1. Parameter, GenericParameter, TypeParameter, TypeEnumerableParameter
Use these directives to reflect over types passed as a parameter.
2. SubTypes
Use a SubTypes directive to reflect over types derived from another type.
3. AttributeImplies
Use an AttributeImplies directive to indicate that your library needs to reflect over
types or methods decorated with an attribute.
For more information on writing Runtime Directives for libraries, please visit
http://go.microsoft.com/fwlink/?LinkID=391919
-->
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
<Library Name="PlaneGcsSdk.Contract.DtuClient">
<!-- add directives for your library here -->
</Library>
</Directives>

View File

@ -0,0 +1,2 @@
本项目:
1实现PLNet-Dtu的登陆逻辑的IConnection

View File

@ -0,0 +1,16 @@
{
"dependencies": {
"Microsoft.NETCore.UniversalWindowsPlatform": "5.0.0"
},
"frameworks": {
"uap10.0": {}
},
"runtimes": {
"win10-arm": {},
"win10-arm-aot": {},
"win10-x86": {},
"win10-x86-aot": {},
"win10-x64": {},
"win10-x64-aot": {}
}
}

View File

@ -0,0 +1,33 @@
namespace PlaneGcsSdk.Contract.EhNetUWP
{
public class CommandArrivalEventArgs
{
private string _friendid;
public string FriendID
{
get { return _friendid; }
set
{
if (_friendid != value)
_friendid = value;
}
}
private string _cmdmessage;
public string CmdMessage
{
get { return _cmdmessage; }
set
{
if (_cmdmessage != value)
_cmdmessage = value;
}
}
public CommandArrivalEventArgs(string fid,string msg)
{
FriendID = fid;
CmdMessage = msg;
}
}
}

View File

@ -0,0 +1,285 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
namespace PlaneGcsSdk.Contract.EhNetUWP
{
/// <summary>
/// 在UWP平台下支持GB2312、Big5编码的字符编码类。
/// </summary>
public sealed class DBCSEncoding : Encoding
{
private const char LEAD_BYTE_CHAR = '\uFFFE';
private char[] _dbcsToUnicode = null;
private ushort[] _unicodeToDbcs = null;
private string _webName = null;
private static Dictionary<string, Tuple<char[], ushort[]>> _cache = null;
static DBCSEncoding()
{
if (!BitConverter.IsLittleEndian)
throw new PlatformNotSupportedException("Not supported big endian platform.");
_cache = new Dictionary<string, Tuple<char[], ushort[]>>();
}
private DBCSEncoding() { }
/// <summary>
/// 支持GB2312和Big5编码
/// </summary>
/// <param name="name">“gb2312”或“big5”</param>
/// <returns></returns>
public static async Task<DBCSEncoding> GetDBCSEncoding(string name)
{
name = name.ToLower();
DBCSEncoding encoding = new DBCSEncoding();
encoding._webName = name;
if (_cache.ContainsKey(name))
{
var tuple = _cache[name];
encoding._dbcsToUnicode = tuple.Item1;
encoding._unicodeToDbcs = tuple.Item2;
return encoding;
}
var dbcsToUnicode = new char[0x10000];
var unicodeToDbcs = new ushort[0x10000];
/*
* According to many feedbacks, add this automatic function for finding resource in revision 1.0.0.1.
* We suggest that use the old method as below if you understand how to embed the resource.
* Please make sure the *.bin file was correctly embedded if throw an exception at here.
*/
//using (Stream stream = typeof(DBCSEncoding).Assembly.GetManifestResourceStream(typeof(DBCSEncoding).Namespace + "." + name + ".bin"))
//using (Stream stream = typeof(DBCSEncoding).Assembly.GetManifestResourceStream(typeof(DBCSEncoding).Assembly.GetManifestResourceNames().Single(s => s.EndsWith("." + name + ".bin"))))
using (Stream stream = await GetInstall(name))
using (BinaryReader reader = new BinaryReader(stream))
{
for (int i = 0; i < 0xffff; i++)
{
ushort u = reader.ReadUInt16();
unicodeToDbcs[i] = u;
}
for (int i = 0; i < 0xffff; i++)
{
ushort u = reader.ReadUInt16();
dbcsToUnicode[i] = (char)u;
}
}
_cache[name] = new Tuple<char[], ushort[]>(dbcsToUnicode, unicodeToDbcs);
encoding._dbcsToUnicode = dbcsToUnicode;
encoding._unicodeToDbcs = unicodeToDbcs;
return encoding;
}
public override int GetByteCount(char[] chars, int index, int count)
{
int byteCount = 0;
ushort u;
char c;
for (int i = 0; i < count; index++, byteCount++, i++)
{
c = chars[index];
u = _unicodeToDbcs[c];
if (u > 0xff)
byteCount++;
}
return byteCount;
}
public override int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex)
{
int byteCount = 0;
ushort u;
char c;
for (int i = 0; i < charCount; charIndex++, byteIndex++, byteCount++, i++)
{
c = chars[charIndex];
u = _unicodeToDbcs[c];
if (u == 0 && c != 0)
{
bytes[byteIndex] = 0x3f; // 0x3f == '?'
}
else if (u < 0x100)
{
bytes[byteIndex] = (byte)u;
}
else
{
bytes[byteIndex] = (byte)((u >> 8) & 0xff);
byteIndex++;
byteCount++;
bytes[byteIndex] = (byte)(u & 0xff);
}
}
return byteCount;
}
public override int GetCharCount(byte[] bytes, int index, int count)
{
return GetCharCount(bytes, index, count, null);
}
public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex)
{
return GetChars(bytes, byteIndex, byteCount, chars, charIndex, null);
}
public override int GetMaxByteCount(int charCount)
{
if (charCount < 0)
throw new ArgumentOutOfRangeException("charCount");
long count = charCount + 1;
count *= 2;
if (count > int.MaxValue)
throw new ArgumentOutOfRangeException("charCount");
return (int)count;
}
public override int GetMaxCharCount(int byteCount)
{
if (byteCount < 0)
throw new ArgumentOutOfRangeException("byteCount");
long count = byteCount + 3;
if (count > int.MaxValue)
throw new ArgumentOutOfRangeException("byteCount");
return (int)count;
}
public override Decoder GetDecoder()
{
return new DBCSDecoder(this);
}
public override string WebName
{
get
{
return _webName;
}
}
private int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex, DBCSDecoder decoder)
{
int charCount = 0;
ushort u;
char c;
for (int i = 0; i < byteCount; byteIndex++, charIndex++, charCount++, i++)
{
u = 0;
if (decoder != null && decoder.pendingByte != 0)
{
u = decoder.pendingByte;
decoder.pendingByte = 0;
}
u = (ushort)(u << 8 | bytes[byteIndex]);
c = _dbcsToUnicode[u];
if (c == LEAD_BYTE_CHAR)
{
if (i < byteCount - 1)
{
byteIndex++;
i++;
u = (ushort)(u << 8 | bytes[byteIndex]);
c = _dbcsToUnicode[u];
}
else if (decoder == null)
{
c = '\0';
}
else
{
decoder.pendingByte = bytes[byteIndex];
return charCount;
}
}
if (c == 0 && u != 0)
chars[charIndex] = '?';
else
chars[charIndex] = c;
}
return charCount;
}
private int GetCharCount(byte[] bytes, int index, int count, DBCSDecoder decoder)
{
int charCount = 0;
ushort u;
char c;
for (int i = 0; i < count; index++, charCount++, i++)
{
u = 0;
if (decoder != null && decoder.pendingByte != 0)
{
u = decoder.pendingByte;
decoder.pendingByte = 0;
}
u = (ushort)(u << 8 | bytes[index]);
c = _dbcsToUnicode[u];
if (c == LEAD_BYTE_CHAR)
{
if (i < count - 1)
{
index++;
i++;
}
else if (decoder != null)
{
decoder.pendingByte = bytes[index];
return charCount;
}
}
}
return charCount;
}
private async static Task<Stream> GetInstall(string name)
{
//此处只是简单的获取到gb2312.bin文件
//name = "gb2312";
var folderInstall = Windows.ApplicationModel.Package.Current.InstalledLocation;//获取安装包的位置
var folder = await folderInstall.GetFolderAsync("EncodingBins");
var file = await folder.GetFileAsync(name + ".bin");  //获取gb2312.bin
Stream stream = await file.OpenStreamForReadAsync(); //获取文件流
return stream;
}
private sealed class DBCSDecoder : Decoder
{
private DBCSEncoding _encoding = null;
public DBCSDecoder(DBCSEncoding encoding)
{
_encoding = encoding;
}
public override int GetCharCount(byte[] bytes, int index, int count)
{
return _encoding.GetCharCount(bytes, index, count, this);
}
public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex)
{
return _encoding.GetChars(bytes, byteIndex, byteCount, chars, charIndex, this);
}
public byte pendingByte;
}
}
}

View File

@ -0,0 +1,14 @@
using System;
namespace PlaneGcsSdk.Contract.EhNetUWP
{
public class DiscoveredOneUserEventArgs : EventArgs
{
public DiscoveredOneUserEventArgs(UserProperty userpro)
{
userproperty = userpro;
}
public UserProperty userproperty { get; set; }
}
}

View File

@ -0,0 +1 @@
Gb2312和Big5编码的库请确保此文件夹及文件存在于运行根目录中

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

View File

@ -0,0 +1,15 @@
using System;
namespace PlaneGcsSdk.Contract.EhNetUWP
{
public class ExceptionThrownEventArgs : EventArgs
{
public ExceptionThrownEventArgs(Exception ex)
{
Exception = ex;
}
public Exception Exception { get; set; }
}
}

View File

@ -0,0 +1,13 @@
using System;
namespace PlaneGcsSdk.Contract.EhNetUWP
{
public class LoginEventArgs : EventArgs
{
public LoginEventArgs(LoginState loginstate)
{
LoginState = loginstate;
}
public LoginState LoginState { get; set; }
}
}

View File

@ -0,0 +1,738 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Networking.Sockets;
using System.IO;
using Windows.Storage.Streams;
using Windows.Networking;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Security.Cryptography.Core;
using Windows.Security.Cryptography;
namespace PlaneGcsSdk.Contract.EhNetUWP
{
public class PLNet
{
#region Properties
public StreamOBJ MyStreamObj;
/// <summary>
/// 连接的IP
/// </summary>
public string ServerIP { get; protected set; }
/// <summary>
/// 连接的端口
/// </summary>
public int TCPPort { get; protected set; }
public bool IsClosing { get; protected set; }
public bool IsOpen { get; protected set; }
/// <summary>
/// 真实名
/// </summary>
public string MyNick { get; protected set; }
/// <summary>
/// 获取登录随机码
/// </summary>
public string MyRND { get { return sMyTempRnd; } }
/// <summary>
/// 发送文件列表
/// </summary>
public List<FileOBJ> SendFileList { get; protected set; }
/// <summary>
/// 接收文件列表
/// </summary>
public List<FileOBJ> RevFileList { get; protected set; }
/// <summary>
/// 用户列表
/// </summary>
public List<UserProperty> FriendList { get; protected set; }
/// <summary>
/// 发送流列表
/// </summary>
public List<StreamOBJ> SendStreamList { get; protected set; }
public List<StreamOBJ> RevStreamList { get; protected set; }
#endregion
#region Fields
string sMyTempRnd; //登录随机数
bool LoginFlag = false; //登录状态
string sMyID; //登录用户名
string sMyPassword; //登录密码
string sMyIP; //用户IP
Encoding _enconding;
int iStreamID = -1;
int iFileID = 0;
protected StreamSocket _socket; //连接对象
protected IInputStream _inputStream;
protected Stream _outputStream;
protected bool _canFlush = true;
protected const uint READ_BUFFER_SIZE = 2047;
#endregion
#region Events
public event EventHandler<LoginEventArgs> Login;
public event EventHandler<DiscoveredOneUserEventArgs> DiscoveredOneUser;
public event EventHandler RefreshFriendListCompleted;
public event EventHandler<UserStateChangeEventArgs> UserStateChange;
public event EventHandler Disconnect;
public event EventHandler<CommandArrivalEventArgs> CommandArrival;
public event EventHandler<ExceptionThrownEventArgs> ExceptionThrown;
public event EventHandler<StartSendFileEventArgs> StartSendFile;
#endregion
public PLNet()
{
FriendList = new List<UserProperty>();
SendFileList = new List<FileOBJ>();
RevFileList = new List<FileOBJ>();
SendStreamList = new List<StreamOBJ>();
RevStreamList = new List<StreamOBJ>();
}
#region Public Methods
/// <summary>
/// 建立连接
/// </summary>
/// <param name="sServerIP"></param>
/// <param name="sUsername"></param>
/// <param name="sPassword"></param>
/// <param name="md5Password"></param>
/// <returns></returns>
public async Task Start(string sServerIP, string sUsername, string sPassword, string md5Password = null)
{
Close();
IsClosing = false;
if (_enconding == null)
{
_enconding = await DBCSEncoding.GetDBCSEncoding("GB2312");
}
sMyID = sUsername;
if (md5Password == null)
sMyPassword = GetStrMd5Hash(sMyID + sPassword);
else
sMyPassword = md5Password;
ServerIP = sServerIP; //登录用户的IP地址
TCPPort = 52510; //登录用户的端口
_socket = new StreamSocket(); //创建连接对象
await _socket.ConnectAsync(new HostName(ServerIP), TCPPort.ToString()).AsTask().ConfigureAwait(false); //执行连接操作
IsOpen = true;
_inputStream = _socket.InputStream;
_outputStream = _socket.OutputStream.AsStreamForWrite();
await Task.Run(() => TCPClientThread());
}
/// <summary>
/// 关闭连接
/// </summary>
public void Close()
{
IsClosing = true;
IsOpen = false;
_inputStream?.Dispose();
_outputStream?.Dispose();
_socket?.Dispose();
if (SendFileList != null)
SendFileList.Clear();
if (RevFileList != null)
RevFileList.Clear();
Disconnect?.Invoke(this, EventArgs.Empty); //触发事件Disconnect
}
/// <summary>
/// 发送命令
/// </summary>
/// <param name="friendIDs"></param>
/// <param name="msg"></param>
/// <returns></returns>
public async Task SendCommand(string friendIDs, string msg)
{
string commandtext = "*" + friendIDs + "|" + msg;
await SendCmd(commandtext);
}
/// <summary>
/// 发送数据流,给多个用户同时发送数据
/// </summary>
/// <param name="friendIDs"></param>
/// <param name="myData"></param>
/// <returns></returns>
public async Task SendStream(string friendIDs, byte[] myData)
{
string[] myFriends = friendIDs.Split(',');
for (int i = 0; i < myFriends.Length; i++)
{
iStreamID += 1;
MyStreamObj = new StreamOBJ();
MyStreamObj.StreamID = iStreamID;
MyStreamObj.StreamData = myData;
MyStreamObj.RevUserID = myFriends[i];
SendStreamList.Add(MyStreamObj);
string streamtext = "*" + myFriends[i] + "|SB|" + MyStreamObj.StreamID.ToString() + "|" + MyStreamObj.StreamData.Length.ToString();
await SendCmd(streamtext);
}
}
/// <summary>
/// 发送普通文件
/// </summary>
/// <param name="friendID"></param>
/// <param name="sFilenames"></param>
/// <returns></returns>
public async Task SendFileCommon(string friendID, string[] sFilenames)
{
string filetype = "F";
await SendFileCommon(friendID, sFilenames, filetype);
}
/// <summary>
/// 发送图片文件
/// </summary>
/// <param name="friendID"></param>
/// <param name="sFilenames"></param>
/// <returns></returns>
public async Task SendPicture(string friendID, string[] sFilenames)
{
string filetype = "P";
await SendFileCommon(friendID, sFilenames, filetype);
}
/// <summary>
/// 发送视频文件
/// </summary>
/// <param name="friendID"></param>
/// <param name="sFilenames"></param>
/// <returns></returns>
public async Task SendVideo(string friendID, string[] sFilenames)
{
string filetype = "V";
await SendFileCommon(friendID, sFilenames, filetype);
}
/// <summary>
/// 发送文件公共函数
/// </summary>
/// <param name="friendID"></param>
/// <param name="sFilenames"></param>
/// <param name="filetype"></param>
/// <returns></returns>
public async Task SendFileCommon(string friendID, string[] sFilenames, string filetype)
{
for (int i = 0; i < sFilenames.Length; i++)
{
FileOBJ tmpFileObj = new FileOBJ();
tmpFileObj.FileID = iFileID;
iFileID += 1;
FileInfo MyFileInfo = new FileInfo(sFilenames[i]);
tmpFileObj.Filename = MyFileInfo.Name;
tmpFileObj.FilePath = MyFileInfo.DirectoryName;
tmpFileObj.FileLength = MyFileInfo.Length;
tmpFileObj.FileModDate = filetype + MyFileInfo.LastWriteTime.ToString(); //filetype表示发送文件的类型
tmpFileObj.RevUserID = friendID;
tmpFileObj.State = FileState.WaitConfim;
tmpFileObj.tmpFileStream = new FileStream(sFilenames[i], FileMode.Open, FileAccess.Read);
SendFileList.Add(tmpFileObj);
StartSendFile?.Invoke(this, new StartSendFileEventArgs(SendFileList.Count - 1));
string filetext = "FB" + friendID + "|" + tmpFileObj.FileID.ToString() + "|" + tmpFileObj.Filename + "|" + tmpFileObj.FileLength.ToString() + "|" + tmpFileObj.FileModDate;
await SendCmd(filetext);
}
}
/// <summary>
/// 发送数据公共函数
/// </summary>
/// <param name="cmdStr"></param>
/// <param name="addBytes"></param>
/// <returns></returns>
public async Task SendCmd(string cmdStr, byte[] addBytes = null)
{
byte[] tmpSendbytes = null;
tmpSendbytes = _enconding.GetBytes(cmdStr);
int nret;
int strLen = LenB(cmdStr);
if (addBytes == null)
{
tmpSendbytes = BitConverter.GetBytes((ushort)strLen);
Array.Resize(ref tmpSendbytes, strLen + 2);
nret = _enconding.GetBytes(cmdStr, 0, cmdStr.Length, tmpSendbytes, 2);
}
else
{
byte[] tmpBytes;
long allLenth = strLen + addBytes.Length;
tmpBytes = BitConverter.GetBytes(allLenth);
Array.Resize(ref tmpBytes, strLen + 2);
nret = _enconding.GetBytes(cmdStr, 0, cmdStr.Length, tmpBytes, 2);
tmpSendbytes = AddByte(tmpBytes, addBytes);
}
try
{
if (tmpSendbytes != null)
{
await _outputStream.WriteAsync(tmpSendbytes, 0, tmpSendbytes.Length).ConfigureAwait(false);
if (_canFlush)
{
await _outputStream.FlushAsync().ConfigureAwait(false);
}
}
}
catch (Exception ex)
{
_canFlush = false;
Close();
ExceptionThrown?.Invoke(this, new ExceptionThrownEventArgs(ex));
}
}
#endregion
#region Private Methods
/// <summary>
/// 启动一个接收数据的线程
/// </summary>
private async void TCPClientThread()
{
uint i; //接收到的数据的长度
byte[] byteBuffer = null; //暂存接收到的数据
int comLength;
bool ReadFlag = false;
bool nRet;
byte[] Tmpbyte;
IBuffer tempbuf = new Windows.Storage.Streams.Buffer(READ_BUFFER_SIZE); //建立一个buffer
await _inputStream.ReadAsync(tempbuf, READ_BUFFER_SIZE, InputStreamOptions.Partial);
i = tempbuf.Length;
byteBuffer = new byte[i];
tempbuf.CopyTo(byteBuffer); //将数据输出
while (i != 0)
{
if (byteBuffer.Length > 3)
{
comLength = BitConverter.ToUInt16(byteBuffer, 0);
if (LoginFlag == false && comLength > 70)
{
#region
if (byteBuffer.Length >= 2)
{
byte[] firstchar = new byte[1];
firstchar[0] = byteBuffer[1];
if (_enconding.GetString(firstchar) != "L")
i = 0;
}
else
{
ReadFlag = true;
}
#endregion
}
else
{
#region
if (byteBuffer.Length >= comLength + 1)
{
Tmpbyte = MidByte(byteBuffer, 3, comLength); //截取字节
if (Tmpbyte.Length < 4)
nRet = false;
nRet = await ProcessData(Tmpbyte);
if (nRet == true)
{
byteBuffer = RightByte(byteBuffer, byteBuffer.Length - comLength - 2); //截取字节
if (byteBuffer.Length <= 0)
ReadFlag = true;
}
else
{
return;
}
}
else
{
ReadFlag = true;
}
#endregion
}
}
else
{
ReadFlag = true;
}
if (ReadFlag == true)
{
#region
ReadFlag = false;
try
{
tempbuf = new Windows.Storage.Streams.Buffer(READ_BUFFER_SIZE); //建立一个buffer
await _inputStream.ReadAsync(tempbuf, READ_BUFFER_SIZE, InputStreamOptions.Partial);
i = tempbuf.Length;
byte[] addbyte = new byte[i];
tempbuf.CopyTo(addbyte);
byteBuffer = AddByte(byteBuffer, addbyte);
}
catch(Exception ex)
{
i = 0;
}
#endregion
}
}
}
/// <summary>
/// 处理接收到的数据
/// </summary>
/// <param name="tmpbyte"></param>
/// <returns></returns>
private async Task<bool> ProcessData(byte[] tmpbyte)
{
string recestr = _enconding.GetString(tmpbyte); //这里本应是GBK编码
UserProperty tmpUserinfo = new UserProperty();
int tmpIndex;
switch (recestr[0])
{
case 'R':
sMyTempRnd = recestr.Substring(1);
await SendCmd("L" + sMyID + "|" + GetStrMd5Hash(sMyPassword + sMyTempRnd));
sMyTempRnd = sMyTempRnd.Substring(0, sMyTempRnd.Length - 1);
break;
case 'U': //收到用户信息
string sUserinfo = recestr.Substring(1);
switch (sUserinfo[0])
{
#region
case 'A': //用户列表
#region
sUserinfo = sUserinfo.Substring(1);
tmpUserinfo.UserID = Fin(1, sUserinfo, "|");
tmpUserinfo.UserNick = Fin(2, sUserinfo, "|");
tmpUserinfo.UserIndex = FriendList.Count;
tmpUserinfo.UserMessage = new List<String>();
FriendList.Add(tmpUserinfo);
DiscoveredOneUser?.Invoke(this, new DiscoveredOneUserEventArgs(tmpUserinfo));
#endregion
break;
case 'O': //用户上线
#region
sUserinfo = sUserinfo.Substring(1);
tmpIndex = GetUserIndexByID(Fin(1, sUserinfo, "|"));
if (tmpIndex >= 0)
{
tmpUserinfo = FriendList[tmpIndex]; //修改用户在线状态
tmpUserinfo.UserOnline = true;
FriendList[tmpIndex] = tmpUserinfo;
UserStateChange?.Invoke(this, new UserStateChangeEventArgs(tmpUserinfo));
}
#endregion
break;
case 'F': //用户下线
#region
sUserinfo = sUserinfo.Substring(1);
string tmpFriendID = Fin(1, sUserinfo, "|");
tmpIndex = GetUserIndexByID(tmpFriendID);
if (tmpIndex >= 0)
{
tmpUserinfo = FriendList[tmpIndex];
tmpUserinfo.UserOnline = false;
FriendList[tmpIndex] = tmpUserinfo;
//处理发送文件残留
for (int i = 0; i < SendFileList.Count; i--)
{
if (SendFileList[i].RevUserID == tmpFriendID)
{
SendFileList[i].tmpFileStream.Dispose();
SendFileList.RemoveAt(i);
}
}
for (int j = 0; j < RevFileList.Count; j--)
{
if (RevFileList[j].RevUserID == tmpFriendID)
{
RevFileList[j].tmpFileStream.Dispose();
RevFileList.RemoveAt(j);
}
}
UserStateChange?.Invoke(this, new UserStateChangeEventArgs(tmpUserinfo));
}
#endregion
break;
case 'D':
break;
case 'C': //被别人添加为好友时会收到
break;
case 'E':
RefreshFriendListCompleted?.Invoke(this, EventArgs.Empty);
break;
default:
break;
#endregion
}
break;
case 'L': //登陆
recestr = recestr.Substring(1);
switch (recestr[0])
{
#region
case 'P':
Login?.Invoke(this, new LoginEventArgs(LoginState.LoginPwdError));
break;
case 'O':
LoginFlag = true;
MyNick = recestr.Substring(1).Split('|')[0];
Login?.Invoke(this, new LoginEventArgs(LoginState.LoginOk));
await SendCmd("UG");
break;
case 'U':
Login?.Invoke(this, new LoginEventArgs(LoginState.LoginNoUser));
break;
case 'E':
Login?.Invoke(this, new LoginEventArgs(LoginState.LoginOtherError));
break;
default:
break;
#endregion
}
break;
case '*': //收到命令,格式为: *+FriendID+|+Msg
string tmpStr = recestr.Substring(1);
string tmpstr2 = Fin(2, tmpStr, "|");
switch (tmpstr2[0])
{
#region
case 'S':
break;
default:
string friendid = Fin(1, tmpStr, "|");
string msgcontent = tmpStr.Substring(tmpStr.IndexOf("|") + 1);
CommandArrival?.Invoke(this, new CommandArrivalEventArgs(friendid, msgcontent));
break;
#endregion
}
break;
default:
break;
}
return true;
}
private int LenB(string str)
{
return _enconding.GetBytes(str).Count();
}
/// <summary>
/// 获取一个字节数组中的某些字节从start个字节开始获取length个字节,第几个是从1开始的
/// </summary>
/// <param name="tbyte"></param>
/// <param name="start"></param>
/// <param name="length"></param>
/// <returns></returns>
private byte[] MidByte(byte[] tbyte, int start, int length)
{
byte[] tmpMidByte = new byte[length];
//for (int i = 0; i < length; i++)
//{
// tmpMidByte[i] = tbyte[i + start - 1];
//}
for (int i = start - 1; i <= length - 1 + start - 1; i++)
{
tmpMidByte[i - (start - 1)] = tbyte[i];
}
return tmpMidByte;
}
/// <summary>
/// 获取某个字节数组的后面的字节获取length个字节
/// </summary>
/// <param name="tbyte"></param>
/// <param name="length"></param>
/// <returns></returns>
private byte[] RightByte(byte[] tbyte, int length)
{
byte[] temRightByte = new byte[length];
temRightByte = MidByte(tbyte, tbyte.Length - length + 1, length);
return temRightByte;
}
/// <summary>
/// 获取某个字节数组的前面的字节获取length个字节
/// </summary>
/// <param name="tbyte"></param>
/// <param name="length"></param>
/// <returns></returns>
private byte[] LeftByte(byte[] tbyte, int length)
{
byte[] temLeftByte = new byte[length];
temLeftByte = MidByte(tbyte, 1, length);
return temLeftByte;
}
/// <summary>
/// 拼接两个字节,将addbyte加在srcbyte后面
/// </summary>
/// <param name="srcbyte"></param>
/// <param name="addbyte"></param>
/// <returns></returns>
private byte[] AddByte(byte[] srcbyte, byte[] addbyte)
{
byte[] resultbyte = new byte[srcbyte.Length + addbyte.Length];
for (int i = 0; i < srcbyte.Length; i++)
{
resultbyte[i] = srcbyte[i];
}
for (int j = 0; j < addbyte.Length; j++)
{
resultbyte[j + srcbyte.Length] = addbyte[j];
}
return resultbyte;
}
/// <summary>
/// 根据ID获取列表中序号
/// </summary>
/// <param name="tmpUserID"></param>
/// <returns></returns>
protected int GetUserIndexByID(string tmpUserID)
{
for (int i = 0; i < FriendList.Count; i++)
{
if (FriendList.ElementAt(i).UserID == tmpUserID)
return i;
}
return -1;
}
/// <summary>
/// 分割字符串第Xnum个字符字符串为SrcStr分割特征为SpStr
/// </summary>
/// <param name="xnum"></param>
/// <param name="srcStr"></param>
/// <param name="spStr"></param>
/// <returns></returns>
private string Fin(int xnum, string srcStr, string spStr)
{
string[] tmpStr;
char[] FF = new char[1];
FF[0] = spStr[0];
tmpStr = srcStr.Split(FF);
if ((xnum > 0) && (xnum <= tmpStr.Length))
return tmpStr[xnum - 1];
else
return "";
}
/// <summary>
/// 计算字符串的MD5哈希值输入为字符串strtohash输出为字符串strHash
/// </summary>
/// <param name="strtohash"></param>
/// <returns></returns>
private string GetStrMd5Hash(string strtohash)
{
byte[] tmpbyte = _enconding.GetBytes(strtohash);
IBuffer buffMsg = CryptographicBuffer.CreateFromByteArray(tmpbyte);
HashAlgorithmProvider objAlgProv = HashAlgorithmProvider.OpenAlgorithm(HashAlgorithmNames.Md5);
IBuffer tmpbuffer = objAlgProv.HashData(buffMsg);
uint i = tmpbuffer.Length;
byte[] mybyte = new byte[i];
tmpbuffer.CopyTo(mybyte);
CryptographicBuffer.CopyToByteArray(tmpbuffer, out mybyte);
StringBuilder sBuilder = new StringBuilder();
for (int k = 0; k < mybyte.Length; k++)
{
sBuilder.Append(mybyte[k].ToString("x2"));
}
string strHash = sBuilder.ToString();
return strHash;
}
#endregion
}
#region Nested Type
/// <summary>
/// 用户信息结构体
/// </summary>
public struct UserProperty
{
public string UserID;
public string UserNick;
public string UserIP;
public int UserIndex;
public bool UserOnline;
public List<string> UserMessage;
}
/// <summary>
/// 文件状态
/// </summary>
public enum FileState
{
WaitConfim,
StartSend, //开始发送,等待确认
Sending, //正在发送中
reSend, //断点续传中
SendError, //发送错误
Completed, //发送完成
LoginOtherError, //其他错
StartReveice, //开始接收,等待数据
Receiving, //接收中
ReReceiving, //断点续传中
ReceiveError
}
/// <summary>
/// 登录状态
/// </summary>
public enum LoginState
{
LoginPwdError, //密码错
LoginOk, //登陆成功
LoginNoUser, //用户不存在
LoginOtherError, //其他错
}
/// <summary>
/// 文件结构体
/// </summary>
public struct FileOBJ
{
public string Filename;
public string FilePath;
public long FileLength;
public string FileModDate;
public int FileID;
public string SendUserID;
public string RevUserID;
public FileStream tmpFileStream;
public FileState State;
}
/// <summary>
/// 数据流结构体
/// </summary>
public struct StreamOBJ
{
public byte[] StreamData;
public ulong CurrPos;
public int StreamID;
public ulong Length;
public string SendUserID;
public string RevUserID;
}
#endregion
}

View File

@ -0,0 +1,141 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{D7D21B2B-6F73-4939-B720-FE51DA1C04C0}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>PlaneGcsSdk.Contract.EhNetUWP</RootNamespace>
<AssemblyName>PlaneGcsSdk.Contract.EhNetUWP</AssemblyName>
<DefaultLanguage>zh-CN</DefaultLanguage>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
<TargetPlatformVersion>10.0.10586.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion>
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
<PlatformTarget>ARM</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\ARM\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>ARM</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
<PlatformTarget>ARM</PlatformTarget>
<OutputPath>bin\ARM\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>ARM</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<PlatformTarget>x64</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<PlatformTarget>x64</PlatformTarget>
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<PlatformTarget>x86</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<NoWarn>;2008</NoWarn>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<PlatformTarget>x86</PlatformTarget>
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
<Optimize>true</Optimize>
<NoWarn>;2008</NoWarn>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<!-- A reference to the entire .Net Framework and Windows SDK are automatically included -->
<Content Include="EncodingBins\big5.bin">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="EncodingBins\gb2312.bin">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<None Include="project.json" />
</ItemGroup>
<ItemGroup>
<Compile Include="CommandArrivalEventArgs.cs" />
<Compile Include="DBCSEncoding.cs" />
<Compile Include="DiscoveredOneUserEventArgs.cs" />
<Compile Include="PLNet.cs" />
<Compile Include="ExceptionThrownEventArgs.cs" />
<Compile Include="LoginEventArgs.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="StartSendFileEventArgs.cs" />
<Compile Include="UserStateChangeEventArgs.cs" />
<Content Include="EncodingBins\Readme.txt" />
<Content Include="Properties\PlaneGcsSdk.Contract.EhNetUWP.rd.xml" />
<Content Include="Readme.txt" />
</ItemGroup>
<ItemGroup />
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' ">
<VisualStudioVersion>14.0</VisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -0,0 +1,29 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("PlaneGcsSdk.Contract.EhNetUWP")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("PlaneGcsSdk.Contract.EhNetUWP")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: ComVisible(false)]

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
This file contains Runtime Directives, specifications about types your application accesses
through reflection and other dynamic code patterns. Runtime Directives are used to control the
.NET Native optimizer and ensure that it does not remove code accessed by your library. If your
library does not do any reflection, then you generally do not need to edit this file. However,
if your library reflects over types, especially types passed to it or derived from its types,
then you should write Runtime Directives.
The most common use of reflection in libraries is to discover information about types passed
to the library. Runtime Directives have three ways to express requirements on types passed to
your library.
1. Parameter, GenericParameter, TypeParameter, TypeEnumerableParameter
Use these directives to reflect over types passed as a parameter.
2. SubTypes
Use a SubTypes directive to reflect over types derived from another type.
3. AttributeImplies
Use an AttributeImplies directive to indicate that your library needs to reflect over
types or methods decorated with an attribute.
For more information on writing Runtime Directives for libraries, please visit
http://go.microsoft.com/fwlink/?LinkID=391919
-->
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
<Library Name="PlaneGcsSdk.Contract.EhNetUWP">
<!-- add directives for your library here -->
</Library>
</Directives>

View File

@ -0,0 +1,4 @@
本项目:
1实现了数据按字节加密的类
2实现了GBK/GB2312/Big5编解码
3移植了PLNet.Net模块

View File

@ -0,0 +1,14 @@
using System;
namespace PlaneGcsSdk.Contract.EhNetUWP
{
public class StartSendFileEventArgs : EventArgs
{
public StartSendFileEventArgs(int streamindex)
{
StreamIndex = streamindex;
}
public int StreamIndex { get; set; }
}
}

View File

@ -0,0 +1,14 @@
using System;
namespace PlaneGcsSdk.Contract.EhNetUWP
{
public class UserStateChangeEventArgs : EventArgs
{
public UserStateChangeEventArgs(UserProperty friendinfo)
{
FriendInfo = friendinfo;
}
public UserProperty FriendInfo { get; set; }
}
}

View File

@ -0,0 +1,16 @@
{
"dependencies": {
"Microsoft.NETCore.UniversalWindowsPlatform": "5.0.0"
},
"frameworks": {
"uap10.0": {}
},
"runtimes": {
"win10-arm": {},
"win10-arm-aot": {},
"win10-x86": {},
"win10-x86-aot": {},
"win10-x64": {},
"win10-x64-aot": {}
}
}

View File

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{18ECD88E-5D74-43E8-8BC2-D28F6DB13A47}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Plane</RootNamespace>
<AssemblyName>PlaneGcsSdk.Contract</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<TargetFrameworkProfile>Profile111</TargetFrameworkProfile>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;PORTABLE;NETFX_CORE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE;PORTABLE;NETFX_CORE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>bin\Release\PlaneGcsSdk.Contract.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<!-- A reference to the entire .NET Framework is automatically included -->
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="..\PlaneGcsSdk.Contract_Shared\PlaneGcsSdk.Contract_Shared.projitems" Label="Shared" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -0,0 +1,30 @@
using System.Resources;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("PlaneGcsSdk.Contract")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Plane, Inc.")]
[assembly: AssemblyProduct("PlaneGcsSdk.Contract")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: NeutralResourcesLanguage("en")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,14 @@
using System;
namespace Plane.Copters
{
public class DataStreamReceivedEventArgs : EventArgs
{
public DataStreamReceivedEventArgs(DataStreamType dataStreamType)
{
DataStreamType = dataStreamType;
}
public DataStreamType DataStreamType { get; private set; }
}
}

View File

@ -0,0 +1,9 @@
namespace Plane.Copters
{
public enum DataStreamType : byte
{
SYS_STATUS = 1, // MAVLINK_MSG_ID_SYS_STATUS,
GPS_RAW_INT = 24, // MAVLINK_MSG_ID_GPS_RAW_INT,
RC_CHANNELS_RAW = 35 // MAVLINK_MSG_ID_RC_CHANNELS_RAW
}
}

View File

@ -0,0 +1,20 @@
using System.Threading.Tasks;
namespace Plane.Copters
{
public partial interface ICopterActions
{
/// <summary>
/// 开始画圈。
/// </summary>
/// <returns>表示此命令异步发送操作的 <see cref="Task"/> 实例。</returns>
Task CircleAsync();
/// <summary>
/// // 林俊清, 20160122, 不明确。目测是发送重启命令,在刷固件之前用到。
/// </summary>
/// <param name="bootloaderMode"></param>
/// <returns>表示此命令异步发送操作的 <see cref="Task"/> 实例。</returns>
Task RebootAsync(bool bootloaderMode = false);
}
}

View File

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{47141894-ECE3-48CA-8DCF-CA751BDA231E}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Plane</RootNamespace>
<AssemblyName>PlaneGcsSdk.Contract_Private</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<TargetFrameworkProfile>Profile111</TargetFrameworkProfile>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;PORTABLE;NETFX_CORE;PRIVATE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE;PORTABLE;NETFX_CORE;PRIVATE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>bin\Release\PlaneGcsSdk.Contract_Private.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<!-- A reference to the entire .NET Framework is automatically included -->
</ItemGroup>
<ItemGroup>
<Compile Include="Copters\DataStreamReceivedEventArgs.cs" />
<Compile Include="Copters\DataStreamType.cs" />
<Compile Include="Copters\ICopterActions.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="..\PlaneGcsSdk.Contract_Shared\PlaneGcsSdk.Contract_Shared.projitems" Label="Shared" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -0,0 +1,30 @@
using System.Resources;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("PlaneGcsSdk.Contract_Private")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Plane, Inc.")]
[assembly: AssemblyProduct("PlaneGcsSdk.Contract_Private")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: NeutralResourcesLanguage("en")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,17 @@
using System;
namespace Plane.Communication
{
public class ConnectionEstablishedEventArgs : EventArgs
{
public ConnectionEstablishedEventArgs(IConnection connection, string remoteAddress)
{
this.Connection = connection;
RemoteAddress = remoteAddress;
}
public IConnection Connection { get; private set; }
public string RemoteAddress { get; private set; }
}
}

View File

@ -0,0 +1,14 @@
using System;
namespace Plane.Communication
{
public class ExceptionThrownEventArgs : EventArgs
{
public ExceptionThrownEventArgs(Exception ex)
{
Exception = ex;
}
public Exception Exception { get; set; }
}
}

View File

@ -0,0 +1,50 @@
using System;
using System.Threading.Tasks;
namespace Plane.Communication
{
/// <summary>
/// 定义与远程主机通信的方法。
/// </summary>
public interface IConnection
{
/// <summary>
/// 在不宜抛出的异常发生时引发的事件。
/// </summary>
event EventHandler<ExceptionThrownEventArgs> ExceptionThrown;
/// <summary>
/// 获取一个值,指示通信是否已开启。
/// </summary>
bool IsOpen { get; }
/// <summary>
/// 关闭通信。
/// </summary>
void Close();
/// <summary>
/// 开启通信。
/// </summary>
/// <returns>表示此异步操作的 <see cref="Task"/> 实例。</returns>
Task OpenAsync();
/// <summary>
/// 异步读取数据。顺利完成时将正好读取 <paramref name="count"/> 个字节。
/// </summary>
/// <param name="buffer">存放数据的缓冲区。</param>
/// <param name="offset">起始下标。</param>
/// <param name="count">要读取的字节数。</param>
/// <returns>包含成功读取的字节数的 <see cref="Task{TResult}"/> 实例。此数目在操作顺利完成时保证与 <paramref name="count"/> 等,否则为 0。</returns>
Task<int> ReadAsync(byte[] buffer, int offset, int count);
/// <summary>
/// 异步写入数据。会抛异常。
/// </summary>
/// <param name="buffer">存放数据的缓冲区。</param>
/// <param name="offset">起始下标。</param>
/// <param name="count">要写入的字节数。</param>
/// <returns>表示此异步操作的 <see cref="Task"/> 实例。</returns>
Task WriteAsync(byte[] buffer, int offset, int count);
}
}

View File

@ -0,0 +1,13 @@
using System;
namespace Plane.CopterControllers
{
[Flags]
public enum CopterControllerTypes : byte
{
AvatarController = 0x1,
MicroController = 0x2,
KeyboardController = 0x4,
FlyToController = 0x8
}
}

View File

@ -0,0 +1,12 @@
namespace Plane.CopterControllers
{
public interface ICopterController
{
/// <summary>
/// 获取或设置一个值,指示是否激活此控制器。
/// </summary>
bool IsEnabled { get; set; }
CopterControllerTypes Type { get; }
}
}

View File

@ -0,0 +1,11 @@
namespace Plane.CopterControllers
{
public interface ICopterControllerManager
{
bool IsControllingRollPitchUsingAvatar { get; }
void EnableCopterControllers(CopterControllerTypes controllerTypes);
bool IsControllerEnabled(CopterControllerTypes controllerType);
}
}

View File

@ -0,0 +1,8 @@
namespace Plane.CopterControllers
{
public enum SpeedType
{
SpeedSlow,
SpeedFast
}
}

View File

@ -0,0 +1,11 @@
using Plane.Copters;
namespace Plane.CopterManagement
{
public interface ICopterFactory
{
ICopter CreateBluetoothCopter(string hostName, string name = "GHOSTDRONE");
IFakeCopter CreateFakeCopter(string id = "FakeCopter", string name = "Linjq's Drone");
}
}

View File

@ -0,0 +1,64 @@
using Plane.Communication;
using Plane.Copters;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
namespace Plane.CopterManagement
{
public interface ICopterManager : ICopterActionsSharedByCopterManager
{
/// <summary>
/// 获取 <see cref="ICopter"/> 实例的动态集合。
/// </summary>
ObservableCollection<ICopter> AllCopters { get; }
/// <summary>
/// 获取单个 <see cref="ICopter"/> 实例。用 <see cref="EmptyCopter.Instance"/> 代替 null使用时不必判断是否为 null。
/// </summary>
ICopter Copter { get; }
/// <summary>
/// 获取一个值,指示是否正在搜寻飞行器。
/// </summary>
bool IsSearching { get; }
/// <summary>
/// 获取被选中的 <see cref="ICopter"/> 实例的动态集合。
/// </summary>
ObservableCollection<ICopter> SelectedCopters { get; }
/// <summary>
/// 添加或更新 <see cref="ICopter"/> 实例。
/// </summary>
/// <param name="id">飞行器的唯一 ID。</param>
/// <param name="name">飞行器的名字。</param>
/// <param name="connection">用于通信的 <see cref="IConnection"/> 实例。</param>
/// <returns></returns>
Task AddOrUpdateCopterAsync(string id, string name, IConnection connection);
/// <summary>
/// 检查飞行器的状态,判断是否允许 FlyTo若允许飞往指定位置。
/// </summary>
/// <param name="lat">目的地纬度。</param>
/// <param name="lng">目的地经度。</param>
/// <returns>若允许并执行了 FlyTo返回 true否则返回 false。</returns>
Task<bool> CheckStatusAndFlyToAsync(double lat, double lng);
/// <summary>
/// 连接一个新的 <see cref="ICopter"/> 实例。
/// </summary>
/// <param name="copter">要连接的 <see cref="ICopter"/> 实例。</param>
/// <returns>表示此异步操作的 <see cref="Task"/> 实例。</returns>
Task ConnectAsync(ICopter copter);
/// <summary>
/// 开始搜索并连接飞行器。
/// </summary>
void StartSearching();
/// <summary>
/// 停止搜索飞行器。
/// </summary>
void StopSearching();
}
}

View File

@ -0,0 +1,27 @@
namespace Plane.Copters
{
public static class Constants
{
/// <summary>
/// 最高加速度,单位为 m/s2。
/// </summary>
public const float MAX_ACCEL = 10f;
public const ushort MAX_CHANNEL = 1900,
MIN_CHANNEL = 1100,
MAX_CHANNEL_DELTA = 370,
HOVER_CHANNEL = 1500,
MAX_HOVER_CHANNEL = MAX_CHANNEL - MAX_CHANNEL_DELTA,
MIN_HOVER_CHANNEL = MIN_CHANNEL + MAX_CHANNEL_DELTA;
/// <summary>
/// 飞行过程中的最大倾斜角度。
/// </summary>
public const float MAX_TILT_IN_FLIGHT = 45;
/// <summary>
/// 最高速度,单位为 m/s。
/// </summary>
public const float MAX_VEL = 5f;
}
}

View File

@ -0,0 +1,27 @@
namespace Plane.Copters
{
public enum CopterCommand
{
StartMovingForward,
StartMovingBack,
StartMovingLeft,
StartMovingRight,
StartMovingUp,
StartMovingDown,
StartRotatingAnticlockwise,
StartRotatingClockwise,
StopMovingForward,
StopMovingBack,
StopMovingLeft,
StopMovingRight,
StopMovingUp,
StopMovingDown,
StopRotatingAnticlockwise,
StopRotatingClockwise,
Unlock,
Lock,
TakeOff,
ReturnToLaunch,
Land
}
}

View File

@ -0,0 +1,16 @@
namespace Plane.Copters
{
public enum CopterState
{
Locked,
Initialized,
TakingOff,
FloatMode,
HoverMode,
CommandMode,
Circling,
Following,
Returning,
Landing
}
}

View File

@ -0,0 +1,38 @@
namespace Plane.Copters
{
/// <summary>
/// 在自动飞行任务中使用的命令枚举,指定飞行器应执行的动作。
/// </summary>
public enum FlightCommand : ushort
{
/// <summary>
/// 命令飞行器飞往指定位置。
/// </summary>
Waypoint = 16,
/// <summary>
/// 命令飞行器在指定位置盘旋指定圈数。
/// </summary>
LoiterTurns = 18,
/// <summary>
/// 命令飞行器在指定位置盘旋指定时间。
/// </summary>
LoiterTime = 19,
/// <summary>
/// 命令飞行器返航。
/// </summary>
ReturnToLaunch = 20,
/// <summary>
/// 命令飞行器降落。
/// </summary>
Land = 21,
/// <summary>
/// 命令飞行器起飞。
/// </summary>
TakeOff = 22
}
}

View File

@ -0,0 +1,17 @@
namespace Plane.Copters
{
public enum GpsFixType : byte
{
NoFix = 0,
Fix2D = 2,
Fix3D = 3
}
public static class ByteExtensions
{
public static GpsFixType ToGpsFixType(this byte value)
{
return value == 1 ? GpsFixType.NoFix : (GpsFixType)value;
}
}
}

View File

@ -0,0 +1,14 @@
using System;
namespace Plane.Copters
{
public class HeartbeatReceivedEventArgs : EventArgs
{
public HeartbeatReceivedEventArgs(ulong count)
{
Count = count;
}
public ulong Count { get; private set; }
}
}

View File

@ -0,0 +1,28 @@
namespace Plane.Copters
{
/// <summary>
/// 定义用于获取三维空间中飞行器姿态的属性。
/// </summary>
public interface IAttitude
{
/// <summary>
/// 获取机头方向,其范围为 [0, 360)。
/// </summary>
short Heading { get; }
/// <summary>
/// 获取俯仰角度,其范围为 (-180, 180],正常飞行中的范围为 [-45, 45]。
/// </summary>
float Pitch { get; }
/// <summary>
/// 获取横滚角度,其范围为 (-180, 180],正常飞行中的范围为 [-45, 45]。
/// </summary>
float Roll { get; }
/// <summary>
/// 获取偏航角度,其范围为 (-180, 180]。
/// </summary>
float Yaw { get; }
}
}

View File

@ -0,0 +1,8 @@
using System.ComponentModel;
namespace Plane.Copters
{
public partial interface ICopter : ICopterStatus, ICopterEvents, ICopterActions, ICopterCommunication, INotifyPropertyChanged
{
}
}

View File

@ -0,0 +1,124 @@
using System.Threading;
using System.Threading.Tasks;
namespace Plane.Copters
{
/// <summary>
/// 定义用于操纵飞行器的属性和方法。
/// </summary>
public partial interface ICopterActions : ICopterActionsSharedByCopterManager, ICopterMissionActions
{
/// <summary>
/// 获取或设置目标通道 1。
/// </summary>
ushort? DesiredChannel1 { get; set; }
/// <summary>
/// 获取或设置目标通道 2。
/// </summary>
ushort? DesiredChannel2 { get; set; }
/// <summary>
/// 获取或设置目标通道 3。
/// </summary>
ushort? DesiredChannel3 { get; set; }
/// <summary>
/// 获取或设置目标通道 4。
/// </summary>
ushort? DesiredChannel4 { get; set; }
/// <summary>
/// 获取或设置目标通道 5。
/// </summary>
ushort? DesiredChannel5 { get; set; }
/// <summary>
/// 获取或设置目标通道 6。
/// </summary>
ushort? DesiredChannel6 { get; set; }
/// <summary>
/// 获取或设置目标通道 7。
/// </summary>
ushort? DesiredChannel7 { get; set; }
/// <summary>
/// 获取或设置目标通道 8。
/// </summary>
ushort? DesiredChannel8 { get; set; }
/// <summary>
/// 获取或设置目标偏航。
/// </summary>
float? DesiredYaw { get; set; }
/// <summary>
/// 获取一个值,指示飞行器是否正处于紧急悬停状态。
/// </summary>
bool IsEmergencyHoverActive { get; }
/// <summary>
/// 开启与飞行器之间的连接。
/// </summary>
/// <returns>表示此异步操作的 <see cref="Task"/> 实例。</returns>
Task ConnectAsync();
/// <summary>
/// 跟随。
/// </summary>
/// <param name="target">目标。</param>
/// <param name="keepYawDifference">设为 true 进保持偏航角度差,设为 false 时将保持两者在空间中的相对位置。</param>
/// <param name="keepFacingTarget">是否保持机头面对目标。</param>
void Follow(IVisibleStatus target, bool keepYawDifference = false, bool keepFacingTarget = true, bool keep3DRelativeLocations = false);
/// <summary>
/// 向飞行器请求数据。
/// </summary>
/// <returns>表示此命令异步发送操作的 <see cref="Task"/> 实例。</returns>
Task GetCopterDataAsync();
/// <summary>
/// 获取参数的值。
/// </summary>
/// <param name="paramName">参数名。</param>
/// <param name="millisecondsTimeout">超时时间,单位为毫秒。</param>
/// <returns>表示参数获取异步操作的 <see cref="Task{TResult}"/>,其结果即为参数的值。</returns>
/// <exception cref="System.TimeoutException">操作超时。</exception>
Task<float> GetParamAsync(string paramName, int millisecondsTimeout = Timeout.Infinite);
/// <summary>
/// 把所有通道设置为目标值。
/// </summary>
/// <returns>表示此命令异步发送操作的 <see cref="Task"/> 实例。</returns>
Task SetChannelsAsync();
/// <summary>
/// 用各个目标值属性设置通道和偏航。
/// </summary>
/// <returns>表示此命令异步发送操作的 <see cref="Task"/> 实例。</returns>
Task SetMobileControlAsync();
/// <summary>
/// 设置参数,返回的 <see cref="Task"/> 实例在确认设置成功后完成。
/// </summary>
/// <param name="paramName">参数名。</param>
/// <param name="value">值。</param>
/// <param name="millisecondsTimeout">超时时间,单位为毫秒。</param>
/// <returns>表示异步设置参数操作的 <see cref="Task"/> 实例。</returns>
/// <exception cref="System.TimeoutException">操作超时。</exception>
Task SetParamAsync(string paramName, float value, int millisecondsTimeout = Timeout.Infinite);
/// <summary>
/// 开始对频。
/// </summary>
/// <returns>表示此命令异步发送操作的 <see cref="Task"/> 实例。</returns>
Task StartPairingAsync();
/// <summary>
/// 停止对频。
/// </summary>
/// <returns>表示此命令异步发送操作的 <see cref="Task"/> 实例。</returns>
Task StopPairingAsync();
}
}

View File

@ -0,0 +1,130 @@
using System.Threading.Tasks;
namespace Plane.Copters
{
public interface ICopterActionsSharedByCopterManager
{
/// <summary>
/// 断开与飞行器之间的连接。
/// </summary>
/// <returns>表示此异步操作的 <see cref="Task"/> 实例。</returns>
Task DisconnectAsync();
/// <summary>
/// 切换到 <see cref="CopterState.FloatMode"/> 并向各个控制通道发中间值。飞行器可能受风等外力影响而在水平方向上飘动。
/// </summary>
/// <returns>表示此命令异步发送操作的 <see cref="Task"/> 实例。</returns>
Task FloatAsync();
/// <summary>
/// 使飞行器飞往水平面上指定的点。
/// </summary>
/// <param name="lat">纬度。</param>
/// <param name="lng">经度。</param>
/// <returns>表示此命令异步发送操作的 <see cref="Task"/> 实例。</returns>
Task FlyToAsync(double lat, double lng);
/// <summary>
/// 使飞行器飞往指定的点。
/// </summary>
/// <param name="lat">纬度。</param>
/// <param name="lng">经度。</param>
/// <param name="alt">相对于解锁点的高度。</param>
/// <returns>表示此命令异步发送操作的 <see cref="Task"/> 实例。</returns>
Task FlyToAsync(double lat, double lng, float alt);
/// <summary>
/// 切换到 <see cref="CopterState.HoverMode"/> 并悬停。此操作需要使用 GPS 定位,卫星数不足导致定位不准时非常危险。
/// </summary>
/// <returns>表示此命令异步发送操作的 <see cref="Task"/> 实例。</returns>
Task HoverAsync();
Task GuidAsync();
/// <summary>
/// 降落。此操作需要使用 GPS 定位,卫星数不足导致定位不准时非常危险。
/// </summary>
/// <returns>表示此命令异步发送操作的 <see cref="Task"/> 实例。</returns>
Task LandAsync();
/// <summary>
/// 锁定飞行器(停止电机转动)。在调用之前务必判断高度及让软件使用者确认!
/// </summary>
Task LockAsync();
/// <summary>
/// 返航。此操作需要使用 GPS 定位,卫星数不足导致定位不准时非常危险。
/// </summary>
/// <returns>表示此命令异步发送操作的 <see cref="Task"/> 实例。</returns>
Task ReturnToLaunchAsync();
/// <summary>
/// 用指定的值设置通道。
/// </summary>
/// <param name="ch1">通道 1 的目标值。</param>
/// <param name="ch2">通道 2 的目标值。</param>
/// <param name="ch3">通道 3 的目标值。</param>
/// <param name="ch4">通道 4 的目标值。</param>
/// <param name="ch5">通道 5 的目标值。</param>
/// <param name="ch6">通道 6 的目标值。</param>
/// <param name="ch7">通道 7 的目标值。</param>
/// <param name="ch8">通道 8 的目标值。</param>
/// <returns>表示此命令异步发送操作的 <see cref="Task"/> 实例。</returns>
Task SetChannelsAsync(ushort? ch1 = null, ushort? ch2 = null, ushort? ch3 = null, ushort? ch4 = null, ushort? ch5 = null, ushort? ch6 = null, ushort? ch7 = null, ushort? ch8 = null);
/// <summary>
/// 用指定的值设置通道和偏航。
/// </summary>
/// <param name="ch1">通道 1 的目标值。</param>
/// <param name="ch2">通道 2 的目标值。</param>
/// <param name="ch3">通道 3 的目标值。</param>
/// <param name="ch4">通道 4 的目标值。目前此参数无效20160119。</param>
/// <param name="ch5">通道 5 的目标值。</param>
/// <param name="ch6">通道 6 的目标值。</param>
/// <param name="ch7">通道 7 的目标值。</param>
/// <param name="ch8">通道 8 的目标值。</param>
/// <param name="yaw">偏航的目标值</param>
/// <returns>表示此命令异步发送操作的 <see cref="Task"/> 实例。</returns>
Task SetMobileControlAsync(ushort? ch1 = null, ushort? ch2 = null, ushort? ch3 = null, ushort? ch4 = null, ushort? ch5 = null, ushort? ch6 = null, ushort? ch7 = null, ushort? ch8 = null, float? yaw = null);
/// <summary>
/// 进入紧急悬停状态。此状态需要使用 GPS 定位,卫星数不足导致定位不准时非常危险。
/// </summary>
/// <returns>表示此命令异步发送操作的 <see cref="Task"/> 实例。</returns>
Task StartEmergencyHoverAsync();
/// <summary>
/// 开始根据各个目标属性(如 <see cref="DesiredChannel1"/>)控制飞行器。
/// </summary>
/// <param name="millisecondsInterval">发送控制命令的时间间距,若为 null将由 SDK 决定。</param>
void StartMobileControl(int? millisecondsInterval = null);
/// <summary>
/// 停止紧急悬停。
/// </summary>
void StopEmergencyHover();
/// <summary>
/// 停止根据各个目标属性(如 <see cref="DesiredChannel1"/>)控制飞行器。
/// </summary>
void StopMobileControl();
/// <summary>
/// 自动起飞到预定高度。此操作需要使用 GPS 定位,卫星数不足导致定位不准时非常危险。
/// </summary>
/// <returns>表示此命令异步发送操作的 <see cref="Task"/> 实例。</returns>
Task TakeOffAsync();
/// <summary>
/// 自动解锁并起飞到指定高度。此操作需要使用 GPS 定位,卫星数不足导致定位不准时非常危险。
/// </summary>
/// <param name="alt">目标高度。</param>
/// <returns>表示此命令异步发送操作的 <see cref="Task"/> 实例。</returns>
Task TakeOffAsync(float alt);
/// <summary>
/// 解锁飞行器。螺旋桨将开始转动,但飞行器不会起飞。
/// </summary>
/// <returns>表示此命令异步发送操作的 <see cref="Task"/> 实例。</returns>
Task UnlockAsync();
}
}

View File

@ -0,0 +1,15 @@
using Plane.Communication;
namespace Plane.Copters
{
/// <summary>
/// 定义与通信相关的属性。
/// </summary>
public interface ICopterCommunication
{
/// <summary>
/// 获取或设置用于与飞行器通信的 <see cref="IConnection"/> 实例。
/// </summary>
IConnection Connection { get; set; }
}
}

View File

@ -0,0 +1,57 @@
using System;
namespace Plane.Copters
{
/// <summary>
/// 定义飞行器代理对象的事件。
/// </summary>
public partial interface ICopterEvents
{
/// <summary>
/// 在高度变化时发生。
/// </summary>
event EventHandler AltitudeChanged;
/// <summary>
/// 在姿态变化时发生。
/// </summary>
event EventHandler AttitudeChanged;
#if PRIVATE
/// <summary>
/// 在收到数据流时发生。
/// </summary>
event EventHandler<DataStreamReceivedEventArgs> DataStreamReceived;
#endif
/// <summary>
/// 在收到心跳时发生。
/// </summary>
event EventHandler<HeartbeatReceivedEventArgs> HeartbeatReceived;
/// <summary>
/// 在位置变化时发生。
/// </summary>
event EventHandler LocationChanged;
/// <summary>
/// 在收到自动飞行任务详情时发生。
/// </summary>
event EventHandler<MissionItemReceivedEventArgs> MissionItemReceived;
/// <summary>
/// 在对频完成(成功或失败)时发生。
/// </summary>
event EventHandler<PairingCompletedEventArgs> PairingCompleted;
/// <summary>
/// 在收到传感器数据时发生。
/// </summary>
event EventHandler SensorDataReceived;
/// <summary>
/// 在收到系统状态信息时发生。
/// </summary>
event EventHandler<SystemStatusReceivedEventArgs> SystemStatusReceived;
}
}

View File

@ -0,0 +1,23 @@
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Plane.Copters
{
public interface ICopterMissionActions
{
/// <summary>
/// 查询任务序列。
/// </summary>
/// <param name="millisecondsTimeout">超时时间。</param>
/// <returns>飞行器返回的任务序列。</returns>
Task<IEnumerable<IMission>> RequestMissionListAsync(int millisecondsTimeout = 10000);
/// <summary>
/// 写入任务序列。
/// </summary>
/// <param name="missions">任务序列。</param>
/// <param name="millisecondsTimeout">超时时间。</param>
/// <returns>若写入成功,返回 true否则返回 false。</returns>
Task<bool> WriteMissionListAsync(IEnumerable<IMission> missions, int millisecondsTimeout = 10000);
}
}

View File

@ -0,0 +1,176 @@
using Plane.Geography;
using System;
namespace Plane.Copters
{
/// <summary>
/// 定义用于获取飞行器状态的属性。
/// </summary>
public partial interface ICopterStatus : IVisibleStatus
{
/// <summary>
/// 获取当前空速,单位为 m/s。
/// </summary>
float AirSpeed { get; }
/// <summary>
/// 获取剩余电量百分比,其范围为 [0, 100]。
/// </summary>
byte BatteryPer { get; }
/// <summary>
/// 获取通道 1 的值。该值在飞控中用于改变飞行器横滚姿态,从而控制其左右方向的移动。有效范围为 [1100, 1900]。小于 1500 时使飞行器向左倾斜,大于 1500 时使飞行器向右倾斜。
/// </summary>
ushort Channel1 { get; }
/// <summary>
/// 获取通道 2 的值。该值在飞控中用于改变飞行器俯仰姿态,从而控制其前后方向的移动。有效范围为 [1100, 1900]。小于 1500 时使飞行器向前倾斜,大于 1500 时使飞行器向后倾斜。
/// </summary>
ushort Channel2 { get; }
/// <summary>
/// 获取通道 3 的值。该值在飞控中用于改变飞行器油门,从而控制其上下方向的移动。有效范围为 [1100, 1900]。在能够定高的模式(如 ALT_HOLD、LOITER小于 1500 时使飞行器下降,大于 1500 时使飞行器上升。
/// </summary>
ushort Channel3 { get; }
/// <summary>
/// 获取通道 4 的值。该值在飞控中用于使飞行器改变机头方向。有效范围为 [1100, 1900]。小于 1500 时使飞行器逆时针旋转,大于 1500 时使飞行器顺时针旋转。
/// </summary>
ushort Channel4 { get; }
/// <summary>
/// 获取通道 5 的值。其作用未定义。
/// </summary>
ushort Channel5 { get; }
/// <summary>
/// 获取通道 6 的值。该值在飞控中用于控制相机正对的方向。有效范围为 [1100, 1900]。小于 1500 时使相机逆时针旋转,大于 1500 时使相机顺时针旋转。
/// </summary>
ushort Channel6 { get; }
/// <summary>
/// 获取通道 7 的值。该值在飞控中用于控制相机俯仰姿态。有效范围为 [1100, 1900]。小于 1500 时使相机向后旋转,大于 1500 时使相机向前旋转。
/// </summary>
ushort Channel7 { get; }
/// <summary>
/// 获取通道 8 的值。其作用未定义。
/// </summary>
ushort Channel8 { get; }
/// <summary>
/// 获取海拔。
/// </summary>
float Elevation { get; }
/// <summary>
/// 获取固件版本。
/// </summary>
int? FirmwareVersion { get; }
/// <summary>
/// 获取固件版本的文本形式。
/// </summary>
string FirmwareVersionText { get; }
/// <summary>
/// 获取在三维空间中的飞行距离。
/// </summary>
double FlightDistance { get; }
/// <summary>
/// 获取在水平面上的飞行距离。
/// </summary>
double FlightDistance2D { get; }
/// <summary>
/// 获取飞行时间。
/// </summary>
TimeSpan FlightTimeSpan { get; }
/// <summary>
/// 获取 GPS 锁定状态。
/// </summary>
GpsFixType GpsFixType { get; }
/// <summary>
/// 获取 GPS HDOPhorizontal dilution of position单位为米。
/// </summary>
float GpsHdop { get; }
/// <summary>
/// 获取当前地速,单位为 m/s。
/// </summary>
float GroundSpeed { get; }
/// <summary>
/// 获取一个值,指示是否切过 GPS 模式。
/// </summary>
bool HasSwitchedToGpsMode { get; }
/// <summary>
/// 获取收到心跳的总数。
/// </summary>
ulong HeartbeatCount { get; }
/// <summary>
/// 获取飞行器的标识。
/// </summary>
string Id { get; }
/// <summary>
/// 获取一个值,指示是否确定飞行器与地面站正常连接。在实现中,一般根据对心跳包的接收情况判断。
/// </summary>
bool IsAbsolutelyConnected { get; }
/// <summary>
/// 获取一个值,指示是否正在检查飞行器与地面站的连接以确定通信正常。在实现中,一般在建立连接后设为 true在收到飞行器发回的数据后设为 false。
/// </summary>
bool IsCheckingConnection { get; set; }
/// <summary>
/// 获取一个值,指示飞行器与地面站之间的连接是否正常。
/// </summary>
bool IsConnected { get; }
/// <summary>
/// 获取一个值,指示当前的 GPS 定位是否足够精确。
/// </summary>
bool IsGpsAccurate { get; }
/// <summary>
/// 获取一个值,指示飞行器是否已解锁。
/// </summary>
bool IsUnlocked { get; }
/// <summary>
/// 获取任务总数。
/// </summary>
ushort? MissionCount { get; }
/// <summary>
/// 获取飞行器的 GPS 卫星数。
/// </summary>
byte SatCount { get; }
/// <summary>
/// 获取当前所处状态。
/// </summary>
CopterState State { get; }
/// <summary>
/// 获取飞控发回的消息,如起飞失败原因。
/// </summary>
string StatusText { get; }
/// <summary>
/// 获取起飞点。
/// </summary>
ILocation TakeOffPoint { get; }
/// <summary>
/// 获取当前电池电压,单位为伏特。
/// </summary>
float Voltage { get; }
}
}

View File

@ -0,0 +1,27 @@
using System;
namespace Plane.Copters
{
/// <summary>
/// 包含 <see cref="ICopter"/> 的所有功能,并提供用于模拟和调试的额外方法。
/// </summary>
public interface IFakeCopter : ICopter
{
void SetProperties(
string id = null, //"Junqing's Drone",
double? latitude = null, //23.14973333,
double? longitude = null, //113.40974166,
float? altitude = null, //0,
string name = null, //"林俊清的飞行器",
byte? batteryPer = null, //10,
short? heading = null, //33,
bool? isConnected = null, //true,
float? pitch = null, //-70,
float? roll = null, //28,
byte? satCount = null, //6,
float? groundSpeed = null, //3.333,
double? flightDistance = null, //100.388,
double? flightDistance2D = null, // 100.88,
TimeSpan? flightTimeSpan = null);
}
}

View File

@ -0,0 +1,53 @@
namespace Plane.Copters
{
/// <summary>
/// 定义自动飞行任务的属性。
/// </summary>
public interface IMission
{
/// <summary>
/// 获取或设置相对于起飞点的高度。
/// </summary>
float Altitude { get; set; }
/// <summary>
/// 获取或设置飞行命令。
/// </summary>
FlightCommand Command { get; set; }
/// <summary>
/// 获取或设置纬度。
/// </summary>
double Latitude { get; set; }
/// <summary>
/// 获取或设置经度。
/// </summary>
double Longitude { get; set; }
/// <summary>
/// 获取或设置参数 1。通常用来指定判断为到达的最大半径单位为米。
/// </summary>
float Param1 { get; set; }
/// <summary>
/// 获取或设置参数 2。通常用来指定停留时间单位为毫秒。
/// </summary>
float Param2 { get; set; }
/// <summary>
/// 获取或设置参数 3。通常用来指定盘旋半径单位为米正数表示顺时针负数表示逆时针。
/// </summary>
float Param3 { get; set; }
/// <summary>
/// 获取或设置参数 4。通常用来指定机头方向单位为角度北方为 0东方为 90范围为 [0, 360)。
/// </summary>
float Param4 { get; set; }
/// <summary>
/// 获取或设置序号。
/// </summary>
ushort Sequence { get; set; }
}
}

View File

@ -0,0 +1,15 @@
using Plane.Geography;
namespace Plane.Copters
{
/// <summary>
/// 定义物体可见的状态。
/// </summary>
public interface IVisibleStatus : ILocation, IAttitude
{
/// <summary>
/// 获取名称。
/// </summary>
string Name { get; }
}
}

View File

@ -0,0 +1,9 @@
using System;
namespace Plane.Copters
{
public class MessageCreatedEventArgs : EventArgs
{
public string Message { get; set; }
}
}

View File

@ -0,0 +1,17 @@
using System;
namespace Plane.Copters
{
public class MissionItemReceivedEventArgs : EventArgs
{
public MissionItemReceivedEventArgs(IMission mission)
{
Mission = mission;
}
/// <summary>
/// 获取任务详情。
/// </summary>
public IMission Mission { get; private set; }
}
}

View File

@ -0,0 +1,414 @@
#define CMNATTR
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Linq.Expressions;
// ReSharper disable RedundantUsingDirective
using System.Linq;
using System.Threading;
// ReSharper restore RedundantUsingDirective
#if CMNATTR
using System.Runtime.CompilerServices;
#endif
namespace Plane.Copters
{
/// <summary>
/// A base class for objects of which the properties must be observable (based on MvvmLight's ObservableObject).
/// </summary>
//// [ClassInfo(typeof(ViewModelBase))]
public class PLObservableObject : INotifyPropertyChanged /*, INotifyPropertyChanging*/
{
/// <summary>
/// 与 UI 线程关联的 <see cref="SynchronizationContext"/> 实例。
/// </summary>
protected SynchronizationContext _uiSyncContext;
/// <summary>
/// 创建 <see cref="EHObservableObject"/> 的实例。
/// </summary>
/// <param name="uiSyncContext"></param>
public PLObservableObject(SynchronizationContext uiSyncContext)
{
_uiSyncContext = uiSyncContext;
}
/// <summary>
/// Occurs after a property value changes.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Provides access to the PropertyChanged event handler to derived classes.
/// </summary>
protected PropertyChangedEventHandler PropertyChangedHandler
{
get
{
return PropertyChanged;
}
}
#if !PORTABLE && !SL4 && !WINDOWS_UWP
/// <summary>
/// Occurs before a property value changes.
/// </summary>
public event PropertyChangingEventHandler PropertyChanging;
/// <summary>
/// Provides access to the PropertyChanging event handler to derived classes.
/// </summary>
protected PropertyChangingEventHandler PropertyChangingHandler
{
get
{
return PropertyChanging;
}
}
#endif
/// <summary>
/// Verifies that a property name exists in this ViewModel. This method
/// can be called before the property is used, for instance before
/// calling RaisePropertyChanged. It avoids errors when a property name
/// is changed but some places are missed.
/// </summary>
/// <remarks>This method is only active in DEBUG mode.</remarks>
/// <param name="propertyName">The name of the property that will be
/// checked.</param>
[Conditional("DEBUG")]
[DebuggerStepThrough]
public void VerifyPropertyName(string propertyName)
{
var myType = GetType();
#if NETFX_CORE
if (!string.IsNullOrEmpty(propertyName)
&& myType.GetRuntimeProperty(propertyName) == null)
{
throw new ArgumentException("Property not found", propertyName);
}
#else
if (!string.IsNullOrEmpty(propertyName)
&& myType.GetProperty(propertyName) == null)
{
#if !SILVERLIGHT
var descriptor = this as ICustomTypeDescriptor;
if (descriptor != null)
{
if (descriptor.GetProperties()
.Cast<PropertyDescriptor>()
.Any(property => property.Name == propertyName))
{
return;
}
}
#endif
throw new ArgumentException("Property not found", propertyName);
}
#endif
}
#if !PORTABLE && !SL4 && !WINDOWS_UWP
#if CMNATTR
/// <summary>
/// Raises the PropertyChanging event if needed.
/// </summary>
/// <remarks>If the propertyName parameter
/// does not correspond to an existing property on the current class, an
/// exception is thrown in DEBUG configuration only.</remarks>
/// <param name="propertyName">(optional) The name of the property that
/// changed.</param>
[SuppressMessage(
"Microsoft.Design",
"CA1030:UseEventsWhereAppropriate",
Justification = "This cannot be an event")]
protected virtual void RaisePropertyChanging(
[CallerMemberName] string propertyName = null)
#else
/// <summary>
/// Raises the PropertyChanging event if needed.
/// </summary>
/// <remarks>If the propertyName parameter
/// does not correspond to an existing property on the current class, an
/// exception is thrown in DEBUG configuration only.</remarks>
/// <param name="propertyName">The name of the property that
/// changed.</param>
[SuppressMessage(
"Microsoft.Design",
"CA1030:UseEventsWhereAppropriate",
Justification = "This cannot be an event")]
protected virtual void RaisePropertyChanging(
string propertyName)
#endif
{
VerifyPropertyName(propertyName);
var handler = PropertyChanging;
if (handler != null)
{
handler(this, new PropertyChangingEventArgs(propertyName));
}
}
#endif
#if CMNATTR
/// <summary>
/// Raises the PropertyChanged event if needed.
/// </summary>
/// <remarks>If the propertyName parameter
/// does not correspond to an existing property on the current class, an
/// exception is thrown in DEBUG configuration only.</remarks>
/// <param name="propertyName">(optional) The name of the property that
/// changed.</param>
[SuppressMessage(
"Microsoft.Design",
"CA1030:UseEventsWhereAppropriate",
Justification = "This cannot be an event")]
protected virtual void RaisePropertyChanged(
[CallerMemberName] string propertyName = null)
#else
/// <summary>
/// Raises the PropertyChanged event if needed.
/// </summary>
/// <remarks>If the propertyName parameter
/// does not correspond to an existing property on the current class, an
/// exception is thrown in DEBUG configuration only.</remarks>
/// <param name="propertyName">The name of the property that
/// changed.</param>
[SuppressMessage(
"Microsoft.Design",
"CA1030:UseEventsWhereAppropriate",
Justification = "This cannot be an event")]
protected virtual void RaisePropertyChanged(
string propertyName)
#endif
{
VerifyPropertyName(propertyName);
var handler = PropertyChanged;
if (handler != null)
{
#if NETFX_CORE
var e = new PropertyChangedEventArgs(propertyName);
if (SynchronizationContext.Current == _uiSyncContext) handler(this, e);
else _uiSyncContext.Post(() => handler(this, e));
#else
handler(this, new PropertyChangedEventArgs(propertyName));
#endif
}
}
#if !PORTABLE && !SL4 && !WINDOWS_UWP
/// <summary>
/// Raises the PropertyChanging event if needed.
/// </summary>
/// <typeparam name="T">The type of the property that
/// changes.</typeparam>
/// <param name="propertyExpression">An expression identifying the property
/// that changes.</param>
[SuppressMessage(
"Microsoft.Design",
"CA1030:UseEventsWhereAppropriate",
Justification = "This cannot be an event")]
[SuppressMessage(
"Microsoft.Design",
"CA1006:GenericMethodsShouldProvideTypeParameter",
Justification = "This syntax is more convenient than other alternatives.")]
protected virtual void RaisePropertyChanging<T>(Expression<Func<T>> propertyExpression)
{
var handler = PropertyChanging;
if (handler != null)
{
var propertyName = GetPropertyName(propertyExpression);
handler(this, new PropertyChangingEventArgs(propertyName));
}
}
#endif
/// <summary>
/// Raises the PropertyChanged event if needed.
/// </summary>
/// <typeparam name="T">The type of the property that
/// changed.</typeparam>
/// <param name="propertyExpression">An expression identifying the property
/// that changed.</param>
[SuppressMessage(
"Microsoft.Design",
"CA1030:UseEventsWhereAppropriate",
Justification = "This cannot be an event")]
[SuppressMessage(
"Microsoft.Design",
"CA1006:GenericMethodsShouldProvideTypeParameter",
Justification = "This syntax is more convenient than other alternatives.")]
protected virtual void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpression)
{
var handler = PropertyChanged;
if (handler != null)
{
var propertyName = GetPropertyName(propertyExpression);
#if NETFX_CORE
var e = new PropertyChangedEventArgs(propertyName);
if (SynchronizationContext.Current == _uiSyncContext) handler(this, e);
else _uiSyncContext.Post(() => handler(this, e));
#else
handler(this, new PropertyChangedEventArgs(propertyName));
#endif
}
}
/// <summary>
/// Extracts the name of a property from an expression.
/// </summary>
/// <typeparam name="T">The type of the property.</typeparam>
/// <param name="propertyExpression">An expression returning the property's name.</param>
/// <returns>The name of the property returned by the expression.</returns>
/// <exception cref="ArgumentNullException">If the expression is null.</exception>
/// <exception cref="ArgumentException">If the expression does not represent a property.</exception>
[SuppressMessage(
"Microsoft.Design",
"CA1011:ConsiderPassingBaseTypesAsParameters",
Justification = "This syntax is more convenient than the alternatives."),
SuppressMessage(
"Microsoft.Design",
"CA1006:DoNotNestGenericTypesInMemberSignatures",
Justification = "This syntax is more convenient than the alternatives.")]
protected static string GetPropertyName<T>(Expression<Func<T>> propertyExpression)
{
if (propertyExpression == null)
{
throw new ArgumentNullException("propertyExpression");
}
var body = propertyExpression.Body as MemberExpression;
if (body == null)
{
throw new ArgumentException("Invalid argument", "propertyExpression");
}
var property = body.Member as PropertyInfo;
if (property == null)
{
throw new ArgumentException("Argument is not a property", "propertyExpression");
}
return property.Name;
}
/// <summary>
/// Assigns a new value to the property. Then, raises the
/// PropertyChanged event if needed.
/// </summary>
/// <typeparam name="T">The type of the property that
/// changed.</typeparam>
/// <param name="propertyExpression">An expression identifying the property
/// that changed.</param>
/// <param name="field">The field storing the property's value.</param>
/// <param name="newValue">The property's value after the change
/// occurred.</param>
/// <returns>True if the PropertyChanged event has been raised,
/// false otherwise. The event is not raised if the old
/// value is equal to the new value.</returns>
[SuppressMessage(
"Microsoft.Design",
"CA1006:DoNotNestGenericTypesInMemberSignatures",
Justification = "This syntax is more convenient than the alternatives."),
SuppressMessage(
"Microsoft.Design",
"CA1045:DoNotPassTypesByReference",
MessageId = "1#",
Justification = "This syntax is more convenient than the alternatives.")]
protected bool Set<T>(
Expression<Func<T>> propertyExpression,
ref T field,
T newValue)
{
if (EqualityComparer<T>.Default.Equals(field, newValue))
{
return false;
}
#if !PORTABLE && !SL4 && !WINDOWS_UWP
RaisePropertyChanging(propertyExpression);
#endif
field = newValue;
RaisePropertyChanged(propertyExpression);
return true;
}
/// <summary>
/// Assigns a new value to the property. Then, raises the
/// PropertyChanged event if needed.
/// </summary>
/// <typeparam name="T">The type of the property that
/// changed.</typeparam>
/// <param name="propertyName">The name of the property that
/// changed.</param>
/// <param name="field">The field storing the property's value.</param>
/// <param name="newValue">The property's value after the change
/// occurred.</param>
/// <returns>True if the PropertyChanged event has been raised,
/// false otherwise. The event is not raised if the old
/// value is equal to the new value.</returns>
[SuppressMessage(
"Microsoft.Design",
"CA1045:DoNotPassTypesByReference",
MessageId = "1#",
Justification = "This syntax is more convenient than the alternatives.")]
protected bool Set<T>(
string propertyName,
ref T field,
T newValue)
{
if (EqualityComparer<T>.Default.Equals(field, newValue))
{
return false;
}
#if !PORTABLE && !SL4 && !WINDOWS_UWP
RaisePropertyChanging(propertyName);
#endif
field = newValue;
// ReSharper disable ExplicitCallerInfoArgument
RaisePropertyChanged(propertyName);
// ReSharper restore ExplicitCallerInfoArgument
return true;
}
#if CMNATTR
/// <summary>
/// Assigns a new value to the property. Then, raises the
/// PropertyChanged event if needed.
/// </summary>
/// <typeparam name="T">The type of the property that
/// changed.</typeparam>
/// <param name="field">The field storing the property's value.</param>
/// <param name="newValue">The property's value after the change
/// occurred.</param>
/// <param name="propertyName">(optional) The name of the property that
/// changed.</param>
/// <returns>True if the PropertyChanged event has been raised,
/// false otherwise. The event is not raised if the old
/// value is equal to the new value.</returns>
protected bool Set<T>(
ref T field,
T newValue,
[CallerMemberName] string propertyName = null)
{
return Set(propertyName, ref field, newValue);
}
#endif
}
}

View File

@ -0,0 +1,20 @@
using System;
namespace Plane.Copters
{
public class PairingCompletedEventArgs : EventArgs
{
public PairingCompletedEventArgs(bool isSuccessful, int rxId, int txId)
{
IsSuccessful = isSuccessful;
RxID = rxId;
TxID = txId;
}
public bool IsSuccessful { get; set; }
public int RxID { get; set; }
public int TxID { get; set; }
}
}

View File

@ -0,0 +1,26 @@
using System;
namespace Plane.Copters
{
public class SystemStatusReceivedEventArgs : EventArgs
{
public SystemStatusReceivedEventArgs(bool gpsBadHealth, bool gyroBadHealth, bool accelBadHealth, bool compassBadHealth, bool barometerBadHealth)
{
GpsBadHealth = gpsBadHealth;
GyroBadHealth = gyroBadHealth;
AccelBadHealth = accelBadHealth;
CompassBadHealth = compassBadHealth;
BarometerBadHealth = barometerBadHealth;
}
public bool AccelBadHealth { get; private set; }
public bool BarometerBadHealth { get; private set; }
public bool CompassBadHealth { get; private set; }
public bool GpsBadHealth { get; private set; }
public bool GyroBadHealth { get; private set; }
}
}

View File

@ -0,0 +1,23 @@
using Plane.Geography;
namespace Plane.Copters
{
public class VisibleStatus : IVisibleStatus
{
public float Altitude { get; set; }
public short Heading => (short)Yaw.NormalizeDirection();
public double Latitude { get; set; }
public double Longitude { get; set; }
public string Name { get; set; }
public float Pitch { get; set; }
public float Roll { get; set; }
public float Yaw { get; set; }
}
}

View File

@ -0,0 +1,301 @@
using System;
namespace Plane.Geography
{
/// <summary>
/// 提供地理相关计算的方法。
/// </summary>
public static class GeographyUtils
{
/// <summary>
/// 米数转换为纬度跨度时需要乘的常数。
/// </summary>
public const double METERS_TO_LAT_SPAN = 1 / (GLOBE_CIRCUMFERENCE / 360);
/// <summary>
/// 角度转换为弧度时需要乘的常数。
/// </summary>
private const double DEG_TO_RAD = Math.PI / 180;
/// <summary>
/// 地球的半径。
/// </summary>
private const double EARTH_RADIUS = 6371000;
/// <summary>
/// 当前星球的周长。
/// </summary>
private const double GLOBE_CIRCUMFERENCE = GLOBE_RADIUS * 2 * Math.PI;
/// <summary>
/// 当前星球的半径。
/// </summary>
private const double GLOBE_RADIUS = EARTH_RADIUS;
/// <summary>
/// 计算从 (lat1, lng1) 到 (lat2, lng2) 的方向,单位为弧度。
/// </summary>
/// <param name="lat1">第一个点的纬度。</param>
/// <param name="lng1">第一个点的经度。</param>
/// <param name="lat2">第二个点的纬度。</param>
/// <param name="lng2">第二个点的经度。</param>
/// <returns>点 1 到点 2 的方向。</returns>
public static double CalcDirection2D(double lat1, double lng1, double lat2, double lng2)
{
return Math.Atan2((lng2 - lng1) / CalcMetersToLngSpan(lat1), (lat2 - lat1) / METERS_TO_LAT_SPAN).NormalizeDirectionRad();
}
/// <summary>
/// 计算空间中两点间的距离,单位为米。
/// </summary>
/// <param name="l1">点 1。</param>
/// <param name="l2">点 2。</param>
/// <returns>空间中两点间的距离,单位为米。</returns>
public static double CalcDistance(ILocation l1, ILocation l2)
{
return CalcDistance(l1.Latitude, l1.Longitude, l1.Altitude, l2.Latitude, l2.Longitude, l2.Altitude);
}
/// <summary>
/// 计算空间中两点之间的距离,单位为米。
/// </summary>
/// <param name="lat1">纬度 1。</param>
/// <param name="lng1">经度 1。</param>
/// <param name="alt1">高度 1。</param>
/// <param name="lat2">纬度 2。</param>
/// <param name="lng2">经度 2。</param>
/// <param name="alt2">高度 2。</param>
/// <returns>空间中两点之间的距离,单位为米。</returns>
public static double CalcDistance(double lat1, double lng1, double alt1, double lat2, double lng2, double alt2)
{
// generally used geo measurement function
// var R = 6378.137; // Radius of earth in KM
var dLat = (lat2 - lat1) * Math.PI / 180;
var dLon = (lng2 - lng1) * Math.PI / 180;
var a = Math.Sin(dLat / 2) * Math.Sin(dLat / 2)
+ Math.Cos(lat1 * Math.PI / 180) * Math.Cos(lat2 * Math.PI / 180) * Math.Sin(dLon / 2) * Math.Sin(dLon / 2);
var c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
var d = GLOBE_RADIUS * c;
return Math.Sqrt(Math.Pow((alt2 - alt1), 2) + Math.Pow(d, 2));
}
/// <summary>
/// 计算二维平面上两个位置之间的距离,单位为米。
/// </summary>
/// <param name="l1">位置 1。</param>
/// <param name="l2">位置 2。</param>
/// <returns>空间中两点间的距离。</returns>
public static double CalcDistance2D(ILocation2D l1, ILocation2D l2)
=> CalcDistance2D(l1.Latitude, l1.Longitude, l2.Latitude, l2.Longitude);
/// <summary>
/// 计算二维平面上两个位置之间的距离,单位为米。
/// </summary>
/// <param name="lat1">纬度 1。</param>
/// <param name="lng1">经度 1。</param>
/// <param name="lat2">纬度 2。</param>
/// <param name="lng2">经度 2。</param>
/// <returns>计算二维平面上两个位置之间的距离,单位为米。</returns>
public static double CalcDistance2D(double lat1, double lng1, double lat2, double lng2)
=> CalcDistance(lat1, lng1, 0, lat2, lng2, 0);
/// <summary>
/// 计算在水平面上从指定点往指定方向移动指定距离后所在的点。
/// </summary>
/// <param name="lat1">出发点的纬度。</param>
/// <param name="lng1">出发点的经度。</param>
/// <param name="directionDegrees">移动方向,单位为角度。</param>
/// <param name="distance">移动距离。</param>
/// <returns>从指定点往指定方向移动指定距离后所在的点。</returns>
public static Tuple<double, double> CalcLatLngSomeMetersAway2D(double lat1, double lng1, float directionDegrees, float distance)
{
var direction = directionDegrees.DegToRad();
return Tuple.Create(
lat1 + distance * Math.Cos(direction) * METERS_TO_LAT_SPAN,
lng1 + distance * Math.Sin(direction) * CalcMetersToLngSpan(lat1)
);
}
/// <summary>
/// 计算在水平面上从指定点往指定方向移动指定距离后所在的点。
/// </summary>
/// <param name="loc1">出发点。</param>
/// <param name="directionDegrees">移动方向,单位为角度。</param>
/// <param name="distance">移动距离。</param>
/// <returns>从指定点往指定方向移动指定距离后所在的点。</returns>
public static ILocation2D CalcLatLngSomeMetersAway2D(ILocation2D loc1, float directionDegrees, float distance)
{
var direction = directionDegrees.DegToRad();
return new PLLocation(
loc1.Latitude + distance * Math.Cos(direction) * METERS_TO_LAT_SPAN,
loc1.Longitude + distance * Math.Sin(direction) * CalcMetersToLngSpan(loc1.Latitude),
0
);
}
/// <summary>
/// 计算在指定纬度上,米数转换为经度跨度时需要乘的值。
/// </summary>
/// <param name="latitude">纬度。</param>
/// <returns>在指定纬度上,米数转换为经度跨度时需要乘的值。</returns>
public static double CalcMetersToLngSpan(double latitude)
{
return METERS_TO_LAT_SPAN / Math.Cos(latitude * DEG_TO_RAD);
}
/// <summary>
/// 检测同一水平面上(忽略高度)的两条线段是否相交。
/// </summary>
/// <param name="l1">线段 A 端点 1。</param>
/// <param name="l2">线段 A 端点 2。</param>
/// <param name="l3">线段 B 端点 1。</param>
/// <param name="l4">线段 B 端点 2。</param>
/// <returns>若相交,返回 true否则返回 false。</returns>
public static bool CheckCrossing2D(ILocation2D l1, ILocation2D l2, ILocation2D l3, ILocation2D l4)
=> CheckCrossing2D(l1.Latitude, l1.Longitude, l2.Latitude, l2.Longitude, l3.Latitude, l3.Longitude, l4.Latitude, l4.Longitude);
/// <summary>
/// 检测同一水平面上的两条线段是否相交。
/// </summary>
/// <param name="latA1">线段 A 端点 1 的纬度。</param>
/// <param name="lngA1">线段 A 端点 1 的经度。</param>
/// <param name="latA2">线段 A 端点 2 的纬度。</param>
/// <param name="lngA2">线段 A 端点 2 的经度。</param>
/// <param name="latB1">线段 B 端点 1 的纬度。</param>
/// <param name="lngB1">线段 B 端点 1 的经度。</param>
/// <param name="latB2">线段 B 端点 2 的纬度。</param>
/// <param name="lngB2">线段 B 端点 2 的经度。</param>
/// <returns>若相交,返回 true否则返回 false。</returns>
public static bool CheckCrossing2D(double latA1, double lngA1, double latA2, double lngA2,
double latB1, double lngB1, double latB2, double lngB2)
{
// 线段 A(x1, y1) - B(x2, y2), 所在直线 L1 方程为 F(x, y) = 0;
// 线段 C(x3, y3) - D(x4, y4), 所在直线 L2 方程为 G(x, y) = 0;
// 思路:
// (即问题的充要条件)
// (点 A 与点 B 在直线 L2 两侧) AND (点 C 与点 D 在直线 L1 两侧);
// 方法:
// 如果点 P(Xp, Yp) 不在直线 a * x + b * y + c = 0 上, 则 a* Xp + b * Yp + c <> 0;
// 如果用两个点的坐标代入同一直线方程 a * x + b * y + c 计算出的值异号, 则两点在直线两侧;
// 解法:
// (G(x1, y1) * G(x2, y2) < 0) AND (F(x3, y3) * F(x4, y4) < 0)
// 斜截式 y = kx + b
// 即 kx - y + b = 0
var k1 = (latA2 - latA1) / (lngA2 - lngA1);
var b1 = latA1 - k1 * lngA1;
var k2 = (latB2 - latB1) / (lngB2 - lngB1);
var b2 = latB1 - k2 * lngB1;
return k2 * lngA1 - latA1 + b2 > 0 != k2 * lngA2 - latA2 + b2 > 0 &&
k1 * lngB1 - latB1 + b1 > 0 != k1 * lngB2 - latB2 + b1 > 0;
}
/// <summary>
/// 把角度转换为弧度。
/// </summary>
/// <param name="value">角度值。</param>
/// <returns>弧度值。</returns>
public static double DegToRad(this float value)
{
return value * DEG_TO_RAD;
}
/// <summary>
/// 把角度转换为弧度。
/// </summary>
/// <param name="value">角度值。</param>
/// <returns>弧度值。</returns>
public static double DegToRad(this double value)
{
return value * DEG_TO_RAD;
}
/// <summary>
/// 把角度转换为弧度。
/// </summary>
/// <param name="value">角度值。</param>
/// <returns>弧度值。</returns>
public static double DegToRad(this short value)
{
return value * DEG_TO_RAD;
}
/// <summary>
/// 把指示方向的角度数限制在 [0, 360)。
/// </summary>
/// <param name="value">指示方向的角度数。</param>
/// <returns>等价的在标准范围内的角度。</returns>
public static float NormalizeDirection(this float value)
{
while (value < 0)
{
value += 360;
}
while (value >= 360)
{
value -= 360;
}
return value;
}
/// <summary>
/// 把指示方向的角度值限制在 [0, 360)。
/// </summary>
/// <param name="value">指示方向的角度值。</param>
/// <returns>等价的在标准范围内的角度。</returns>
public static double NormalizeDirection(this double value)
{
while (value < 0)
{
value += 360;
}
while (value >= 360)
{
value -= 360;
}
return value;
}
/// <summary>
/// 把指示方向的弧度值限制在 [0, 2PI)。
/// </summary>
/// <param name="value">指示方向的弧度值。</param>
/// <returns>等价的在标准范围内的弧度。</returns>
public static double NormalizeDirectionRad(this double value)
{
while (value < 0)
{
value += Math.PI * 2;
}
while (value >= Math.PI * 2)
{
value -= Math.PI * 2;
}
return value;
}
/// <summary>
/// 把弧度转换为角度。
/// </summary>
/// <param name="value">弧度值。</param>
/// <returns>角度值。</returns>
public static double RadToDeg(this float value)
{
return value / DEG_TO_RAD;
}
/// <summary>
/// 把弧度转换为角度。
/// </summary>
/// <param name="value">弧度值。</param>
/// <returns>角度值。</returns>
public static double RadToDeg(this double value)
{
return value / DEG_TO_RAD;
}
}
}

View File

@ -0,0 +1,13 @@
namespace Plane.Geography
{
/// <summary>
/// 定义可用于确定一个固定的星球上的空间中的一个点的属性。
/// </summary>
public interface ILocation : ILocation2D
{
/// <summary>
/// 获取相对高度。
/// </summary>
float Altitude { get; }
}
}

View File

@ -0,0 +1,15 @@
namespace Plane.Geography
{
public interface ILocation2D
{
/// <summary>
/// 获取纬度。
/// </summary>
double Latitude { get; }
/// <summary>
/// 获取经度。
/// </summary>
double Longitude { get; }
}
}

View File

@ -0,0 +1,80 @@
namespace Plane.Geography
{
public static class LocationExtensions
{
/// <summary>
/// 计算在二维平面上从 <paramref name="l1"/> 到 <paramref name="l2"/> 的方向,单位为弧度。
/// </summary>
/// <param name="l1">出发点。</param>
/// <param name="l2">目标点。</param>
/// <returns>点 1 到点 2 的方向。</returns>
public static double CalcDirection2D(this ILocation2D l1, ILocation2D l2)
=> GeographyUtils.CalcDirection2D(l1.Latitude, l1.Longitude, l2.Latitude, l2.Longitude);
/// <summary>
/// 计算在二维平面上从 <paramref name="l1"/> 到 (<paramref name="lat2"/>, <paramref name="lng2"/>) 的方向,单位为弧度。
/// </summary>
/// <param name="l1">出发点。</param>
/// <param name="lat2">目标点的纬度。</param>
/// <param name="lng2">目标点的经度。</param>
/// <returns>点 1 到点 2 的方向。</returns>
public static double CalcDirection2D(this ILocation2D l1, double lat2, double lng2)
=> GeographyUtils.CalcDirection2D(l1.Latitude, l1.Longitude, lat2, lng2);
/// <summary>
/// 计算空间中两点间的距离,单位为米。
/// </summary>
/// <param name="l1">点 1。</param>
/// <param name="l2">点 2。</param>
/// <returns>空间中两点间的距离。</returns>
public static double CalcDistance(this ILocation l1, ILocation l2)
=> GeographyUtils.CalcDistance(l1, l2);
/// <summary>
/// 计算空间中两点间的距离,单位为米。
/// </summary>
/// <param name="l1">点 1。</param>
/// <param name="lat2">点 2 的纬度。</param>
/// <param name="lng2">点 2 的经度。</param>
/// <param name="alt2">点 2 的高度。</param>
/// <returns>空间中两点间的距离。</returns>
public static double CalcDistance(this ILocation l1, double lat2, double lng2, double alt2)
=> GeographyUtils.CalcDistance(l1.Latitude, l1.Longitude, l1.Altitude, lat2, lng2, alt2);
/// <summary>
/// 计算二维平面上两个位置之间的距离,单位为米。
/// </summary>
/// <param name="l1">位置 1。</param>
/// <param name="l2">位置 2。</param>
/// <returns>平面上两点间的距离。</returns>
public static double CalcDistance2D(this ILocation2D l1, ILocation2D l2)
=> GeographyUtils.CalcDistance2D(l1, l2);
/// <summary>
/// 计算二维平面上两个位置之间的距离,单位为米。
/// </summary>
/// <param name="lat2">点 2 的纬度。</param>
/// <param name="lng2">点 2 的经度。</param>
/// <returns>平面上两点间的距离。</returns>
public static double CalcDistance2D(this ILocation2D l1, double lat2, double lng2)
=> GeographyUtils.CalcDistance2D(l1.Latitude, l1.Longitude, lat2, lng2);
/// <summary>
/// 计算在水平面上从指定点往指定方向移动指定距离后所在的点。
/// </summary>
/// <param name="loc1">出发点。</param>
/// <param name="directionDegrees">移动方向,单位为角度。</param>
/// <param name="distance">移动距离。</param>
/// <returns>从指定点往指定方向移动指定距离后所在的点。</returns>
public static ILocation2D CalcLatLngSomeMetersAway2D(this ILocation2D loc1, float directionDegrees, float distance)
=> GeographyUtils.CalcLatLngSomeMetersAway2D(loc1, directionDegrees, distance);
/// <summary>
/// 判断一个 <see cref="ILocation"/> 实例是否被认为是空值。
/// </summary>
/// <param name="loc"><see cref="ILocation"/> 实例。</param>
/// <returns>若给定的位置被认为是空值,返回 true否则返回 false。</returns>
public static bool IsNullOrEmpty(this ILocation loc)
=> loc == null || (loc.Latitude == 0 && loc.Longitude == 0 && loc.Altitude == 0);
}
}

View File

@ -0,0 +1,56 @@
using System.Diagnostics;
namespace Plane.Geography
{
[DebuggerDisplay("lat: {Latitude}, lng: {Longitude}, alt: {Altitude}")]
public class PLLocation : ILocation
{
public PLLocation()
{
}
public PLLocation(ILocation locToCopy)
: this(locToCopy.Latitude, locToCopy.Longitude, locToCopy.Altitude)
{
}
public PLLocation(double lat, double lng, float alt)
{
Latitude = lat;
Longitude = lng;
Altitude = alt;
}
public float Altitude { get; set; }
public double Latitude { get; set; }
public double Longitude { get; set; }
public PLLocation AddAltitude(float altToAdd)
{
Altitude += altToAdd;
return this;
}
public PLLocation AddLatitude(double latToAdd)
{
Latitude += latToAdd;
return this;
}
public PLLocation AddLatLngAlt(double latToAdd, double lngToAdd, float altToAdd)
{
Latitude += latToAdd;
Longitude += lngToAdd;
Altitude += altToAdd;
return this;
}
public PLLocation AddLongitude(double lngToAdd)
{
Longitude += lngToAdd;
return this;
}
}
}

View File

@ -0,0 +1,31 @@
using System;
namespace Plane
{
public static class MathExtensions
{
public static bool IsInRange<T>(this T value, T min, T max) where T : struct, IComparable<T>
{
if (min.CompareTo(max) > 0)
{
throw new ArgumentException($"The {nameof(min)} argument ({min}) must be less than or equal to the {nameof(max)} argument ({max}).");
}
return value.CompareTo(min) >= 0 && value.CompareTo(max) <= 0;
}
public static T Limit<T>(this T value, T? min = null, T? max = null) where T : struct, IComparable<T>
{
if (min.HasValue && max.HasValue && min.Value.CompareTo(max.Value) > 0)
{
throw new ArgumentException($"The {nameof(min)} argument ({min}) must be less than or equal to the {nameof(max)} argument ({max}).");
}
if (!min.HasValue && !max.HasValue)
{
throw new ArgumentException($"The {nameof(min)} argument and the {nameof(max)} argument are both missing.");
}
if (min.HasValue && value.CompareTo(min.Value) < 0) return min.Value;
if (max.HasValue && value.CompareTo(max.Value) > 0) return max.Value;
return value;
}
}
}

View File

@ -0,0 +1,11 @@
using Plane.Copters;
namespace Plane.Messaging
{
public class CopterAltitudeChangedMessage : CopterMessageBase
{
public CopterAltitudeChangedMessage(ICopter copter) : base(copter)
{
}
}
}

View File

@ -0,0 +1,14 @@
using Plane.Copters;
namespace Plane.Messaging
{
/// <summary>
/// 在飞行器姿态变化时发出的消息。
/// </summary>
public class CopterAttitudeChangedMessage : CopterMessageBase
{
public CopterAttitudeChangedMessage(ICopter copter) : base(copter)
{
}
}
}

View File

@ -0,0 +1,11 @@
using Plane.Copters;
namespace Plane.Messaging
{
public class CopterConnectedMessage : CopterMessageBase
{
public CopterConnectedMessage(ICopter copter) : base(copter)
{
}
}
}

View File

@ -0,0 +1,11 @@
using Plane.Copters;
namespace Plane.Messaging
{
public class CopterHeartbeatReceivedMessage : CopterMessageBase
{
public CopterHeartbeatReceivedMessage(ICopter copter) : base(copter)
{
}
}
}

View File

@ -0,0 +1,11 @@
using Plane.Copters;
namespace Plane.Messaging
{
public class CopterLocationChangedMessage : CopterMessageBase
{
public CopterLocationChangedMessage(ICopter copter) : base(copter)
{
}
}
}

View File

@ -0,0 +1,14 @@
using Plane.Copters;
namespace Plane.Messaging
{
public class CopterMessageBase
{
public CopterMessageBase(ICopter copter)
{
Copter = copter;
}
public ICopter Copter { get; set; }
}
}

View File

@ -0,0 +1,14 @@
using Plane.Copters;
namespace Plane.Messaging
{
public class CopterPairingCompletedMessage : CopterMessageBase
{
public CopterPairingCompletedMessage(ICopter copter, bool isSuccessful) : base(copter)
{
this.IsSuccessful = isSuccessful;
}
public bool IsSuccessful { get; set; }
}
}

View File

@ -0,0 +1,17 @@
using Plane.Copters;
namespace Plane.Messaging
{
/// <summary>
/// 通过注册 <see cref="CopterPropertyChangedMessage"/> 来监视未关联到特定 Message 的属性。
/// </summary>
public class CopterPropertyChangedMessage : CopterMessageBase
{
public CopterPropertyChangedMessage(ICopter copter, string propertyName) : base(copter)
{
PropertyName = propertyName;
}
public string PropertyName { get; }
}
}

View File

@ -0,0 +1,12 @@
namespace Plane.Messaging
{
public class FlyToRequestAcceptedMessage
{
public FlyToRequestAcceptedMessage(RequestFlyToMessage request)
{
this.Request = request;
}
public RequestFlyToMessage Request { get; }
}
}

View File

@ -0,0 +1,36 @@
using System;
namespace Plane.Messaging
{
public interface IPLMessenger
{
/// <summary>
/// Registers a recipient for a type of message TMessage. The action
/// parameter will be executed when a corresponding message is sent.
/// <para>Registering a recipient does not create a hard reference to it,
/// so if this recipient is deleted, no memory leak is caused.</para>
/// </summary>
/// <typeparam name="TMessage">The type of message that the recipient registers
/// for.</typeparam>
/// <param name="recipient">The recipient that will receive the messages.</param>
/// <param name="action">The action that will be executed when a message
/// of type TMessage is sent.</param>
void Register<TMessage>(object recipient, Action<TMessage> action);
/// <summary>
/// Sends a message to registered recipients. The message will
/// reach all recipients that registered for this message type
/// using one of the Register methods.
/// </summary>
/// <typeparam name="TMessage">The type of message that will be sent.</typeparam>
/// <param name="message">The message to send to registered recipients.</param>
void Send<TMessage>(TMessage message);
/// <summary>
/// Unregisters a messager recipient completely. After this method
/// is executed, the recipient will not receive any messages anymore.
/// </summary>
/// <param name="recipient">The recipient that must be unregistered.</param>
void Unregister(object recipient);
}
}

View File

@ -0,0 +1,12 @@
namespace Plane.Messaging
{
public class LandingStateAcceptsAvatarChangedMessage
{
public LandingStateAcceptsAvatarChangedMessage(bool landingStateAcceptsAvatar)
{
LandingStateAcceptsAvatar = landingStateAcceptsAvatar;
}
public bool LandingStateAcceptsAvatar { get; }
}
}

View File

@ -0,0 +1,15 @@
namespace Plane.Messaging
{
public class RequestFlyToMessage
{
public RequestFlyToMessage(double lat, double lng)
{
Latitude = lat;
Longitude = lng;
}
public double Latitude { get; set; }
public double Longitude { get; set; }
}
}

View File

@ -0,0 +1,27 @@
namespace Plane.Messaging
{
public class RequestUpdateAttitudeMessage
{
public RequestUpdateAttitudeMessage(float rollDegrees, float pitchDegrees, float? yawDegrees)
{
this.RollDegrees = rollDegrees;
this.PitchDegrees = pitchDegrees;
this.YawDegrees = yawDegrees;
}
/// <summary>
/// 获取绕 X 轴的旋转(以度为单位)。
/// </summary>
public float PitchDegrees { get; }
/// <summary>
/// 获取绕 Y 轴的旋转(以度为单位)。
/// </summary>
public float RollDegrees { get; }
/// <summary>
/// 获取绕 Z 轴的旋转(以度为单位,正北 0正东 90范围为 [0, 360))。
/// </summary>
public float? YawDegrees { get; }
}
}

View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
<HasSharedItems>true</HasSharedItems>
<SharedGUID>695733d7-99ff-4707-8c89-474e949cadcb</SharedGUID>
</PropertyGroup>
<PropertyGroup Label="Configuration">
<Import_RootNamespace>Plane</Import_RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)Communication\ConnectionEstablishedEventArgs.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Communication\ExceptionThrownEventArgs.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Communication\IConnection.cs" />
<Compile Include="$(MSBuildThisFileDirectory)CopterControllers\CopterControllerTypes.cs" />
<Compile Include="$(MSBuildThisFileDirectory)CopterControllers\ICopterController.cs" />
<Compile Include="$(MSBuildThisFileDirectory)CopterControllers\ICopterControllerManager.cs" />
<Compile Include="$(MSBuildThisFileDirectory)CopterControllers\SpeedType.cs" />
<Compile Include="$(MSBuildThisFileDirectory)CopterManagement\ICopterFactory.cs" />
<Compile Include="$(MSBuildThisFileDirectory)CopterManagement\ICopterManager.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Copters\Constants.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Copters\CopterCommand.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Copters\CopterState.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Copters\PLObservableObject.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Copters\FlightCommand.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Copters\GpsFixType.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Copters\HeartbeatReceivedEventArgs.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Copters\IAttitude.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Copters\ICopter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Copters\ICopterActions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Copters\ICopterActionsSharedByCopterManager.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Copters\ICopterCommunication.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Copters\ICopterEvents.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Copters\ICopterMissionActions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Copters\ICopterStatus.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Copters\IFakeCopter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Copters\IMission.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Copters\IVisibleStatus.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Copters\MessageCreatedEventArgs.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Copters\MissionItemReceivedEventArgs.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Copters\PairingCompletedEventArgs.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Copters\SystemStatusReceivedEventArgs.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Copters\VisibleStatus.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Geography\PLLocation.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Geography\GeographyUtils.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Geography\ILocation.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Geography\ILocation2D.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Geography\LocationExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)MathExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Messaging\CopterAltitudeChangedMessage.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Messaging\CopterAttitudeChangedMessage.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Messaging\CopterConnectedMessage.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Messaging\CopterHeartbeatReceivedMessage.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Messaging\CopterLocationChangedMessage.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Messaging\CopterMessageBase.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Messaging\CopterPairingCompletedMessage.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Messaging\CopterPropertyChangedMessage.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Messaging\FlyToRequestAcceptedMessage.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Messaging\IPLMessenger.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Messaging\LandingStateAcceptsAvatarChangedMessage.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Messaging\RequestFlyToMessage.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Messaging\RequestUpdateAttitudeMessage.cs" />
<Compile Include="$(MSBuildThisFileDirectory)SynchronizationContextExtensions.cs" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<ProjectGuid>695733d7-99ff-4707-8c89-474e949cadcb</ProjectGuid>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
<PropertyGroup />
<Import Project="PlaneGcsSdk.Contract_Shared.projitems" Label="Shared" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
</Project>

View File

@ -0,0 +1,32 @@
using System;
using System.Threading;
namespace Plane
{
public static class SynchronizationContextExtensions
{
public static void Post(this SynchronizationContext syncContext, Action action)
{
if (SynchronizationContext.Current == syncContext)
{
action();
}
else
{
syncContext.Post(state => action(), null);
}
}
public static void Send(this SynchronizationContext syncContext, Action action)
{
if (SynchronizationContext.Current == syncContext)
{
action();
}
else
{
syncContext.Send(state => action(), null);
}
}
}
}

View File

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{331C28E1-5BA3-42CE-8A4A-BC468E692FED}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Plane</RootNamespace>
<AssemblyName>PlaneGcsSdk_NET46</AssemblyName>
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>bin\Release\PlaneGcsSdk_NET46.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PlaneGcsSdk.Contract\PlaneGcsSdk.Contract.csproj">
<Project>{18ecd88e-5d74-43e8-8bc2-d28f6db13a47}</Project>
<Name>PlaneGcsSdk.Contract</Name>
</ProjectReference>
</ItemGroup>
<Import Project="..\PlaneGcsSdk_Shared\PlaneGcsSdk_Shared.projitems" Label="Shared" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("PlaneGcsSdk_NET46")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Plane, Inc.")]
[assembly: AssemblyProduct("PlaneGcsSdk_NET46")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
//将 ComVisible 设置为 false 将使此程序集中的类型
//对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("331c28e1-5ba3-42ce-8a4a-bc468e692fed")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
// 方法是按如下所示使用“*”: :
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,13 @@
using System;
using System.Threading.Tasks;
namespace Plane.Copters
{
public abstract partial class CopterImplSharedPart : PLObservableObject
{
public Task CircleAsync()
{
return SetModeAsync(FlightMode.CIRCLE);
}
}
}

View File

@ -0,0 +1,18 @@
using System;
using System.Threading.Tasks;
namespace Plane.Copters
{
public partial class FakeCopter
{
/// <summary>
/// // 林俊清, 20160122, 不明确。目测是发送重启命令,在刷固件之前用到。
/// </summary>
/// <param name="bootloaderMode"></param>
/// <returns>表示此命令异步发送操作的 <see cref="Task"/> 实例。</returns>
public Task RebootAsync(bool bootloaderMode = false)
{
throw new NotImplementedException();
}
}
}

View File

@ -0,0 +1,22 @@
using System.Threading.Tasks;
namespace Plane.Copters
{
public partial class PLCopter
{
/// <summary>
/// 暴露内部的 <see cref="PlaneCopter"/> 实例。
/// </summary>
public PlaneCopter InternalCopter { get { return _internalCopter; } }
/// <summary>
/// // 林俊清, 20160122, 不明确。目测是发送重启命令,在刷固件之前用到。
/// </summary>
/// <param name="bootloaderMode"></param>
/// <returns>表示此命令异步发送操作的 <see cref="Task"/> 实例。</returns>
public Task RebootAsync(bool bootloaderMode = false)
{
return _internalCopter.RebootAsync(bootloaderMode);
}
}
}

Some files were not shown because too many files have changed in this diff Show More