├── .editorconfig
├── .gitattributes
├── .github
└── workflows
│ └── validate-openapi.yml
├── .gitignore
├── .redocly.lint-ignore.yaml
├── ASCOM Remote.sln
├── BuildRemote.cmd
├── Documentation
├── ASCOM Alpaca API Reference.docx
├── ASCOM Alpaca API Reference.pdf
├── ASCOM Distributed Architecture.docx
├── ASCOM Distributed Architecture.pdf
├── ASCOM Remote Installation and Configuration.docx
├── ASCOM Remote Installation and Configuration.pdf
├── ASCOM Remote.vsdx
├── Alpaca Introduction.docx
├── Alpaca Introduction.pdf
├── AlpacaImageBytes.docx
├── AlpacaImageBytes.pdf
└── ImageBytesDiagrams.vsdx
├── LICENSE
├── NuGet.config
├── README.md
├── Remote Server Key.snk
├── Remote Server
├── ASCOM.ico
├── ASCOMAlpacaMidRes.jpg
├── AlpacaConfiguredDevice.cs
├── AlpacaDeviceDescription.cs
├── App.config
├── Configuration.cs
├── ConfigurationManager.cs
├── ConfiguredDevice.cs
├── DriverHostForm.Designer.cs
├── DriverHostForm.cs
├── DriverHostForm.resx
├── Entity Classes
│ └── ActiveObject.cs
├── ExtensionMethods.cs
├── HideTabControlBorders.cs
├── HostPc.cs
├── InvalidParameterException.cs
├── ProfileDevice.cs
├── Program.cs
├── Remote Server.csproj
├── RequestData.cs
├── ResponseClasses
│ ├── AlpacaConfiguredDevicesResponse.cs
│ ├── AlpacaDescriptionResponse.cs
│ ├── AlpacaDiscoveryResponse.cs
│ ├── AxisRatesResponse.cs
│ ├── Base64ArrayHandOffResponse.cs
│ ├── Base64ArrayJsonResponse.cs
│ ├── BoolResponse.cs
│ ├── ConfigurationResponse.cs
│ ├── DateAndTimeResponse.cs
│ ├── DoubleArray2DResponse.cs
│ ├── DoubleArray3DResponse.cs
│ ├── DoubleResponse.cs
│ ├── ImageArrayResponseBase.cs
│ ├── IntArray1DResponse.cs
│ ├── IntArray2DResponse.cs
│ ├── IntArray3DResponse.cs
│ ├── IntResponse.cs
│ ├── MethodResponse.cs
│ ├── ProfileResponse.cs
│ ├── RateResponse.cs
│ ├── RestResponseBase.cs
│ ├── ShortArray2DResponse.cs
│ ├── ShortArray3DResponse.cs
│ ├── ShortResponse.cs
│ ├── StringArrayResponse.cs
│ ├── StringListResponse.cs
│ ├── StringResponse.cs
│ └── TrackingRatesResponse.cs
├── ServedDevice.cs
├── ServerForm.Designer.cs
├── ServerForm.cs
├── ServerForm.resx
├── Settings.cs
├── SetupForm.Designer.cs
├── SetupForm.cs
├── SetupForm.resx
├── Shared Constants.cs
├── SharedResources.cs
├── StringValue.cs
├── TraceLoggerPlus.cs
├── Updates
│ ├── GitHubReleases.cs
│ └── Updates.cs
├── WindowsErrorCodes.cs
├── ascomicon.ico
├── servedDevice.Designer.cs
└── servedDevice.resx
├── SetNetworkPermissions
├── ASCOM.ico
├── Options.cs
├── Program.cs
├── SetNetworkPermissions.csproj
├── app.config
└── app.manifest
├── Setup
├── ASCOM Remote Setup.iss
├── ASCOM.ico
├── ASCOMLogo.bmp
└── NewWizardImage.bmp
├── SignASCOMRemote.cmd
├── Swagger
├── AlpacaDeviceAPI_v1.yaml
├── AlpacaDeviceAPI_v1P7.yaml
├── AlpacaManagementAPI_v1.yaml
├── bugt300square.jpg
├── favicon-16x16.png
├── favicon-32x32.png
├── index.html
├── oauth2-redirect.html
└── redoclyconfig.yaml
└── redocly.yaml
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.cs]
2 |
3 | # VSSpell001: Spell Check
4 | dotnet_diagnostic.VSSpell001.severity = none
5 | csharp_using_directive_placement = outside_namespace:silent
6 | csharp_prefer_simple_using_statement = true:suggestion
7 | csharp_prefer_braces = true:silent
8 | csharp_style_namespace_declarations = block_scoped:silent
9 | csharp_style_prefer_method_group_conversion = true:silent
10 | csharp_style_prefer_top_level_statements = true:silent
11 | csharp_style_expression_bodied_methods = false:silent
12 | csharp_style_expression_bodied_constructors = false:silent
13 | csharp_style_expression_bodied_operators = false:silent
14 | csharp_style_expression_bodied_properties = true:silent
15 | csharp_style_expression_bodied_indexers = true:silent
16 | csharp_style_expression_bodied_accessors = true:silent
17 | csharp_style_expression_bodied_lambdas = true:silent
18 | csharp_style_expression_bodied_local_functions = false:silent
19 | csharp_style_throw_expression = true:suggestion
20 | csharp_style_prefer_null_check_over_type_check = true:suggestion
21 | csharp_prefer_simple_default_expression = true:suggestion
22 | csharp_style_prefer_local_over_anonymous_function = true:suggestion
23 | csharp_style_prefer_index_operator = true:suggestion
24 | csharp_style_prefer_range_operator = true:suggestion
25 | csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion
26 | csharp_style_prefer_tuple_swap = true:suggestion
27 | csharp_style_prefer_utf8_string_literals = true:suggestion
28 | csharp_style_inlined_variable_declaration = true:suggestion
29 | csharp_style_deconstructed_variable_declaration = true:suggestion
30 | csharp_style_unused_value_assignment_preference = unused_local_variable:suggestion
31 | csharp_style_unused_value_expression_statement_preference = unused_local_variable:silent
32 | csharp_indent_labels = one_less_than_current
33 | csharp_space_around_binary_operators = before_and_after
34 |
35 | [*.{cs,vb}]
36 | #### Naming styles ####
37 |
38 | # Naming rules
39 |
40 | dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
41 | dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
42 | dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
43 |
44 | dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
45 | dotnet_naming_rule.types_should_be_pascal_case.symbols = types
46 | dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
47 |
48 | dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
49 | dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
50 | dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
51 |
52 | # Symbol specifications
53 |
54 | dotnet_naming_symbols.interface.applicable_kinds = interface
55 | dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
56 | dotnet_naming_symbols.interface.required_modifiers =
57 |
58 | dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
59 | dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
60 | dotnet_naming_symbols.types.required_modifiers =
61 |
62 | dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
63 | dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
64 | dotnet_naming_symbols.non_field_members.required_modifiers =
65 |
66 | # Naming styles
67 |
68 | dotnet_naming_style.begins_with_i.required_prefix = I
69 | dotnet_naming_style.begins_with_i.required_suffix =
70 | dotnet_naming_style.begins_with_i.word_separator =
71 | dotnet_naming_style.begins_with_i.capitalization = pascal_case
72 |
73 | dotnet_naming_style.pascal_case.required_prefix =
74 | dotnet_naming_style.pascal_case.required_suffix =
75 | dotnet_naming_style.pascal_case.word_separator =
76 | dotnet_naming_style.pascal_case.capitalization = pascal_case
77 |
78 | dotnet_naming_style.pascal_case.required_prefix =
79 | dotnet_naming_style.pascal_case.required_suffix =
80 | dotnet_naming_style.pascal_case.word_separator =
81 | dotnet_naming_style.pascal_case.capitalization = pascal_case
82 | dotnet_style_coalesce_expression = true:suggestion
83 | dotnet_style_null_propagation = true:suggestion
84 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
85 | dotnet_style_prefer_auto_properties = true:silent
86 | dotnet_style_object_initializer = true:suggestion
87 | dotnet_style_collection_initializer = true:suggestion
88 | dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
89 | dotnet_style_prefer_conditional_expression_over_assignment = true:silent
90 | dotnet_style_prefer_conditional_expression_over_return = true:silent
91 | dotnet_style_explicit_tuple_names = true:suggestion
92 | dotnet_style_prefer_inferred_tuple_names = true:suggestion
93 | dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
94 | dotnet_style_prefer_compound_assignment = true:suggestion
95 | dotnet_style_prefer_simplified_interpolation = true:suggestion
96 | dotnet_style_namespace_match_folder = true:suggestion
97 | dotnet_style_readonly_field = true:suggestion
98 | dotnet_style_predefined_type_for_locals_parameters_members = true:silent
99 | dotnet_style_predefined_type_for_member_access = true:silent
100 | dotnet_style_operator_placement_when_wrapping = beginning_of_line
101 | tab_width = 4
102 | indent_size = 4
103 | end_of_line = crlf
104 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Tell Git Linguist to ignore Swagger content files when deciding what language
3 | # is used in the repository
4 | ###############################################################################
5 | Swagger/** linguist-documentation=true
6 |
--------------------------------------------------------------------------------
/.github/workflows/validate-openapi.yml:
--------------------------------------------------------------------------------
1 | on: [push]
2 |
3 | jobs:
4 | validate_openapi:
5 | runs-on: ubuntu-latest
6 | name: Validate OpenAPI definitions
7 | steps:
8 | - uses: actions/checkout@v4
9 | - name: Install OpenAPI validator
10 | run: npm install -g @redocly/cli
11 | - name: Validate Managment API
12 | run: redocly lint --config Swagger/redoclyconfig.yaml Swagger/AlpacaManagementAPI_v1.yaml
13 | - name: Validate Alpaca Device API
14 | run: redocly lint --config Swagger/redoclyconfig.yaml Swagger/AlpacaDeviceAPI_v1.yaml
15 | env:
16 | NODE_NO_WARNINGS: 1
17 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # MSTest test Results
33 | [Tt]est[Rr]esult*/
34 | [Bb]uild[Ll]og.*
35 |
36 | # NUNIT
37 | *.VisualState.xml
38 | TestResult.xml
39 |
40 | # Build Results of an ATL Project
41 | [Dd]ebugPS/
42 | [Rr]eleasePS/
43 | dlldata.c
44 |
45 | # .NET Core
46 | project.lock.json
47 | project.fragment.lock.json
48 | artifacts/
49 | **/Properties/launchSettings.json
50 |
51 | *_i.c
52 | *_p.c
53 | *_i.h
54 | *.ilk
55 | *.meta
56 | *.obj
57 | *.pch
58 | *.pdb
59 | *.pgc
60 | *.pgd
61 | *.rsp
62 | *.sbr
63 | *.tlb
64 | *.tli
65 | *.tlh
66 | *.tmp
67 | *.tmp_proj
68 | *.log
69 | *.vspscc
70 | *.vssscc
71 | .builds
72 | *.pidb
73 | *.svclog
74 | *.scc
75 |
76 | # Chutzpah Test files
77 | _Chutzpah*
78 |
79 | # Visual C++ cache files
80 | ipch/
81 | *.aps
82 | *.ncb
83 | *.opendb
84 | *.opensdf
85 | *.sdf
86 | *.cachefile
87 | *.VC.db
88 | *.VC.VC.opendb
89 |
90 | # Visual Studio profiler
91 | *.psess
92 | *.vsp
93 | *.vspx
94 | *.sap
95 |
96 | # TFS 2012 Local Workspace
97 | $tf/
98 |
99 | # Guidance Automation Toolkit
100 | *.gpState
101 |
102 | # ReSharper is a .NET coding add-in
103 | _ReSharper*/
104 | *.[Rr]e[Ss]harper
105 | *.DotSettings.user
106 |
107 | # JustCode is a .NET coding add-in
108 | .JustCode
109 |
110 | # TeamCity is a build add-in
111 | _TeamCity*
112 |
113 | # DotCover is a Code Coverage Tool
114 | *.dotCover
115 |
116 | # Visual Studio code coverage results
117 | *.coverage
118 | *.coveragexml
119 |
120 | # NCrunch
121 | _NCrunch_*
122 | .*crunch*.local.xml
123 | nCrunchTemp_*
124 |
125 | # MightyMoose
126 | *.mm.*
127 | AutoTest.Net/
128 |
129 | # Web workbench (sass)
130 | .sass-cache/
131 |
132 | # Installshield output folder
133 | [Ee]xpress/
134 |
135 | # DocProject is a documentation generator add-in
136 | DocProject/buildhelp/
137 | DocProject/Help/*.HxT
138 | DocProject/Help/*.HxC
139 | DocProject/Help/*.hhc
140 | DocProject/Help/*.hhk
141 | DocProject/Help/*.hhp
142 | DocProject/Help/Html2
143 | DocProject/Help/html
144 |
145 | # Click-Once directory
146 | publish/
147 |
148 | # Publish Web Output
149 | *.[Pp]ublish.xml
150 | *.azurePubxml
151 | # TODO: Comment the next line if you want to checkin your web deploy settings
152 | # but database connection strings (with potential passwords) will be unencrypted
153 | *.pubxml
154 | *.publishproj
155 |
156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
157 | # checkin your Azure Web App publish settings, but sensitive information contained
158 | # in these scripts will be unencrypted
159 | PublishScripts/
160 |
161 | # NuGet Packages
162 | *.nupkg
163 | # The packages folder can be ignored because of Package Restore
164 | **/packages/*
165 | # except build/, which is used as an MSBuild target.
166 | !**/packages/build/
167 | # Uncomment if necessary however generally it will be regenerated when needed
168 | #!**/packages/repositories.config
169 | # NuGet v3's project.json files produces more ignorable files
170 | *.nuget.props
171 | *.nuget.targets
172 |
173 | # Microsoft Azure Build Output
174 | csx/
175 | *.build.csdef
176 |
177 | # Microsoft Azure Emulator
178 | ecf/
179 | rcf/
180 |
181 | # Windows Store app package directories and files
182 | AppPackages/
183 | BundleArtifacts/
184 | Package.StoreAssociation.xml
185 | _pkginfo.txt
186 |
187 | # Visual Studio cache files
188 | # files ending in .cache can be ignored
189 | *.[Cc]ache
190 | # but keep track of directories ending in .cache
191 | !*.[Cc]ache/
192 |
193 | # Others
194 | ClientBin/
195 | ~$*
196 | *~
197 | *.dbmdl
198 | *.dbproj.schemaview
199 | *.jfm
200 | *.pfx
201 | *.publishsettings
202 | orleans.codegen.cs
203 |
204 | # Since there are multiple workflows, uncomment next line to ignore bower_components
205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
206 | #bower_components/
207 |
208 | # RIA/Silverlight projects
209 | Generated_Code/
210 |
211 | # Backup & report files from converting an old project file
212 | # to a newer Visual Studio version. Backup files are not needed,
213 | # because we have git ;-)
214 | _UpgradeReport_Files/
215 | Backup*/
216 | UpgradeLog*.XML
217 | UpgradeLog*.htm
218 |
219 | # SQL Server files
220 | *.mdf
221 | *.ldf
222 | *.ndf
223 |
224 | # Business Intelligence projects
225 | *.rdl.data
226 | *.bim.layout
227 | *.bim_*.settings
228 |
229 | # Microsoft Fakes
230 | FakesAssemblies/
231 |
232 | # GhostDoc plugin setting file
233 | *.GhostDoc.xml
234 |
235 | # Node.js Tools for Visual Studio
236 | .ntvs_analysis.dat
237 | node_modules/
238 |
239 | # Typescript v1 declaration files
240 | typings/
241 |
242 | # Visual Studio 6 build log
243 | *.plg
244 |
245 | # Visual Studio 6 workspace options file
246 | *.opt
247 |
248 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
249 | *.vbw
250 |
251 | # Visual Studio LightSwitch build output
252 | **/*.HTMLClient/GeneratedArtifacts
253 | **/*.DesktopClient/GeneratedArtifacts
254 | **/*.DesktopClient/ModelManifest.xml
255 | **/*.Server/GeneratedArtifacts
256 | **/*.Server/ModelManifest.xml
257 | _Pvt_Extensions
258 |
259 | # Paket dependency manager
260 | .paket/paket.exe
261 | paket-files/
262 |
263 | # FAKE - F# Make
264 | .fake/
265 |
266 | # JetBrains Rider
267 | .idea/
268 | *.sln.iml
269 |
270 | # CodeRush
271 | .cr/
272 |
273 | # Python Tools for Visual Studio (PTVS)
274 | __pycache__/
275 | *.pyc
276 |
277 | # Cake - Uncomment if you are using it
278 | # tools/**
279 | # !tools/packages.config
280 |
281 | # Telerik's JustMock configuration file
282 | *.jmconfig
283 |
284 | # BizTalk build output
285 | *.btp.cs
286 | *.btm.cs
287 | *.odx.cs
288 | *.xsd.cs
289 | Build
290 | /Swagger/AlpacaDeviceAPI_v1.yaml.org2
291 |
--------------------------------------------------------------------------------
/.redocly.lint-ignore.yaml:
--------------------------------------------------------------------------------
1 | # This file instructs Redocly's linter to ignore the rules contained for specific parts of your API.
2 | # See https://redoc.ly/docs/cli/ for more information.
3 | Swagger/AlpacaManagementAPI_v1.yaml:
4 | # /setup endpoint must always be present
5 | operation-4xx-response:
6 | - '#/paths/~1setup/get/responses'
7 |
--------------------------------------------------------------------------------
/ASCOM Remote.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.5.33627.172
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SetNetworkPermissions", "SetNetworkPermissions\SetNetworkPermissions.csproj", "{FF57CAEA-63F3-4F4F-9252-734796B74731}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Remote Server", "Remote Server\Remote Server.csproj", "{15D5962B-2A5E-4B07-98B6-D4D4A888F9B7}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{0B2836E8-6FC8-4616-8E83-CBCEB4E01784}"
11 | ProjectSection(SolutionItems) = preProject
12 | .editorconfig = .editorconfig
13 | NuGet.config = NuGet.config
14 | Remote Server Key.snk = Remote Server Key.snk
15 | EndProjectSection
16 | EndProject
17 | Global
18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
19 | Debug|Any CPU = Debug|Any CPU
20 | Debug|x64 = Debug|x64
21 | Debug|x86 = Debug|x86
22 | Release|Any CPU = Release|Any CPU
23 | Release|x64 = Release|x64
24 | Release|x86 = Release|x86
25 | EndGlobalSection
26 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
27 | {FF57CAEA-63F3-4F4F-9252-734796B74731}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
28 | {FF57CAEA-63F3-4F4F-9252-734796B74731}.Debug|Any CPU.Build.0 = Debug|Any CPU
29 | {FF57CAEA-63F3-4F4F-9252-734796B74731}.Debug|x64.ActiveCfg = Debug|x64
30 | {FF57CAEA-63F3-4F4F-9252-734796B74731}.Debug|x64.Build.0 = Debug|x64
31 | {FF57CAEA-63F3-4F4F-9252-734796B74731}.Debug|x86.ActiveCfg = Debug|x86
32 | {FF57CAEA-63F3-4F4F-9252-734796B74731}.Debug|x86.Build.0 = Debug|x86
33 | {FF57CAEA-63F3-4F4F-9252-734796B74731}.Release|Any CPU.ActiveCfg = Release|Any CPU
34 | {FF57CAEA-63F3-4F4F-9252-734796B74731}.Release|Any CPU.Build.0 = Release|Any CPU
35 | {FF57CAEA-63F3-4F4F-9252-734796B74731}.Release|x64.ActiveCfg = Release|x64
36 | {FF57CAEA-63F3-4F4F-9252-734796B74731}.Release|x64.Build.0 = Release|x64
37 | {FF57CAEA-63F3-4F4F-9252-734796B74731}.Release|x86.ActiveCfg = Release|x86
38 | {FF57CAEA-63F3-4F4F-9252-734796B74731}.Release|x86.Build.0 = Release|x86
39 | {15D5962B-2A5E-4B07-98B6-D4D4A888F9B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
40 | {15D5962B-2A5E-4B07-98B6-D4D4A888F9B7}.Debug|Any CPU.Build.0 = Debug|Any CPU
41 | {15D5962B-2A5E-4B07-98B6-D4D4A888F9B7}.Debug|x64.ActiveCfg = Debug|x64
42 | {15D5962B-2A5E-4B07-98B6-D4D4A888F9B7}.Debug|x64.Build.0 = Debug|x64
43 | {15D5962B-2A5E-4B07-98B6-D4D4A888F9B7}.Debug|x86.ActiveCfg = Debug|x86
44 | {15D5962B-2A5E-4B07-98B6-D4D4A888F9B7}.Debug|x86.Build.0 = Debug|x86
45 | {15D5962B-2A5E-4B07-98B6-D4D4A888F9B7}.Release|Any CPU.ActiveCfg = Release|Any CPU
46 | {15D5962B-2A5E-4B07-98B6-D4D4A888F9B7}.Release|Any CPU.Build.0 = Release|Any CPU
47 | {15D5962B-2A5E-4B07-98B6-D4D4A888F9B7}.Release|x64.ActiveCfg = Release|x64
48 | {15D5962B-2A5E-4B07-98B6-D4D4A888F9B7}.Release|x64.Build.0 = Release|x64
49 | {15D5962B-2A5E-4B07-98B6-D4D4A888F9B7}.Release|x86.ActiveCfg = Release|x86
50 | {15D5962B-2A5E-4B07-98B6-D4D4A888F9B7}.Release|x86.Build.0 = Release|x86
51 | EndGlobalSection
52 | GlobalSection(SolutionProperties) = preSolution
53 | HideSolutionNode = FALSE
54 | EndGlobalSection
55 | GlobalSection(ExtensibilityGlobals) = postSolution
56 | SolutionGuid = {171EDC5A-81C8-4545-BB43-723B4AE9B622}
57 | EndGlobalSection
58 | EndGlobal
59 |
--------------------------------------------------------------------------------
/BuildRemote.cmd:
--------------------------------------------------------------------------------
1 | @echo on
2 | @echo Setting up variables
3 | call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x86
4 | @echo Selecting Remote directory
5 |
6 | SET RemoteDirectory=%cd%
7 | @echo Current directory: %RemoteDirectory%
8 |
9 | @echo Restoring packages
10 | msbuild /t:restore /p:configuration=Debug;Platform="Any CPU"
11 |
12 | @echo Building Debug AnyCPU in directory %cd%
13 | msbuild /t:rebuild /p:configuration=Debug;Platform="Any CPU"
14 |
15 | cd %RemoteDirectory%
16 | @echo Building Release AnyCPU in directory %cd%
17 | msbuild /t:rebuild /p:configuration=Release;Platform="Any CPU"
18 |
19 | cd %RemoteDirectory%
20 | rmdir /s /q "publish"
21 | @echo Publishing ASCOM Remote x86
22 | dotnet publish "remote server\remote server.csproj" --runtime win-x86 --self-contained -p:Configuration=Debug -p:Platform="x86" -p:publishsinglefile=true -o publish\remote\x86\
23 |
24 | @echo Publishing ASCOM Remote x64
25 | dotnet publish "remote server\remote server.csproj" --runtime win-x64 --self-contained -p:Configuration=Debug -p:Platform="Any CPU" -p:publishsinglefile=true -o publish\remote\x64\
26 |
27 | @echo Publishing Set Network Permissions x86
28 | dotnet publish "SetNetworkPermissions\SetNetworkPermissions.csproj" --runtime win-x86 --self-contained -p:Configuration=Debug -p:Platform="x86" -p:publishsinglefile=true -o publish\permissions\x86\
29 |
30 | rem @echo Publishing Set Network Permissions x64
31 | rem dotnet publish "SetNetworkPermissions\SetNetworkPermissions.csproj" --runtime win-x64 --self-contained -p:Configuration=Debug -p:Platform="Any CPU" -p:publishsinglefile=true -o publish\permissions\x64\
32 |
33 | rem @echo Publishing ASCOM Remote x86 - Needs Support Library
34 | rem dotnet publish "remote server\remote server.csproj" --runtime win-x86 -p:Configuration=Debug --self-contained false -p:Platform="x86" -p:publishsinglefile=true -o publish\x86NeedsCoreInstall\
35 | rem @echo Publishing ASCOM Remote x64 - Needs Support Library
36 | rem dotnet publish "remote server\remote server.csproj" --runtime win-x64 -p:Configuration=Debug --self-contained false -p:Platform="Any CPU" -p:publishsinglefile=true -o publish\x64NeedsCoreInstall\
37 |
38 | @echo *** Creating Windows installer
39 | cd Setup
40 | "C:\Program Files (x86)\Inno Script Studio\isstudio.exe" -compile "ASCOM Remote Setup.iss"
41 | cd ..
42 | @echo *** Finsihed!
43 | pause
--------------------------------------------------------------------------------
/Documentation/ASCOM Alpaca API Reference.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ASCOMInitiative/ASCOMRemote/e4d60019d54692a0dafd788895d1dde6a778a28e/Documentation/ASCOM Alpaca API Reference.docx
--------------------------------------------------------------------------------
/Documentation/ASCOM Alpaca API Reference.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ASCOMInitiative/ASCOMRemote/e4d60019d54692a0dafd788895d1dde6a778a28e/Documentation/ASCOM Alpaca API Reference.pdf
--------------------------------------------------------------------------------
/Documentation/ASCOM Distributed Architecture.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ASCOMInitiative/ASCOMRemote/e4d60019d54692a0dafd788895d1dde6a778a28e/Documentation/ASCOM Distributed Architecture.docx
--------------------------------------------------------------------------------
/Documentation/ASCOM Distributed Architecture.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ASCOMInitiative/ASCOMRemote/e4d60019d54692a0dafd788895d1dde6a778a28e/Documentation/ASCOM Distributed Architecture.pdf
--------------------------------------------------------------------------------
/Documentation/ASCOM Remote Installation and Configuration.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ASCOMInitiative/ASCOMRemote/e4d60019d54692a0dafd788895d1dde6a778a28e/Documentation/ASCOM Remote Installation and Configuration.docx
--------------------------------------------------------------------------------
/Documentation/ASCOM Remote Installation and Configuration.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ASCOMInitiative/ASCOMRemote/e4d60019d54692a0dafd788895d1dde6a778a28e/Documentation/ASCOM Remote Installation and Configuration.pdf
--------------------------------------------------------------------------------
/Documentation/ASCOM Remote.vsdx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ASCOMInitiative/ASCOMRemote/e4d60019d54692a0dafd788895d1dde6a778a28e/Documentation/ASCOM Remote.vsdx
--------------------------------------------------------------------------------
/Documentation/Alpaca Introduction.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ASCOMInitiative/ASCOMRemote/e4d60019d54692a0dafd788895d1dde6a778a28e/Documentation/Alpaca Introduction.docx
--------------------------------------------------------------------------------
/Documentation/Alpaca Introduction.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ASCOMInitiative/ASCOMRemote/e4d60019d54692a0dafd788895d1dde6a778a28e/Documentation/Alpaca Introduction.pdf
--------------------------------------------------------------------------------
/Documentation/AlpacaImageBytes.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ASCOMInitiative/ASCOMRemote/e4d60019d54692a0dafd788895d1dde6a778a28e/Documentation/AlpacaImageBytes.docx
--------------------------------------------------------------------------------
/Documentation/AlpacaImageBytes.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ASCOMInitiative/ASCOMRemote/e4d60019d54692a0dafd788895d1dde6a778a28e/Documentation/AlpacaImageBytes.pdf
--------------------------------------------------------------------------------
/Documentation/ImageBytesDiagrams.vsdx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ASCOMInitiative/ASCOMRemote/e4d60019d54692a0dafd788895d1dde6a778a28e/Documentation/ImageBytesDiagrams.vsdx
--------------------------------------------------------------------------------
/NuGet.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ASCOMRemote
2 | The ASCOM REST based Remote Driver Server and Remote Access Clients
3 |
4 | Contains the definition of the ASCOM REST device interfaces together with device drivers that can present remote network based drivers,
5 | connected through TCP/IP as local devices.access remote
--------------------------------------------------------------------------------
/Remote Server Key.snk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ASCOMInitiative/ASCOMRemote/e4d60019d54692a0dafd788895d1dde6a778a28e/Remote Server Key.snk
--------------------------------------------------------------------------------
/Remote Server/ASCOM.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ASCOMInitiative/ASCOMRemote/e4d60019d54692a0dafd788895d1dde6a778a28e/Remote Server/ASCOM.ico
--------------------------------------------------------------------------------
/Remote Server/ASCOMAlpacaMidRes.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ASCOMInitiative/ASCOMRemote/e4d60019d54692a0dafd788895d1dde6a778a28e/Remote Server/ASCOMAlpacaMidRes.jpg
--------------------------------------------------------------------------------
/Remote Server/AlpacaConfiguredDevice.cs:
--------------------------------------------------------------------------------
1 | namespace ASCOM.Remote
2 | {
3 | public class AlpacaConfiguredDevice
4 | {
5 | public AlpacaConfiguredDevice() { }
6 |
7 | public AlpacaConfiguredDevice(string deviceName,string deviceType,int deviceNumber,string uniqueID)
8 | {
9 | DeviceName = deviceName;
10 | DeviceType = deviceType;
11 | DeviceNumber = deviceNumber;
12 | UniqueID = uniqueID;
13 | }
14 |
15 | public string DeviceName { get; set; }
16 | public string DeviceType { get; set; }
17 | public int DeviceNumber { get; set; }
18 | public string UniqueID { get; set; }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Remote Server/AlpacaDeviceDescription.cs:
--------------------------------------------------------------------------------
1 | namespace ASCOM.Remote
2 | {
3 | public class AlpacaDeviceDescription
4 | {
5 | public AlpacaDeviceDescription() { }
6 |
7 | public AlpacaDeviceDescription(string serverName, string manufacturer, string manufacturerVersion, string location)
8 | {
9 | ServerName = serverName;
10 | Manufacturer = manufacturer;
11 | ManufacturerVersion = manufacturerVersion;
12 | Location = location;
13 | }
14 |
15 | public string ServerName { get; set; } = "";
16 | public string Manufacturer { get; set; } = "";
17 | public string ManufacturerVersion { get; set; } = "";
18 | public string Location { get; set; } = "";
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Remote Server/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Remote Server/Configuration.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using Microsoft.Win32;
4 |
5 | namespace ASCOM.Remote
6 | {
7 | class Configuration : IDisposable
8 | {
9 | private readonly bool LOG_CONFIGURATION_CALLS = false; // Stored as a variable rather than a const to avoid compiler warnings about unreachable code
10 |
11 | private readonly RegistryKey hiveKey, baseRegistryKey;
12 |
13 | public static void Reset()
14 | {
15 | try
16 | {
17 | RegistryKey hiveKey = RegistryKey.OpenBaseKey(SharedConstants.ASCOM_REMOTE_CONFIGURATION_HIVE, RegistryView.Default);
18 | hiveKey.DeleteSubKeyTree(SharedConstants.ASCOM_REMOTE_CONFIGURATION_KEY);
19 | }
20 | catch (Exception ex)
21 | {
22 | Console.WriteLine($"Exception reseting configuration:\r\n{ex}");
23 | }
24 | }
25 |
26 | public Configuration()
27 | {
28 | try
29 | {
30 | if (LOG_CONFIGURATION_CALLS) ServerForm.LogMessage(0, 0, 0, "Configuration New", "About to create base key");
31 | hiveKey = RegistryKey.OpenBaseKey(SharedConstants.ASCOM_REMOTE_CONFIGURATION_HIVE, RegistryView.Default);
32 | baseRegistryKey = hiveKey.CreateSubKey(SharedConstants.ASCOM_REMOTE_CONFIGURATION_KEY);
33 | if (LOG_CONFIGURATION_CALLS) ServerForm.LogMessage(0, 0, 0, "Configuration New", "Created base key: " + baseRegistryKey.Name);
34 | }
35 | catch (Exception ex)
36 | {
37 | ServerForm.LogException(0, 0, 0, "Configuration New", ex.ToString());
38 | }
39 | }
40 |
41 | public T GetValue(string KeyName, string SubKey, T DefaultValue)
42 | {
43 | if (LOG_CONFIGURATION_CALLS) ServerForm.LogMessage(0, 0, 0, "GetValue", $"Getting {typeof(T).Name} value '{KeyName}' in subkey '{SubKey}', default: '{DefaultValue}'");
44 |
45 | if (typeof(T) == typeof(bool))
46 | {
47 | string registryValue;
48 | if (SubKey == "")
49 | {
50 | if (LOG_CONFIGURATION_CALLS) ServerForm.LogMessage(0, 0, 0, "GetValue", "SubKey is empty so getting value directly");
51 | registryValue = (string)baseRegistryKey.GetValue(KeyName);
52 | if (LOG_CONFIGURATION_CALLS) ServerForm.LogMessage(0, 0, 0, "GetValue", "Value retrieved OK: " + registryValue);
53 | }
54 | else
55 | {
56 | if (LOG_CONFIGURATION_CALLS) ServerForm.LogMessage(0, 0, 0, "GetValue", "SubKey has a value so using it...");
57 | registryValue = (string)baseRegistryKey.CreateSubKey(SubKey).GetValue(KeyName);
58 | if (LOG_CONFIGURATION_CALLS) ServerForm.LogMessage(0, 0, 0, "GetValue", "Value retrieved OK: " + registryValue);
59 | }
60 |
61 | if (registryValue == null)
62 | {
63 | SetValueInvariant(KeyName, SubKey, DefaultValue);
64 | bool defaultValue = Convert.ToBoolean(DefaultValue);
65 | registryValue = defaultValue.ToString(CultureInfo.InvariantCulture);
66 | }
67 |
68 | bool RetVal = Convert.ToBoolean(registryValue, CultureInfo.InvariantCulture);
69 | if (LOG_CONFIGURATION_CALLS) ServerForm.LogMessage(0, 0, 0, "GetValue", $"Retrieved {KeyName} = {RetVal}");
70 | return (T)((object)RetVal);
71 | }
72 |
73 | if (typeof(T) == typeof(string))
74 | {
75 | string RetVal;
76 | if (SubKey == "")
77 | {
78 | if (LOG_CONFIGURATION_CALLS) ServerForm.LogMessage(0, 0, 0, "GetValue", "SubKey is empty so getting value directly");
79 | RetVal = (string)baseRegistryKey.GetValue(KeyName);
80 | if (LOG_CONFIGURATION_CALLS) ServerForm.LogMessage(0, 0, 0, "GetValue", "Value retrieved OK: " + RetVal);
81 | }
82 | else
83 | {
84 | if (LOG_CONFIGURATION_CALLS) ServerForm.LogMessage(0, 0, 0, "GetValue", "SubKey has a value so using it...");
85 | RetVal = (string)baseRegistryKey.CreateSubKey(SubKey).GetValue(KeyName);
86 | if (LOG_CONFIGURATION_CALLS) ServerForm.LogMessage(0, 0, 0, "GetValue", "Value retrieved OK: " + RetVal);
87 | }
88 |
89 | if (RetVal == null)
90 | {
91 | SetValue(KeyName, SubKey, DefaultValue);
92 | RetVal = DefaultValue.ToString();
93 | }
94 | if (LOG_CONFIGURATION_CALLS) ServerForm.LogMessage(0, 0, 0, "GetValue", $"Retrieved {KeyName} = {RetVal}");
95 | return (T)((object)RetVal);
96 | }
97 |
98 | if (typeof(T) == typeof(decimal))
99 | {
100 | string registryValue;
101 | if (SubKey == "")
102 | {
103 | if (LOG_CONFIGURATION_CALLS) ServerForm.LogMessage(0, 0, 0, "GetValue", "SubKey is empty so getting value directly");
104 | registryValue = (string)baseRegistryKey.GetValue(KeyName);
105 | if (LOG_CONFIGURATION_CALLS) ServerForm.LogMessage(0, 0, 0, "GetValue", "Value retrieved OK: " + registryValue);
106 | }
107 | else
108 | {
109 | if (LOG_CONFIGURATION_CALLS) ServerForm.LogMessage(0, 0, 0, "GetValue", "SubKey has a value so using it...");
110 | registryValue = (string)baseRegistryKey.CreateSubKey(SubKey).GetValue(KeyName);
111 | if (LOG_CONFIGURATION_CALLS) ServerForm.LogMessage(0, 0, 0, "GetValue", "Value retrieved OK: " + registryValue);
112 | }
113 |
114 | if (registryValue == null)
115 | {
116 | SetValueInvariant(KeyName, SubKey, DefaultValue);
117 | decimal defaultValue = Convert.ToDecimal(DefaultValue);
118 | registryValue = defaultValue.ToString(CultureInfo.InvariantCulture);
119 | }
120 |
121 | decimal RetVal = Convert.ToDecimal(registryValue, CultureInfo.InvariantCulture);
122 | if (LOG_CONFIGURATION_CALLS) ServerForm.LogMessage(0, 0, 0, "GetValue", $"Retrieved {KeyName} = {RetVal}");
123 | return (T)((object)RetVal);
124 | }
125 |
126 | if (typeof(T) == typeof(DateTime))
127 | {
128 | string registryValue;
129 | if (SubKey == "")
130 | {
131 | if (LOG_CONFIGURATION_CALLS) ServerForm.LogMessage(0, 0, 0, "GetValue", "SubKey is empty so getting value directly");
132 | registryValue = (string)baseRegistryKey.GetValue(KeyName);
133 | if (LOG_CONFIGURATION_CALLS) ServerForm.LogMessage(0, 0, 0, "GetValue", "Value retrieved OK: " + registryValue);
134 | }
135 | else
136 | {
137 | if (LOG_CONFIGURATION_CALLS) ServerForm.LogMessage(0, 0, 0, "GetValue", "SubKey has a value so using it...");
138 | registryValue = (string)baseRegistryKey.CreateSubKey(SubKey).GetValue(KeyName);
139 | if (LOG_CONFIGURATION_CALLS) ServerForm.LogMessage(0, 0, 0, "GetValue", "Value retrieved OK: " + registryValue);
140 | }
141 |
142 | if (registryValue == null)
143 | {
144 | SetValueInvariant(KeyName, SubKey, DefaultValue);
145 | return DefaultValue;
146 | }
147 |
148 | if (LOG_CONFIGURATION_CALLS) ServerForm.LogMessage(0, 0, 0, "GetValue DateTime", $"String value prior to Convert: {registryValue}");
149 |
150 | if (DateTime.TryParse(registryValue, CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces, out DateTime RetVal))
151 | {
152 | // The string parsed OK so return the parsed value;
153 | if (LOG_CONFIGURATION_CALLS) ServerForm.LogMessage(0, 0, 0, "GetValue DateTime", $"Retrieved {KeyName} = {RetVal}");
154 | return (T)((object)RetVal);
155 | }
156 | else // If the string fails to parse, overwrite with the default value and return this
157 | {
158 | if (LOG_CONFIGURATION_CALLS) ServerForm.LogMessage(0, 0, 0, "GetValue DateTime", $"Failed to parse registry value, persisting and returning the default value: {DefaultValue}");
159 | SetValueInvariant(KeyName, SubKey, DefaultValue);
160 | return DefaultValue;
161 | }
162 | }
163 |
164 | if ((typeof(T) == typeof(Int32)) | (typeof(T) == typeof(int)))
165 | {
166 | string registryValue;
167 | if (SubKey == "")
168 | {
169 | if (LOG_CONFIGURATION_CALLS) ServerForm.LogMessage(0, 0, 0, "GetValue", "SubKey is empty so getting value directly");
170 | registryValue = (string)baseRegistryKey.GetValue(KeyName);
171 | if (LOG_CONFIGURATION_CALLS) ServerForm.LogMessage(0, 0, 0, "GetValue", "Value retrieved OK: " + registryValue);
172 | }
173 | else
174 | {
175 | if (LOG_CONFIGURATION_CALLS) ServerForm.LogMessage(0, 0, 0, "GetValue", "SubKey has a value so using it...");
176 | registryValue = (string)baseRegistryKey.CreateSubKey(SubKey).GetValue(KeyName);
177 | if (LOG_CONFIGURATION_CALLS) ServerForm.LogMessage(0, 0, 0, "GetValue", "Value retrieved OK: " + registryValue);
178 | }
179 |
180 | if (registryValue == null)
181 | {
182 | SetValueInvariant(KeyName, SubKey, DefaultValue);
183 | int defaultValue = Convert.ToInt32(DefaultValue);
184 | registryValue = defaultValue.ToString(CultureInfo.InvariantCulture);
185 | }
186 |
187 | int RetVal = Convert.ToInt32(registryValue, CultureInfo.InvariantCulture);
188 | if (LOG_CONFIGURATION_CALLS) ServerForm.LogMessage(0, 0, 0, "GetValue", $"Retrieved {KeyName} = {RetVal}");
189 | return (T)((object)RetVal);
190 | }
191 |
192 | throw new DriverException("GetValue: Unknown type: " + typeof(T).Name);
193 | }
194 |
195 | public void SetValue(string KeyName, string SubKey, T Value)
196 | {
197 | if (LOG_CONFIGURATION_CALLS) ServerForm.LogMessage(0, 0, 0, "SetValue", $"Setting {typeof(T).Name} value '{KeyName}' in subkey '{SubKey}' to: '{Value}'");
198 |
199 | if (SubKey == "") baseRegistryKey.SetValue(KeyName, Value.ToString());
200 | else baseRegistryKey.CreateSubKey(SubKey).SetValue(KeyName, Value.ToString());
201 | }
202 |
203 | public void SetValueInvariant(string KeyName, string SubKey, T Value)
204 | {
205 | if (LOG_CONFIGURATION_CALLS) ServerForm.LogMessage(0, 0, 0, "SetValue DateTime", $"Setting {typeof(T).Name} value '{KeyName}' in subkey '{SubKey}' to: '{Value}'");
206 |
207 | if ((typeof(T) == typeof(Int32)) | (typeof(T) == typeof(int)))
208 | {
209 | int intValue = Convert.ToInt32(Value);
210 | if (SubKey == "") baseRegistryKey.SetValue(KeyName, intValue.ToString(CultureInfo.InvariantCulture));
211 | else baseRegistryKey.CreateSubKey(SubKey).SetValue(KeyName, intValue.ToString(CultureInfo.InvariantCulture));
212 | return;
213 | }
214 |
215 | if (typeof(T) == typeof(bool))
216 | {
217 | bool boolValue = Convert.ToBoolean(Value);
218 | if (SubKey == "") baseRegistryKey.SetValue(KeyName, boolValue.ToString(CultureInfo.InvariantCulture));
219 | else baseRegistryKey.CreateSubKey(SubKey).SetValue(KeyName, boolValue.ToString(CultureInfo.InvariantCulture));
220 | return;
221 | }
222 |
223 | if (typeof(T) == typeof(decimal))
224 | {
225 | decimal decimalValue = Convert.ToDecimal(Value);
226 | if (SubKey == "") baseRegistryKey.SetValue(KeyName, decimalValue.ToString(CultureInfo.InvariantCulture));
227 | else baseRegistryKey.CreateSubKey(SubKey).SetValue(KeyName, decimalValue.ToString(CultureInfo.InvariantCulture));
228 | return;
229 | }
230 |
231 | if (typeof(T) == typeof(DateTime))
232 | {
233 | DateTime dateTimeValue = Convert.ToDateTime(Value);
234 | if (SubKey == "") baseRegistryKey.SetValue(KeyName, dateTimeValue.ToString("HH:mm:ss", CultureInfo.InvariantCulture));
235 | else baseRegistryKey.CreateSubKey(SubKey).SetValue(KeyName, dateTimeValue.ToString("HH:mm:ss", CultureInfo.InvariantCulture));
236 | return;
237 | }
238 |
239 | throw new DriverException("SetValueInvariant: Unknown type: " + typeof(T).Name);
240 | }
241 |
242 | #region IDisposable Support
243 | private bool disposedValue = false; // To detect redundant calls
244 |
245 | protected virtual void Dispose(bool disposing)
246 | {
247 | if (!disposedValue)
248 | {
249 | if (disposing)
250 | {
251 | baseRegistryKey?.Dispose();
252 | hiveKey?.Dispose();
253 | }
254 |
255 | disposedValue = true;
256 | }
257 | }
258 |
259 | // This code added to correctly implement the disposable pattern.
260 | public void Dispose()
261 | {
262 | // Do not change this code. Put clean up code in Dispose(bool disposing) above.
263 | Dispose(true);
264 | }
265 | #endregion
266 | }
267 | }
268 |
--------------------------------------------------------------------------------
/Remote Server/ConfigurationManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Reflection;
4 | using System.Text.Json.Serialization;
5 | using System.Text.Json;
6 |
7 | namespace ASCOM.Remote
8 | {
9 | [DefaultMember("Settings")]
10 | internal class ConfigurationManager : IDisposable
11 | {
12 | private const string FOLDER_NAME = "ASCOM Remote"; // Folder name underneath the local application data folder
13 | private const string SETTINGS_FILENAME = "remote.settings"; // Settings file name
14 |
15 | private TraceLoggerPlus TL;
16 | private Settings settings;
17 | private bool disposedValue;
18 | readonly int settingsFileVersion;
19 | private readonly JsonDocument appSettingsDocument = null;
20 | private readonly JsonSerializerOptions deserialiseOptions;
21 | private readonly JsonSerializerOptions serialiseOptions;
22 |
23 | #region Initialiser and Dispose
24 |
25 | ///
26 | /// Create a Configuration management instance and load the current settings
27 | ///
28 | /// Data logger instance.
29 | public ConfigurationManager(TraceLoggerPlus logger)
30 | {
31 | TL = logger;
32 |
33 | try
34 | {
35 | // Set JSON serialisation options
36 | serialiseOptions = new()
37 | {
38 | WriteIndented = true // Write the file in indented form for easier reading
39 | };
40 | serialiseOptions.Converters.Add(new JsonStringEnumConverter()); // For increased resilience, accept both string member names and integer member values as valid for enum elements.
41 |
42 | // Set JSON de-serialisation options
43 | deserialiseOptions = new()
44 | {
45 | PropertyNameCaseInsensitive = true // Ignore incorrect element name casing
46 | };
47 | deserialiseOptions.Converters.Add(new JsonStringEnumConverter()); // For increased resilience, accept both string member names and integer member values as valid for enum elements.
48 |
49 | // Create a new settings file with default values in case the supplied file cannot be used
50 | settings = new();
51 |
52 | // Get the full settings file name including path
53 | string folderName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), FOLDER_NAME);
54 | SettingsFileName = Path.Combine(folderName, SETTINGS_FILENAME);
55 | TL?.LogMessage("ConfigurationManager", $"Settings folder: {folderName}, Settings file: {SettingsFileName}");
56 |
57 | // Load the values in the settings file if it exists
58 | if (File.Exists(SettingsFileName)) // Settings file exists
59 | {
60 | // Read the file contents into a string
61 | TL?.LogMessage("ConfigurationManager", "File exists, about to read it...");
62 | string serialisedSettings = File.ReadAllText(SettingsFileName);
63 | TL?.LogMessage("ConfigurationManager", $"Serialised settings: \r\n{serialisedSettings}");
64 |
65 | // Make a basic check to see if this file is a beta / pre-release version that doesn't have a version number. If so replace with a new version
66 | if (!serialisedSettings.Contains("\"SettingsCompatibilityVersion\":")) // No compatibility version found so assume that this is a corrupt settings file
67 | {
68 | // Persist the default settings values
69 | try
70 | {
71 | // Rename the current settings file to preserve it
72 | string badVersionSettingsFileName = $"{SettingsFileName}.bad";
73 | File.Delete(badVersionSettingsFileName);
74 | File.Move(SettingsFileName, $"{badVersionSettingsFileName}");
75 |
76 | // Persist the default settings values
77 | settings = new();
78 | PersistSettings(settings);
79 |
80 | Status = $"A corrupt settings file was found.\r\n\r\nApplication settings have been reset to defaults and the original settings file has been renamed to {badVersionSettingsFileName}.";
81 | }
82 | catch (Exception ex2)
83 | {
84 | TL?.LogMessage("ConfigurationManager", $"A corrupt settings file found but an error occurred when saving new Remote Server settings: {ex2}");
85 | Status = $"$\"A corrupt settings file was found but an error occurred when saving new Remote Server settings: {ex2.Message}.";
86 | }
87 | }
88 | else // File does have a compatibility version so read in the settings from the file
89 | {
90 | TL?.LogMessage("ConfigurationManager", $"Found compatibility version element...");
91 | // Try to read in the settings version number from the settings file
92 | try
93 | {
94 | TL?.LogMessage("ConfigurationManager", $"About to parse settings string");
95 | appSettingsDocument = JsonDocument.Parse(serialisedSettings, new JsonDocumentOptions { CommentHandling = JsonCommentHandling.Skip });
96 | TL?.LogMessage("ConfigurationManager", $"About to get settings version");
97 | settingsFileVersion = appSettingsDocument.RootElement.GetProperty("SettingsCompatibilityVersion").GetInt32();
98 | TL?.LogMessage("ConfigurationManager", $"Found settings version: {settingsFileVersion}");
99 |
100 | // Handle different file versions
101 | switch (settingsFileVersion)
102 | {
103 | // File version 1 - first production release
104 | case 1:
105 |
106 | try
107 | {
108 |
109 | // De-serialise the settings string into a Settings object
110 | settings = JsonSerializer.Deserialize(serialisedSettings, deserialiseOptions);
111 |
112 | // Test whether the retrieved settings match the requirements of this version of the Remote Server
113 | if (settings.SettingsCompatibilityVersion == Settings.SETTINGS_COMPATIBILTY_VERSION) // Version numbers match so all is well
114 | {
115 | Status = $"Settings read OK.";
116 | }
117 | else // Version numbers don't match so reset to defaults
118 | {
119 | int originalSettingsCompatibilityVersion = 0;
120 | try
121 | {
122 | originalSettingsCompatibilityVersion = settings.SettingsCompatibilityVersion;
123 |
124 | // Rename the current settings file to preserve it
125 | string badVersionSettingsFileName = $"{SettingsFileName}.badversion";
126 | File.Delete(badVersionSettingsFileName);
127 | File.Move(SettingsFileName, $"{badVersionSettingsFileName}");
128 |
129 | // Persist the default settings values
130 | settings = new();
131 | PersistSettings(settings);
132 |
133 | Status = $"The current settings version: {originalSettingsCompatibilityVersion} does not match the required version: {Settings.SETTINGS_COMPATIBILTY_VERSION}. Application settings have been reset to default values and the original settings file renamed to {badVersionSettingsFileName}.";
134 | }
135 | catch (Exception ex2)
136 | {
137 | TL?.LogMessage("ConfigurationManager", $"Error persisting new Remote Server settings file: {ex2}");
138 | Status = $"The current settings version:{originalSettingsCompatibilityVersion} does not match the required version: {Settings.SETTINGS_COMPATIBILTY_VERSION} but the new settings could not be saved: {ex2.Message}.";
139 | }
140 | }
141 | }
142 | catch (JsonException ex1)
143 | {
144 | // There was an exception when parsing the settings file so report it and set default values
145 | TL?.LogMessage("ConfigurationManager", $"Error de-serialising Remote Server settings file: {ex1}");
146 | Status = $"There was an error de-serialising the settings file and application default settings are in effect.\r\n\r\nPlease correct the error in the file or use the \"Reset to Defaults\" button on the Settings page to save new values.\r\n\r\nJSON parser error message:\r\n{ex1.Message}";
147 | }
148 | catch (Exception ex1)
149 | {
150 | TL?.LogMessage("ConfigurationManager", ex1.ToString());
151 | Status = $"Exception reading the settings file, default values are in effect.";
152 | }
153 | break;
154 |
155 | // Handle unknown settings version numbers
156 | default:
157 |
158 | // Persist default settings values because the file version is unknown and the file may be corrupt
159 | try
160 | {
161 | // Rename the current settings file to preserve it
162 | string badVersionSettingsFileName = $"{SettingsFileName}.unknownversion";
163 | File.Delete(badVersionSettingsFileName);
164 | File.Move(SettingsFileName, $"{badVersionSettingsFileName}");
165 |
166 | // Persist the default settings values
167 | settings = new();
168 | PersistSettings(settings);
169 |
170 | Status = $"An unsupported settings version was found: {settingsFileVersion}. Settings have been reset to defaults and the original settings file has been renamed to {badVersionSettingsFileName}.";
171 | }
172 | catch (Exception ex2)
173 | {
174 | TL?.LogMessage("ConfigurationManager", $"An unsupported settings version was found: {settingsFileVersion} but an error occurred when saving new Remote Server settings: {ex2}");
175 | Status = $"$\"An unsupported settings version was found: {settingsFileVersion} but an error occurred when saving new Remote Server settings: {ex2.Message}.";
176 | }
177 | break;
178 | }
179 | }
180 | catch (JsonException ex)
181 | {
182 | // There was an exception when parsing the settings file so report it and use default values
183 | TL?.LogMessage("ConfigurationManager", $"Error getting settings file version from settings file: {ex}");
184 | Status = $"An error occurred when reading the settings file version and application default settings are in effect.\r\n\r\nPlease correct the error in the file or use the \"Reset to Defaults\" button on the Settings page to create a new settings file.\r\n\r\nJSON parser error message:\r\n{ex.Message}";
185 | }
186 | catch (Exception ex)
187 | {
188 | TL?.LogMessage("ConfigurationManager", $"Exception parsing the settings file: {ex}");
189 | Status = $"Exception parsing the settings file: {ex.Message}";
190 | }
191 | finally
192 | {
193 | appSettingsDocument?.Dispose();
194 | }
195 | }
196 | }
197 | else // Settings file does not exist
198 | {
199 | TL.LogMessage("ConfigurationManager", $"Configuration file does not exist, initialising new file: {SettingsFileName}");
200 | PersistSettings(settings);
201 | Status = $"First time use - configuration set to default values.";
202 | }
203 | }
204 | catch (Exception ex)
205 | {
206 | TL?.LogMessage("ConfigurationManager", ex.ToString());
207 | Status = $"Unexpected exception reading the settings file, default values are in use.";
208 | }
209 | }
210 |
211 | protected virtual void Dispose(bool disposing)
212 | {
213 | if (!disposedValue)
214 | {
215 | if (disposing)
216 | {
217 | TL = null;
218 | settings = null;
219 | }
220 |
221 | disposedValue = true;
222 | }
223 | }
224 |
225 | public void Dispose()
226 | {
227 | // Do not change this code. Put clean-up code in 'Dispose(bool disposing)' method
228 | Dispose(disposing: true);
229 | GC.SuppressFinalize(this);
230 | }
231 |
232 | #endregion
233 |
234 | #region Public methods
235 |
236 | public void Reset()
237 | {
238 | try
239 | {
240 | settings = new();
241 | PersistSettings(settings);
242 | Status = $"Settings reset at {DateTime.Now:HH:mm:ss}.";
243 | }
244 | catch (Exception ex)
245 | {
246 | TL?.LogMessage("Reset", $"Exception during Reset: {ex}");
247 | throw;
248 | }
249 | }
250 |
251 | ///
252 | /// Persist current settings
253 | ///
254 | public void Save()
255 | {
256 | TL?.LogMessage("Save", "Saving settings to settings file");
257 | PersistSettings(settings);
258 | Status = $"Settings saved at {DateTime.Now:HH:mm:ss}.";
259 | }
260 |
261 | public Settings Settings
262 | {
263 | get { return settings; }
264 | }
265 |
266 | public string SettingsFileName { get; private set; }
267 |
268 | ///
269 | /// Text message describing any issues found when validating the settings
270 | ///
271 | public string Status { get; private set; }
272 |
273 | #endregion
274 |
275 | #region Support code
276 |
277 | private void PersistSettings(Settings settingsToPersist)
278 | {
279 | try
280 | {
281 | ArgumentNullException.ThrowIfNull(settingsToPersist);
282 |
283 | // Set the version number of this settings file
284 | settingsToPersist.SettingsCompatibilityVersion = Settings.SETTINGS_COMPATIBILTY_VERSION;
285 |
286 | TL?.LogMessage("PersistSettings", $"Settings file: {SettingsFileName}");
287 |
288 | string serialisedSettings = JsonSerializer.Serialize(settingsToPersist, serialiseOptions);
289 |
290 | Directory.CreateDirectory(Path.GetDirectoryName(SettingsFileName));
291 | File.WriteAllText(SettingsFileName, serialisedSettings);
292 | }
293 | catch (Exception ex)
294 | {
295 | TL.LogMessage("PersistSettings", ex.ToString());
296 | }
297 | }
298 |
299 | #endregion
300 |
301 | }
302 | }
303 |
--------------------------------------------------------------------------------
/Remote Server/ConfiguredDevice.cs:
--------------------------------------------------------------------------------
1 | namespace ASCOM.Remote
2 | {
3 | ///
4 | /// Class to hold COM activation and access information for a served device
5 | ///
6 | public class ConfiguredDevice(string deviceType, string progID, string description, int deviceNumber, bool allowConnectedSetFalse, bool allowConnectedSetTrue, bool allowConcurrentAccess, string uniqueId)
7 | {
8 | public string DeviceType { get; set; } = deviceType;
9 | public string ProgID { get; set; } = progID;
10 | public string Description { get; set; } = description;
11 | public int DeviceNumber { get; set; } = deviceNumber;
12 | public bool AllowConnectedSetFalse { get; set; } = allowConnectedSetFalse;
13 | public bool AllowConnectedSetTrue { get; set; } = allowConnectedSetTrue;
14 | public bool AllowConcurrentAccess { get; set; } = allowConcurrentAccess;
15 | public string UniqueID { get; set; } = uniqueId;
16 |
17 | ///
18 | /// Return a unique key for this device based on its device type and device number
19 | ///
20 | public string DeviceKey
21 | {
22 | get
23 | {
24 | return $"{DeviceType.ToLowerInvariant()}/{DeviceNumber}"; // Create the device key
25 | }
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Remote Server/DriverHostForm.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace ASCOM.Remote
2 | {
3 | partial class DriverHostForm
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | this.label1 = new System.Windows.Forms.Label();
32 | this.SuspendLayout();
33 | //
34 | // label1
35 | //
36 | this.label1.AutoSize = true;
37 | this.label1.Location = new System.Drawing.Point(12, 9);
38 | this.label1.Name = "label1";
39 | this.label1.Size = new System.Drawing.Size(165, 13);
40 | this.label1.TabIndex = 1;
41 | this.label1.Text = "ASCOM Remote Server Driver host";
42 | //
43 | // DriverHostForm
44 | //
45 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
46 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
47 | this.ClientSize = new System.Drawing.Size(193, 31);
48 | this.ControlBox = false;
49 | this.Controls.Add(this.label1);
50 | this.MaximizeBox = false;
51 | this.MinimizeBox = false;
52 | this.Name = "DriverHostForm";
53 | this.ShowInTaskbar = false;
54 | this.Text = "Driver Host Form";
55 | this.WindowState = System.Windows.Forms.FormWindowState.Minimized;
56 | this.ResumeLayout(false);
57 | this.PerformLayout();
58 |
59 | }
60 |
61 | #endregion
62 |
63 | private System.Windows.Forms.Label label1;
64 | }
65 | }
--------------------------------------------------------------------------------
/Remote Server/DriverHostForm.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Windows.Forms;
4 | using System.Threading;
5 |
6 | namespace ASCOM.Remote
7 | {
8 | ///
9 | /// Form class to host a single driver and provide the required message loop to make sure all works properly
10 | /// The driver is created in the form loaded event and signalled by adding an entry in ActiveObjects in the form load event handler.
11 | ///
12 | public partial class DriverHostForm : Form
13 | {
14 | string deviceKey;
15 | readonly ServerForm restServer;
16 | readonly KeyValuePair configuredDevice;
17 |
18 | ///
19 | /// Main constructor for the form. Save state variables to use when creating, using and destroying the driver
20 | ///
21 | /// TraceLogger object
22 | /// ConfiguredDevice object with details of the driver to be created
23 | /// Handle to the main server form
24 | public DriverHostForm(KeyValuePair device, ServerForm server)
25 | {
26 | InitializeComponent();
27 | configuredDevice = device;
28 | restServer = server;
29 |
30 | this.FormClosed += DriverHostForm_FormClosed;
31 | this.Load += DriverHostForm_Load;
32 | ServerForm.LogMessage(0, 0, 0, "DriverHostForm", "Form has been instantiated on thread: " + Environment.CurrentManagedThreadId);
33 | }
34 |
35 | ///
36 | /// Form load event - Create the driver
37 | ///
38 | ///
39 | ///
40 | private void DriverHostForm_Load(object sender, EventArgs e)
41 | {
42 | deviceKey = $"{configuredDevice.Value.DeviceType.ToLowerInvariant()}/{configuredDevice.Value.DeviceNumber}";
43 |
44 | ServerForm.LogMessage(0, 0, 0, "DriverHostForm", $"Creating driver {deviceKey} ({configuredDevice.Key}) on thread {Environment.CurrentManagedThreadId} with apartment state {Thread.CurrentThread.GetApartmentState()}");
45 | restServer.CreateInstance(configuredDevice); // Create the driver on this thread
46 | ServerForm.LogMessage(0, 0, 0, "DriverHostForm", $"Created driver {deviceKey} ({configuredDevice.Key}) on thread {Environment.CurrentManagedThreadId}");
47 |
48 | ServerForm.ActiveObjects[deviceKey].DriverHostForm = this; // Save the driver host form reference so that calls can be made to the driver
49 | }
50 |
51 | ///
52 | /// When the form is closing stop the windows message loop on this thread so that the thread will end
53 | ///
54 | ///
55 | ///
56 | private void DriverHostForm_FormClosed(object sender, FormClosedEventArgs e)
57 | {
58 | Application.ExitThread();
59 | }
60 |
61 | ///
62 | /// Send a command to the driver
63 | ///
64 | /// Details of the command to send
65 | /// Background thread on which the command is executing
66 | public Thread DriverCommand(RequestData requestData)
67 | {
68 | try // Process the command
69 | {
70 | Application.DoEvents();
71 |
72 | // Process the command on a separate thread allowing other requests to be handled concurrently through this thread, which is running the Windows message loop
73 | Thread driverThread = new(new ParameterizedThreadStart(ProcessCommand)); // Create a new thread on which to make the call to the COM driver
74 | if (ServerForm.DebugTraceState) ServerForm.LogMessage1(requestData, requestData.Elements[SharedConstants.URL_ELEMENT_METHOD], $"DriverCommand has received a command for {deviceKey} on FORM thread {Environment.CurrentManagedThreadId} Apartment state: {Thread.CurrentThread.GetApartmentState()} Is background: {Thread.CurrentThread.IsBackground} Is thread pool thread: {Thread.CurrentThread.IsThreadPoolThread}");
75 |
76 | driverThread.Start(requestData); // Start the thread supplying the request data to the method
77 |
78 | if (ServerForm.DebugTraceState) ServerForm.LogMessage1(requestData, requestData.Elements[SharedConstants.URL_ELEMENT_METHOD], $"DriverCommand has started the command for {deviceKey} on FORM thread {Environment.CurrentManagedThreadId}");
79 | return driverThread; // Return the thread so that the calling method can wait for it to complete and so that this thread can start waiting for the next command
80 | }
81 | catch (Exception ex) // Something serious has gone wrong with the ASCOM Remote server itself so report this to the user
82 | {
83 | ServerForm.LogException1(requestData, "DriverCommand", ex.ToString());
84 | ServerForm.Return500Error(requestData, $"Internal server error (DriverOnSeparateThread): {ex}");
85 | }
86 | return null;
87 | }
88 |
89 | void ProcessCommand(object requestData)
90 | {
91 | restServer.ProcessDriverCommand((RequestData)requestData);
92 | }
93 |
94 | ///
95 | /// Destroy the driver
96 | ///
97 | public void DestroyDriver()
98 | {
99 | ServerForm.LogMessage(0, 0, 0, "DriverHostForm", "Destroy driver method has been called on thread: " + Environment.CurrentManagedThreadId);
100 | ServerForm.DestroyDriver(deviceKey);
101 | ServerForm.LogMessage(0, 0, 0, "DriverHostForm", "Destroy driver method completed on thread: " + Environment.CurrentManagedThreadId);
102 | Application.ExitThread(); // Close all forms on this thread, which will also terminate the thread itself
103 | }
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/Remote Server/DriverHostForm.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/Remote Server/Entity Classes/ActiveObject.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | namespace ASCOM.Remote
3 | {
4 | ///
5 | /// Class to hold information about an ASCOM Remote served device
6 | ///
7 | ///
8 | /// Parameterised initialiser for the main object properties that also initialises the lock object
9 | ///
10 | ///
11 | ///
12 | ///
13 | public class ActiveObject(bool AllowConnectedSetFalseParm, bool AllowSetConnectedTrueParm, bool AllowConcurrentAccessParm, string ConfiguredDeviceKeyParm)
14 | {
15 | private int? interfaceVersion;
16 |
17 | ///
18 | /// Key of the corresponding entry in ConfiguredDevices to allow tieback to the main configuration information
19 | ///
20 | public string ConfiguredDeviceKey { get; set; } = ConfiguredDeviceKeyParm;
21 |
22 | ///
23 | /// The device COM object
24 | ///
25 | public dynamic DeviceObject { get; set; }
26 |
27 | ///
28 | /// Flag indicating whether the user is allowed to set the device's Connected property to False
29 | ///
30 | public bool AllowConnectedSetFalse { get; set; } = AllowConnectedSetFalseParm;
31 |
32 | ///
33 | /// Flag indicating whether the user is allowed to set the device's Connected property to True
34 | ///
35 | public bool AllowConnectedSetTrue { get; set; } = AllowSetConnectedTrueParm;
36 |
37 | ///
38 | /// Flag indicating whether the driver can handle concurrent calls
39 | ///
40 | public bool AllowConcurrentAccess { get; set; } = AllowConcurrentAccessParm;
41 |
42 | ///
43 | /// Lock object to ensure that only one command at a time is sent to the device
44 | ///
45 | public object CommandLock { get; } = new object(); // Create a lock object
46 |
47 | ///
48 | /// Host form for the device when devices are set to run on independent threads
49 | ///
50 | public DriverHostForm DriverHostForm { get; set; }
51 |
52 | ///
53 | /// Flag indicating whether the device was created and the Connected property set True without error
54 | ///
55 | public bool InitialisedOk { get; set; } = false; // Initialise flag and error message
56 |
57 | ///
58 | /// Error message that will be returned if the user tries to call a method on a device that did not initialise correctly.
59 | ///
60 | public string InitialisationErrorMessage { get; set; } = "ASCOM Remote ActiveObject error message - something went wrong during device initialisation but the error message was not recorded for an unknown reason.";
61 |
62 | ///
63 | /// If the device is a Camera, points to the last image array value returned, otherwise null
64 | ///
65 | public object LastImageArray { get; set; }
66 |
67 | ///
68 | /// The device's interface version
69 | ///
70 | public int InterfaceVersion
71 | {
72 | get
73 | {
74 | // Check whether we have already cached this device's interface version
75 | if (interfaceVersion.HasValue) // Cached value available so return it.
76 | return interfaceVersion.Value;
77 |
78 | // No cached value so query it from the device
79 | try
80 | {
81 | interfaceVersion = DeviceObject.Interfaceversion;
82 | }
83 | catch // Something went wrong, so most likely this is an old simulator without an InterfceVersion property - Set the property to 1.
84 | {
85 | interfaceVersion = 1;
86 | }
87 |
88 | // Return the interface version.
89 | return interfaceVersion.Value;
90 | }
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/Remote Server/ExtensionMethods.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace ASCOM.Remote
5 | {
6 | public static class ExtensionMethods
7 | {
8 | ///
9 | /// Lookup dictionary to translate lower case method names to mixed case.
10 | /// The device type is included in order to disambiguate the same method name if used in different device types AND cased differently/>
11 | ///
12 | private static readonly Dictionary methodLookup = new()
13 | {
14 | { "connected","Connected" },
15 |
16 | // Telescope
17 | { "tracking","Tracking" },
18 | { "doesrefraction","DoesRefraction" },
19 | { "slewsettletime","SlewSettleTime" },
20 | { "declinationrate","DeclinationRate" },
21 | { "rightascensionrate","RightAscensionRate" },
22 | { "guideratedeclination","GuideRateDeclination" },
23 | { "guideraterightascension","GuideRateRightAscension" },
24 | { "sideofpier", "SideOfPier" },
25 | { "siteelevation","SiteElevation" },
26 | { "sitelatitude","SiteLatitude" },
27 | { "sitelongitude","SiteLongitude" },
28 | { "targetdeclination","TargetDeclination" },
29 | { "targetrightascension","TargetRightAscension" },
30 | { "utcdate","UTCDate" },
31 | { "trackingrate","TrackingRate" },
32 | { SharedConstants.AXIS_PARAMETER_NAME,SharedConstants.AXIS_PARAMETER_NAME },
33 | { SharedConstants.RA_PARAMETER_NAME,SharedConstants.RA_PARAMETER_NAME },
34 | { SharedConstants.DEC_PARAMETER_NAME,SharedConstants.DEC_PARAMETER_NAME },
35 | { SharedConstants.RATE_PARAMETER_NAME,SharedConstants.RATE_PARAMETER_NAME },
36 | { SharedConstants.DIRECTION_PARAMETER_NAME,SharedConstants.DIRECTION_PARAMETER_NAME },
37 | { SharedConstants.DURATION_PARAMETER_NAME,SharedConstants.DURATION_PARAMETER_NAME },
38 | { SharedConstants.ALT_PARAMETER_NAME,SharedConstants.ALT_PARAMETER_NAME },
39 | { SharedConstants.AZ_PARAMETER_NAME,SharedConstants.AZ_PARAMETER_NAME },
40 |
41 | // Rotator
42 | { SharedConstants.POSITION_PARAMETER_NAME,SharedConstants.POSITION_PARAMETER_NAME},
43 | { "reverse","Reverse" },
44 |
45 | // Camera
46 | { "binx","BinX" },
47 | { "biny","BinY"},
48 | { "cooleron","CoolerOn"},
49 | { "fastreadout","FastReadout"},
50 | { "gain","Gain"},
51 | { "numx","NumX"},
52 | { "numy","NumY"},
53 | { "offset","Offset"},
54 | { "readoutmode","ReadoutMode"},
55 | { "setccdtemperature","SetCCDTemperature"},
56 | { "startx","StartX"},
57 | { "starty","StartY"},
58 | { "subexposureduration","SubExposureDuration"},
59 | { "slaved","Slaved" },
60 | { "Brightness","Brightness" },
61 | { "position","Position" },
62 | { "tempcomp","TempComp" },
63 | { SharedConstants.SENSORNAME_PARAMETER_NAME,SharedConstants.SENSORNAME_PARAMETER_NAME },
64 | { "averageperiod","AveragePeriod" },
65 | { "sensordescription","SensorDescription" },
66 | { SharedConstants.ID_PARAMETER_NAME,SharedConstants.ID_PARAMETER_NAME },
67 | { SharedConstants.NAME_PARAMETER_NAME,SharedConstants.NAME_PARAMETER_NAME },
68 | { SharedConstants.VALUE_PARAMETER_NAME,SharedConstants.VALUE_PARAMETER_NAME },
69 | { SharedConstants.STATE_PARAMETER_NAME,SharedConstants.STATE_PARAMETER_NAME },
70 | { "id","Id" }
71 | };
72 |
73 | ///
74 | /// Look up the cased version of a method name.
75 | ///
76 | /// The method name to look up
77 | /// Optional device type to disambiguate method names that are used in more than 1 device type AND cased differently
78 | /// When the required method name key has not yet been added to the lookup dictionary.
79 | /// The mixed case equivalent of the supplied method name
80 | public static string ToCorrectCase(this string methodName, string deviceType = null)
81 | {
82 | string lookupKey = "ValueNotSet";
83 | // Look up the cased version of the method. If this fails a KeyNotFoiund exception will be thrown
84 | try
85 | {
86 | lookupKey = $"{methodName}{(deviceType is null ? "" : $".{deviceType}")}";
87 | return methodLookup[lookupKey];
88 | }
89 | catch (Exception ex)
90 | {
91 | return $"UnknownMethod:'{lookupKey}' - {ex}";
92 | }
93 | }
94 |
95 | ///
96 | /// Append a byte array to an existing array
97 | ///
98 | /// First array
99 | /// Second array
100 | /// Concatenated array of byte
101 | public static byte[] Append(this byte[] first, byte[] second)
102 | {
103 | byte[] ret = new byte[first.Length + second.Length];
104 | Buffer.BlockCopy(first, 0, ret, 0, first.Length);
105 | Buffer.BlockCopy(second, 0, ret, first.Length, second.Length);
106 | return ret;
107 | }
108 |
109 | public static string ToConcatenatedString(this List list, string separator)
110 | {
111 | string concatenatedList = "";
112 | foreach (string item in list)
113 | {
114 | concatenatedList += item + separator;
115 | }
116 | return concatenatedList.Trim(separator.ToCharArray());
117 | }
118 |
119 | public static void FromConcatenatedString(this List list, string concatenatedString, string separator)
120 | {
121 | string[] items = concatenatedString.Split(separator.ToCharArray());
122 |
123 | list.Clear();
124 |
125 | foreach (string item in items)
126 | {
127 | list.Add(item);
128 | }
129 | }
130 |
131 | public static List ToListStringValue(this List fromList)
132 | {
133 | List toList = [];
134 |
135 | foreach (string item in fromList)
136 | {
137 | toList.Add(new StringValue(item));
138 | }
139 |
140 | return toList;
141 | }
142 |
143 | public static List ToListString(this List fromList)
144 | {
145 | List toList = [];
146 |
147 | foreach (StringValue item in fromList)
148 | {
149 | toList.Add(item.Value);
150 | }
151 |
152 | return toList;
153 | }
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/Remote Server/HideTabControlBorders.cs:
--------------------------------------------------------------------------------
1 | using System.Drawing;
2 | using System.Drawing.Drawing2D;
3 | using System.Windows.Forms;
4 |
5 | namespace ASCOM.Remote
6 | {
7 | ///
8 | /// Class that takes overrides normal tab control drawing in order to remove white boarders that are created by the default control
9 | ///
10 | /// This is taken from https://stackoverflow.com/questions/7768555/tabcontrol-and-borders-visual-glitch
11 | ///
12 | internal class HideTabControlBorders : NativeWindow
13 | {
14 | private const int WM_PAINT = 0xF;
15 |
16 | private readonly TabControl tabControl;
17 |
18 | public HideTabControlBorders(TabControl tc)
19 | {
20 | tabControl = tc;
21 | tabControl.Selected += new TabControlEventHandler(TabControl_Selected);
22 | AssignHandle(tc.Handle);
23 | }
24 |
25 | void TabControl_Selected(object sender, TabControlEventArgs e)
26 | {
27 | tabControl.Invalidate();
28 | }
29 |
30 | protected override void WndProc(ref Message m)
31 | {
32 | base.WndProc(ref m);
33 |
34 | if (m.Msg == WM_PAINT)
35 | {
36 | using Graphics g = Graphics.FromHwnd(m.HWnd);
37 |
38 | //Replace the outside white borders:
39 | if (tabControl.Parent != null)
40 | {
41 | g.SetClip(new Rectangle(0, 0, tabControl.Width - 2, tabControl.Height - 1), CombineMode.Exclude);
42 | using SolidBrush sb = new(tabControl.Parent.BackColor);
43 | g.FillRectangle(sb, new Rectangle(0,
44 | tabControl.ItemSize.Height + 2,
45 | tabControl.Width,
46 | tabControl.Height - (tabControl.ItemSize.Height + 2)));
47 | }
48 |
49 | //Replace the inside white borders:
50 | if (tabControl.SelectedTab != null)
51 | {
52 | g.ResetClip();
53 | Rectangle r = tabControl.SelectedTab.Bounds;
54 | g.SetClip(r, CombineMode.Exclude);
55 | using SolidBrush sb = new(tabControl.SelectedTab.BackColor);
56 | g.FillRectangle(sb, new Rectangle(r.Left - 3,
57 | r.Top - 1,
58 | r.Width + 4,
59 | r.Height + 3));
60 | }
61 | }
62 | }
63 |
64 |
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/Remote Server/HostPc.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Net;
3 | using System.Net.NetworkInformation;
4 | using System.Net.Sockets;
5 |
6 | namespace ASCOM.Remote
7 | {
8 | ///
9 | /// Class that presents all usable IPv4 and IPv6 addresses on the host
10 | ///
11 | internal class HostPc
12 | {
13 |
14 | ///
15 | /// Class initialiser
16 | ///
17 | public HostPc()
18 | {
19 | }
20 |
21 | ///
22 | /// Returns the hosts IPv4 addresses
23 | ///
24 | ///
25 | public static List IpV4Addresses
26 | {
27 | get
28 | {
29 | return GetIpAddresses(AddressFamily.InterNetwork);
30 | }
31 | }
32 | ///
33 | /// Returns the hosts IPv6 addresses
34 | ///
35 | ///
36 | public static List IpV6Addresses
37 | {
38 | get
39 | {
40 | return GetIpAddresses(AddressFamily.InterNetworkV6);
41 | }
42 | }
43 |
44 | ///
45 | ///
46 | ///
47 | ///
48 | ///
49 | private static List GetIpAddresses(AddressFamily addressFamily)
50 | {
51 | // Initialise the IPv4 and IPv6 address lists
52 | List ipAddresses = [];
53 |
54 | // Get an array of all network interfaces on this host
55 | NetworkInterface[] adapters = NetworkInterface.GetAllNetworkInterfaces();
56 |
57 | // Iterate over each network adapter looking for usable IP addresses
58 | foreach (NetworkInterface adapter in adapters)
59 | {
60 | // Only test operational adapters
61 | if (adapter.OperationalStatus == OperationalStatus.Up)
62 | {
63 | // Get the adapter's properties
64 | IPInterfaceProperties adapterProperties = adapter.GetIPProperties();
65 |
66 | // If the adapter has properties get the collection of unicast addresses
67 | if (adapterProperties != null)
68 | {
69 | // Get the collection of unicast addresses
70 | UnicastIPAddressInformationCollection uniCast = adapterProperties.UnicastAddresses;
71 |
72 | // If there are some unicast IP addresses get these
73 | if (uniCast.Count > 0)
74 | {
75 | // Iterate over the unicast addresses
76 | foreach (UnicastIPAddressInformation uni in uniCast)
77 | {
78 | // Save IPv4 addresses to the IPv4 list
79 | if (uni.Address.AddressFamily == addressFamily)
80 | {
81 | ipAddresses.Add(uni.Address);
82 | }
83 | }
84 | }
85 | }
86 | }
87 | }
88 |
89 | // Sort the addresses into ascending text order
90 | ipAddresses.Sort(CompareIPaddresses);
91 |
92 | return ipAddresses;
93 | }
94 |
95 | ///
96 | /// COmpare two IPAdress values based on their text representations
97 | ///
98 | ///
99 | ///
100 | ///
101 | private static int CompareIPaddresses(IPAddress x, IPAddress y)
102 | {
103 | if (x == null)
104 | {
105 | if (y == null) // If x is null and y is null, they're equal.
106 | {
107 | return 0;
108 | }
109 | else // If x is null and y is not null, y is greater.
110 | {
111 | return -1;
112 | }
113 | }
114 | else // If x is not null...
115 | {
116 | if (y == null) // ...and y is null, x is greater.
117 | {
118 | return 1;
119 | }
120 | else // ...and y is not null, compare the lengths of the two strings.
121 | {
122 | return x.ToString().CompareTo(y.ToString());
123 | }
124 | }
125 | }
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/Remote Server/InvalidParameterException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.Serialization;
3 |
4 | namespace ASCOM.Remote
5 | {
6 | ///
7 | /// This exception should be raised by the driver to reject a parameter from the client.
8 | ///
9 | [Serializable]
10 | public class InvalidParameterException : DriverException
11 | {
12 | const string csDefaultMessage = "The requested operation is not permitted at this time";
13 | public static readonly int InvalidParameterErrorNumber = unchecked((int)0x80040FFE);
14 |
15 | ///
16 | /// Default public constructor for NotConnectedException takes no parameters.
17 | ///
18 | public InvalidParameterException() : base(csDefaultMessage, InvalidParameterErrorNumber)
19 | {
20 | }
21 |
22 | ///
23 | /// Initializes a new instance of the class
24 | /// from another exception.
25 | ///
26 | /// The inner exception.
27 | public InvalidParameterException(Exception innerException) : base(csDefaultMessage, InvalidParameterErrorNumber, innerException)
28 | {
29 | }
30 |
31 | ///
32 | /// Initializes a new instance of the class
33 | /// with a non-default error message.
34 | ///
35 | /// A descriptive human-readable message.
36 | public InvalidParameterException(string message) : base(message, InvalidParameterErrorNumber)
37 | {
38 | }
39 |
40 | ///
41 | /// Initializes a new instance of the class
42 | /// based on another exception.
43 | ///
44 | /// Descriptive text documenting the cause or source of the error.
45 | /// The inner exception the led to the throwing of this exception.
46 | public InvalidParameterException(string message, Exception innerException) : base(message, InvalidParameterErrorNumber, innerException)
47 | {
48 | }
49 |
50 | ///
51 | /// Added to keep Code Analysis happy
52 | ///
53 | ///
54 | ///
55 | protected InvalidParameterException(SerializationInfo info, StreamingContext context) : base(info, context)
56 | {
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/Remote Server/ProfileDevice.cs:
--------------------------------------------------------------------------------
1 | namespace ASCOM.Remote
2 | {
3 | public class ProfileDevice(string deviceType, string progID, string description)
4 | {
5 | public string DeviceType { get; set; } = deviceType;
6 | public string ProgID { get; set; } = progID;
7 | public string Description { get; set; } = description;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Remote Server/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.IO;
4 | using System.Threading;
5 | using System.Windows.Forms;
6 | using ASCOM.Tools;
7 |
8 | namespace ASCOM.Remote
9 | {
10 | static class Program
11 | {
12 | ///
13 | /// The main entry point for the application.
14 | ///
15 | [STAThread]
16 | static void Main(string[] arguments)
17 | {
18 | // Check whether any command line arguments were supplied
19 | if (arguments.Length > 0) // One or more arguments were supplied
20 | {
21 | switch (arguments[0].ToLowerInvariant())
22 | {
23 | case "-reset":
24 | case "--reset":
25 | case "/reset":
26 | // Reset the configuration
27 | TraceLoggerPlus TLReset = new("RemoteReset", true);
28 | using (ConfigurationManager configurationManager = new(TLReset))
29 | {
30 | configurationManager.Reset();
31 | configurationManager.Save();
32 | }
33 |
34 | Configuration.Reset();
35 |
36 | MessageBox.Show($"Configuration reset to default values.", "Reset Configuration", MessageBoxButtons.OK);
37 | break;
38 |
39 | default:
40 | MessageBox.Show($"The parameter: {arguments[0]} is not valid.", "Unrecognised command line parameter", MessageBoxButtons.OK, MessageBoxIcon.Warning);
41 | return;
42 | }
43 | }
44 |
45 | TraceLoggerPlus TLInit = new("RemoteInit", true);
46 | using (ConfigurationManager configurationManager = new(TLInit))
47 | {
48 | // Restart as the other bitness version if required
49 |
50 | // Check whether we are supposed to be running as a 32bit or a 64bit application
51 | if (configurationManager.Settings.RunAs64Bit) // We are supposed to be running as a 64bit application
52 | {
53 | // Check whether the OS is 32bit or 64bit
54 | if (Environment.Is64BitOperatingSystem) // OS is 64bit
55 | {
56 | // Check whether the application is running as 32bit or 64bit
57 | if (Environment.Is64BitProcess) // Application is 64bit
58 | {
59 | // No action required because we are already running as 64bit
60 | Debug.WriteLine($"Already running as 64bit");
61 | }
62 | else // Application is 32bit
63 | {
64 | // Start the 64bit version of the application
65 | string folderName32 = Path.GetDirectoryName(Application.ExecutablePath); // Folder name of the 32bit version
66 | Debug.WriteLine($"Folder name = {folderName32}");
67 | string folderName64 = Directory.GetParent(folderName32).FullName;
68 |
69 | Debug.WriteLine($"New folder name = {folderName64}");
70 | Process.Start($"{folderName64}\\remoteserver.exe");
71 |
72 | // End this program
73 | return;
74 | }
75 | }
76 | else // OS is 32bit
77 | {
78 | // Can't run as a 64bit application on a 32bit OS so no action because this must already be the 32bit version of the application
79 | }
80 | }
81 | else // We are supposed to be running as a 32bit application
82 | {
83 | // Check whether the OS is 32bit or 64bit
84 | if (Environment.Is64BitOperatingSystem) // OS is 64bit
85 | {
86 | // Check whether the application is running as 32bit or 64bit
87 | if (Environment.Is64BitProcess) // Application is 64bit
88 | {
89 | // Start the 32bit version of the application
90 | Debug.WriteLine($"Starting the 32bit version");
91 |
92 | string folderName = Path.GetDirectoryName(Application.ExecutablePath);
93 | Debug.WriteLine($"Folder name = {folderName}");
94 | folderName += @"\32bit";
95 | Debug.WriteLine($"New folder name = {folderName}");
96 | Process.Start($"{folderName}\\remoteserver.exe");
97 |
98 | // End this program
99 | return;
100 | }
101 | else // Application is 32bit
102 | {
103 | // No action required because we are already running as 32bit on the 64bit OS
104 | Debug.WriteLine($"Already running as 32bit");
105 | }
106 | }
107 | else // OS is 32bit
108 | {
109 | // No action required because the OS is 32bit so this application must also be 32bit.
110 | }
111 | }
112 |
113 | Debug.WriteLine($"Starting application");
114 | }
115 |
116 | #if !DEBUG // Exclude the un-handled exception handlers from the Debug version so that the application can be debugged in Visual Studio
117 | // Add the event handler for handling UI thread exceptions to the event.
118 | Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
119 |
120 | // Set the un-handled exception mode to force all Windows Forms errors to go through our handler.
121 | Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
122 |
123 | // Add the event handler for handling non-UI thread exceptions to the event.
124 | AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
125 | #endif
126 | Application.EnableVisualStyles();
127 | Application.SetCompatibleTextRenderingDefault(false);
128 | ServerForm serverForm = new();
129 | Application.Run(serverForm);
130 |
131 | if (serverForm.RestartApplication) Application.Restart(); // Restart the application if the network permissions have been changed
132 |
133 | #if DEBUG // When debugging, include a log to show the time of close down
134 | TraceLogger TL = new("ASCOMRemoteEnded", true)
135 | {
136 | Enabled = true
137 | };
138 | TL.LogMessage("ASCOMRemoteEnded", "Application has exited");
139 | TL.Enabled = false;
140 | TL.Dispose();
141 | TL = null;
142 | #endif
143 | }
144 |
145 | static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
146 | {
147 | TraceLogger TL = new("RemoteAccessServerException", true)
148 | {
149 | Enabled = true
150 | };
151 | TL.LogMessage("Main", $"Thread exception: {e.Exception}");
152 | Process.Start(TL.LogFileName);
153 |
154 | TL.Enabled = false;
155 | TL.Dispose();
156 |
157 | //MessageBox.Show(e.Exception.Message, "Un-handled Thread Exception, see RemoteAccessServerException log for details.");
158 | Environment.Exit(0);
159 | }
160 |
161 | static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
162 | {
163 | Exception exception = (Exception)e.ExceptionObject;
164 | TraceLogger TL = new("RemoteAccessServerException", true)
165 | {
166 | Enabled = true
167 | };
168 | TL.LogMessage("Main", $"Un-handled exception: {exception}");
169 | Process.Start(TL.LogFileName);
170 | TL.Enabled = false;
171 | TL.Dispose();
172 | Environment.Exit(0);
173 | }
174 | }
175 | }
176 |
--------------------------------------------------------------------------------
/Remote Server/Remote Server.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | WinExe
4 | ASCOM.Remote
5 | RemoteServer
6 | net8.0-windows
7 | true
8 | true
9 | ASCOM Remote Server
10 | ASCOM Remote Server
11 | Copyright © 2024 Peter Simpson
12 | bin\$(Configuration)\
13 | AnyCPU;x86;x64
14 | win-x86;win-x64
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | $(ProductMajor).$(ProductMinor).$(ProductPatch)$(ProductPreReleaseSeparator)$(ProductPreRelease)+$(BuildNumber).$(Head)
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | <_Parameter1>ShortGitId
41 | <_Parameter2>$(BuildNumber).$(Head)
42 |
43 |
44 |
45 |
46 |
47 |
48 | 7
49 | 0
50 | 1
51 |
52 |
53 |
54 |
55 |
60 |
61 | $([MSBuild]::Add($([MSBuild]::Multiply($([MSBuild]::Modulo($([MSBuild]::Add($([MSBuild]::Multiply($([MSBuild]::Subtract($([System.DateTime]::UtcNow.Year),2023)),366)),$([System.DateTime]::UtcNow.DayOfYear))),2048)),32)),$([System.DateTime]::UtcNow.TimeOfDay.Hours)))
62 |
63 |
64 |
65 | -
66 |
67 |
68 |
69 | $(ProductMajor).$(ProductMinor).$(ProductPatch).$(BuildNumber)
70 | $(ProductMajor).$(ProductMinor).$(ProductPatch).$(BuildNumber)
71 |
72 |
73 | $(ProductMajor).$(ProductMinor).$(ProductPatch)$(ProductPreReleaseSeparator)$(ProductPreRelease)+$(BuildNumber)
74 |
75 |
76 | embedded
77 | AnyCPU
78 |
79 |
80 | embedded
81 | AnyCPU
82 |
83 |
84 | x86
85 | embedded
86 |
87 |
88 | embedded
89 | AnyCPU
90 | true
91 |
92 |
93 | embedded
94 | AnyCPU
95 | true
96 |
97 |
98 | embedded
99 | x86
100 | true
101 |
102 |
103 | ASCOM.Remote.Program
104 |
105 |
106 | ..\Remote Server Key.snk
107 |
108 |
109 | ASCOM.ico
110 |
111 |
112 | True
113 |
114 |
115 |
116 |
117 | DriverHostForm.cs
118 |
119 |
120 |
121 | ServedDevice.cs
122 |
123 |
124 |
125 | SetupForm.cs
126 |
127 |
128 |
129 | ServerForm.cs
130 |
131 |
132 | DriverHostForm.cs
133 |
134 |
135 | ServedDevice.cs
136 |
137 |
138 | SetupForm.cs
139 |
140 |
141 | ServerForm.cs
142 | Designer
143 |
144 |
145 |
146 |
147 | Always
148 |
149 |
150 | Always
151 |
152 |
153 | Never
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
--------------------------------------------------------------------------------
/Remote Server/RequestData.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Specialized;
2 | using System.Net;
3 |
4 | namespace ASCOM.Remote
5 | {
6 | public class RequestData
7 | {
8 | public RequestData()
9 | {
10 | }
11 |
12 | public RequestData(string clientIpAddress, uint clientID, uint clientTransactionID, uint serverTransactionID, NameValueCollection suppliedParameters, HttpListenerRequest request, HttpListenerResponse response, string[] elements, string deviceKey)
13 | {
14 | ClientIpAddress = clientIpAddress;
15 | ClientID = clientID;
16 | ClientTransactionID = clientTransactionID;
17 | ServerTransactionID = serverTransactionID;
18 | QueryParameters = suppliedParameters;
19 | Request = request;
20 | Response = response;
21 | Elements = elements;
22 | DeviceKey = deviceKey;
23 | }
24 |
25 | public uint ClientID { get; set; }
26 | public uint ClientTransactionID { get; set; }
27 | public uint ServerTransactionID { get; set; }
28 | public NameValueCollection FormParameters { get; set; }
29 | public NameValueCollection QueryParameters { get; set; }
30 | public HttpListenerRequest Request { get; set; }
31 | public HttpListenerResponse Response { get; set; }
32 | public string[] Elements { get; set; }
33 | public string DeviceKey { get; set; }
34 | public string ClientIpAddress { get; set; }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Remote Server/ResponseClasses/AlpacaConfiguredDevicesResponse.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace ASCOM.Remote
4 | {
5 | public class AlpacaConfiguredDevicesResponse : RestResponseBase
6 | {
7 | public AlpacaConfiguredDevicesResponse()
8 | {
9 | Value = [];
10 | }
11 |
12 | public AlpacaConfiguredDevicesResponse(uint clientTransactionID, uint transactionID, List value)
13 | {
14 | base.ServerTransactionID = transactionID;
15 | base.ClientTransactionID = clientTransactionID;
16 | Value = value;
17 | }
18 |
19 | public List Value { get; set; }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Remote Server/ResponseClasses/AlpacaDescriptionResponse.cs:
--------------------------------------------------------------------------------
1 | namespace ASCOM.Remote
2 | {
3 | public class AlpacaDescriptionResponse : RestResponseBase
4 | {
5 | public AlpacaDescriptionResponse()
6 | {
7 | Value = new AlpacaDeviceDescription();
8 | }
9 |
10 | public AlpacaDescriptionResponse(uint clientTransactionID, uint transactionID, AlpacaDeviceDescription value)
11 | {
12 | base.ServerTransactionID = transactionID;
13 | base.ClientTransactionID = clientTransactionID;
14 | Value = value;
15 | }
16 |
17 | public AlpacaDeviceDescription Value { get; set; }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Remote Server/ResponseClasses/AlpacaDiscoveryResponse.cs:
--------------------------------------------------------------------------------
1 | namespace ASCOM.Remote
2 | {
3 | public class AlpacaDiscoveryResponse
4 | {
5 | public AlpacaDiscoveryResponse() { }
6 |
7 | public AlpacaDiscoveryResponse(int alpacaPort)
8 | {
9 | AlpacaPort = alpacaPort;
10 | }
11 |
12 | public int AlpacaPort { get; set; }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Remote Server/ResponseClasses/AxisRatesResponse.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace ASCOM.Remote
4 | {
5 | public class AxisRatesResponse : RestResponseBase
6 | {
7 | public AxisRatesResponse() { }
8 |
9 | public AxisRatesResponse(uint clientTransactionID, uint transactionID, List value)
10 | {
11 | base.ServerTransactionID = transactionID;
12 | base.ClientTransactionID = clientTransactionID;
13 | Value = value;
14 | }
15 |
16 | public List Value { get; set; }
17 | }
18 | }
--------------------------------------------------------------------------------
/Remote Server/ResponseClasses/Base64ArrayHandOffResponse.cs:
--------------------------------------------------------------------------------
1 | namespace ASCOM.Remote
2 | {
3 | public class Base64ArrayHandOffResponse : ImageArrayResponseBase
4 | {
5 | public int Dimension0Length { get; set; } = 0;
6 |
7 | public int Dimension1Length { get; set; } = 0;
8 |
9 | public int Dimension2Length { get; set; } = 0;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Remote Server/ResponseClasses/Base64ArrayJsonResponse.cs:
--------------------------------------------------------------------------------
1 | namespace ASCOM.Remote
2 | {
3 | public class Base64ArrayJsonResponse : Base64ArrayHandOffResponse
4 | {
5 | public string Value { get; set; }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/Remote Server/ResponseClasses/BoolResponse.cs:
--------------------------------------------------------------------------------
1 | namespace ASCOM.Remote
2 | {
3 | public class BoolResponse : RestResponseBase
4 | {
5 | public BoolResponse() { }
6 | public BoolResponse(uint clientTransactionID, uint transactionID, bool value)
7 | {
8 | base.ServerTransactionID = transactionID;
9 | base.ClientTransactionID = clientTransactionID;
10 | Value = value;
11 | }
12 |
13 | public bool Value { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Remote Server/ResponseClasses/ConfigurationResponse.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace ASCOM.Remote
4 | {
5 | public class ConfigurationResponse : RestResponseBase
6 | {
7 | private Dictionary list;
8 |
9 | public ConfigurationResponse() { }
10 |
11 | public ConfigurationResponse(uint clientTransactionID, uint transactionID, Dictionary value)
12 | {
13 | base.ClientTransactionID = clientTransactionID;
14 | base.ServerTransactionID = transactionID;
15 | list = value;
16 | }
17 |
18 | public Dictionary Value
19 | {
20 | get { return list; }
21 | set { list = value; }
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/Remote Server/ResponseClasses/DateAndTimeResponse.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace ASCOM.Remote
4 | {
5 | public class DateTimeResponse : RestResponseBase
6 | {
7 | public DateTimeResponse() { }
8 |
9 | public DateTimeResponse(uint clientTransactionID, uint transactionID, DateTime value)
10 | {
11 | base.ServerTransactionID = transactionID;
12 | base.ClientTransactionID = clientTransactionID;
13 | Value = value;
14 | }
15 |
16 | public DateTime Value { get; set; }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Remote Server/ResponseClasses/DoubleArray2DResponse.cs:
--------------------------------------------------------------------------------
1 | namespace ASCOM.Remote
2 | {
3 | public class DoubleArray2DResponse : ImageArrayResponseBase
4 | {
5 | private double[,] doubleArray2D;
6 |
7 | private const int RANK = 2;
8 | private const SharedConstants.ImageArrayElementTypes TYPE = SharedConstants.ImageArrayElementTypes.Double;
9 |
10 | public DoubleArray2DResponse(uint clientTransactionID, uint transactionID, double[,] value)
11 | {
12 | base.ServerTransactionID = transactionID;
13 | doubleArray2D = value;
14 | base.Type = (int)TYPE;
15 | base.Rank = RANK;
16 | base.ClientTransactionID = clientTransactionID;
17 | }
18 |
19 | public double[,] Value
20 | {
21 | get { return doubleArray2D; }
22 | set
23 | {
24 | doubleArray2D = value;
25 | base.Type = (int)TYPE;
26 | base.Rank = RANK;
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Remote Server/ResponseClasses/DoubleArray3DResponse.cs:
--------------------------------------------------------------------------------
1 | namespace ASCOM.Remote
2 | {
3 | public class DoubleArray3DResponse : ImageArrayResponseBase
4 | {
5 | private double[,,] doubleArray3D;
6 |
7 | private const int RANK = 3;
8 | private const SharedConstants.ImageArrayElementTypes TYPE = SharedConstants.ImageArrayElementTypes.Double;
9 |
10 | public DoubleArray3DResponse(uint clientTransactionID, uint transactionID, double[,,] value)
11 | {
12 | base.ServerTransactionID = transactionID;
13 | doubleArray3D = value;
14 | base.Type = (int)TYPE;
15 | base.Rank = RANK;
16 | base.ClientTransactionID = clientTransactionID;
17 | }
18 |
19 | public double[,,] Value
20 | {
21 | get { return doubleArray3D; }
22 | set
23 | {
24 | doubleArray3D = value;
25 | base.Type = (int)TYPE;
26 | base.Rank = RANK;
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Remote Server/ResponseClasses/DoubleResponse.cs:
--------------------------------------------------------------------------------
1 | namespace ASCOM.Remote
2 | {
3 | public class DoubleResponse : RestResponseBase
4 | {
5 | public DoubleResponse() { }
6 |
7 | public DoubleResponse(uint clientTransactionID, uint transactionID, double value)
8 | {
9 | base.ServerTransactionID = transactionID;
10 | base.ClientTransactionID = clientTransactionID;
11 | Value = value;
12 | }
13 |
14 | public double Value { get; set; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Remote Server/ResponseClasses/ImageArrayResponseBase.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace ASCOM.Remote
4 | {
5 | public class ImageArrayResponseBase : RestResponseBase
6 | {
7 | private int rank = 0;
8 | private SharedConstants.ImageArrayElementTypes type = SharedConstants.ImageArrayElementTypes.Unknown;
9 |
10 | [JsonProperty(Order = -3)]
11 | public int Type
12 | {
13 | get { return (int)type; }
14 | set { type = (SharedConstants.ImageArrayElementTypes)value; }
15 | }
16 |
17 | [JsonProperty(Order = -2)]
18 | public int Rank
19 | {
20 | get { return rank; }
21 | set { rank = value; }
22 | }
23 |
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Remote Server/ResponseClasses/IntArray1DResponse.cs:
--------------------------------------------------------------------------------
1 | namespace ASCOM.Remote
2 | {
3 | public class IntArray1DResponse : RestResponseBase
4 | {
5 | private int[] intArray1D;
6 |
7 | public IntArray1DResponse() { }
8 |
9 | public IntArray1DResponse(uint clientTransactionID, uint transactionID, int[] value)
10 | {
11 | base.ServerTransactionID = transactionID;
12 | base.ClientTransactionID = clientTransactionID;
13 | intArray1D = value;
14 | }
15 |
16 | public int[] Value
17 | {
18 | get { return intArray1D; }
19 | set { intArray1D = value; }
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Remote Server/ResponseClasses/IntArray2DResponse.cs:
--------------------------------------------------------------------------------
1 | namespace ASCOM.Remote
2 | {
3 | public class IntArray2DResponse : ImageArrayResponseBase
4 | {
5 | private int[,] intArray2D;
6 |
7 | private const int RANK = 2;
8 | private const SharedConstants.ImageArrayElementTypes TYPE = SharedConstants.ImageArrayElementTypes.Int32;
9 |
10 | public IntArray2DResponse(uint clientTransactionID, uint transactionID)
11 | {
12 | base.ServerTransactionID = transactionID;
13 | base.ClientTransactionID = clientTransactionID;
14 | }
15 |
16 | public int[,] Value
17 | {
18 | get { return intArray2D; }
19 | set
20 | {
21 | intArray2D = value;
22 | base.Type = (int)TYPE;
23 | base.Rank = RANK;
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Remote Server/ResponseClasses/IntArray3DResponse.cs:
--------------------------------------------------------------------------------
1 | namespace ASCOM.Remote
2 | {
3 | public class IntArray3DResponse : ImageArrayResponseBase
4 | {
5 | private int[,,] intArray3D;
6 |
7 | private const int RANK = 3;
8 | private const SharedConstants.ImageArrayElementTypes TYPE = SharedConstants.ImageArrayElementTypes.Int32;
9 |
10 | public IntArray3DResponse(uint clientTransactionID, uint transactionID)
11 | {
12 | base.ServerTransactionID = transactionID;
13 | base.ClientTransactionID = clientTransactionID;
14 | }
15 |
16 | public int[,,] Value
17 | {
18 | get { return intArray3D; }
19 | set
20 | {
21 | intArray3D = value;
22 | base.Type = (int)TYPE;
23 | base.Rank = RANK;
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Remote Server/ResponseClasses/IntResponse.cs:
--------------------------------------------------------------------------------
1 | namespace ASCOM.Remote
2 | {
3 | public class IntResponse : RestResponseBase
4 | {
5 | public IntResponse() { }
6 |
7 | public IntResponse(uint clientTransactionID, uint transactionID, int value)
8 | {
9 | base.ServerTransactionID = transactionID;
10 | base.ClientTransactionID = clientTransactionID;
11 | Value = value;
12 | }
13 |
14 | public int Value { get; set; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Remote Server/ResponseClasses/MethodResponse.cs:
--------------------------------------------------------------------------------
1 | namespace ASCOM.Remote
2 | {
3 | public enum MethodTypes
4 | {
5 | PropertyGet,
6 | PropertySet,
7 | Method,
8 | Function
9 | }
10 |
11 | public class MethodResponse : RestResponseBase
12 | {
13 | public MethodResponse() { }
14 | public MethodResponse(uint clientTransactionID, uint transactionID)
15 | {
16 | base.ServerTransactionID = transactionID;
17 | base.ClientTransactionID = clientTransactionID;
18 | }
19 | // No additional fields for this class
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Remote Server/ResponseClasses/ProfileResponse.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace ASCOM.Remote
4 | {
5 | public class ProfileResponse : RestResponseBase
6 | {
7 | private List list;
8 |
9 | public ProfileResponse() { }
10 |
11 | public ProfileResponse(uint clientTransactionID, uint transactionID, List value)
12 | {
13 | base.ServerTransactionID = transactionID;
14 | list = value;
15 | base.ClientTransactionID = clientTransactionID;
16 | }
17 |
18 | public List Value
19 | {
20 | get { return list; }
21 | set { list = value; }
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/Remote Server/ResponseClasses/RateResponse.cs:
--------------------------------------------------------------------------------
1 | namespace ASCOM.Remote
2 | {
3 | public class RateResponse(double minimum, double maximum)
4 | {
5 | private double maximum = maximum;
6 | private double minimum = minimum;
7 |
8 | public double Maximum
9 | {
10 | get { return this.maximum; }
11 | set { this.maximum = value; }
12 | }
13 |
14 | public double Minimum
15 | {
16 | get { return this.minimum; }
17 | set { this.minimum = value; }
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Remote Server/ResponseClasses/RestResponseBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace ASCOM.Remote
4 | {
5 | public abstract class RestResponseBase
6 | {
7 | private Exception exception;
8 |
9 | public uint ClientTransactionID { get; set; }
10 | public uint ServerTransactionID { get; set; }
11 | public int ErrorNumber { get; set; } = 0;
12 | public string ErrorMessage { get; set; } = "";
13 | public Exception DriverException
14 | {
15 | get
16 | {
17 | return exception;
18 | }
19 | set
20 | {
21 | exception = value;
22 | if (exception != null)
23 | {
24 | // Set the error number and message fields from the exception
25 | ErrorNumber = exception.HResult;
26 | ErrorMessage = exception.Message;
27 |
28 | // Convert ASCOM exception error numbers (0x80040400 - 0x80040FFF) to equivalent Alpaca error numbers (0x400 to 0xFFF) so that they will be interpreted correctly by native Alpaca clients
29 | if ((ErrorNumber >= SharedConstants.ASCOM_ERROR_NUMBER_BASE) && (ErrorNumber <= SharedConstants.ASCOM_ERROR_NUMBER_MAX))
30 | {
31 | ErrorNumber = ErrorNumber - SharedConstants.ASCOM_ERROR_NUMBER_OFFSET;
32 | }
33 | }
34 | }
35 | }
36 |
37 | ///
38 | /// Method used by NewtonSoft JSON to determine whether the DriverException field should be included in the serialise JSON response.
39 | ///
40 | ///
41 | public bool ShouldSerializeDriverException()
42 | {
43 | return SerializeDriverException;
44 | }
45 |
46 | ///
47 | /// Control variable that determines whether the DriverException field will be included in serialised JSON responses
48 | ///
49 | internal bool SerializeDriverException { get; set; } = true;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Remote Server/ResponseClasses/ShortArray2DResponse.cs:
--------------------------------------------------------------------------------
1 | namespace ASCOM.Remote
2 | {
3 | public class ShortArray2DResponse : ImageArrayResponseBase
4 | {
5 | private short[,] shortArray2D;
6 |
7 | private const int RANK = 2;
8 | private const SharedConstants.ImageArrayElementTypes TYPE = SharedConstants.ImageArrayElementTypes.Int16;
9 |
10 | public ShortArray2DResponse(uint clientTransactionID, uint transactionID, short[,] value)
11 | {
12 | base.ServerTransactionID = transactionID;
13 | shortArray2D = value;
14 | base.Type = (int)TYPE;
15 | base.Rank = RANK;
16 | base.ClientTransactionID = clientTransactionID;
17 | }
18 |
19 | public short[,] Value
20 | {
21 | get { return shortArray2D; }
22 | set
23 | {
24 | shortArray2D = value;
25 | base.Type = (int)TYPE;
26 | base.Rank = RANK;
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Remote Server/ResponseClasses/ShortArray3DResponse.cs:
--------------------------------------------------------------------------------
1 | namespace ASCOM.Remote
2 | {
3 | public class ShortArray3DResponse : ImageArrayResponseBase
4 | {
5 | private short[,,] shortArray3D;
6 |
7 | private const int RANK = 3;
8 | private const SharedConstants.ImageArrayElementTypes TYPE = SharedConstants.ImageArrayElementTypes.Int16;
9 |
10 | public ShortArray3DResponse(uint clientTransactionID, uint transactionID, short[,,] value)
11 | {
12 | base.ServerTransactionID = transactionID;
13 | shortArray3D = value;
14 | base.Type = (int)TYPE;
15 | base.Rank = RANK;
16 | base.ClientTransactionID = clientTransactionID;
17 | }
18 |
19 | public short[,,] Value
20 | {
21 | get { return shortArray3D; }
22 | set
23 | {
24 | shortArray3D = value;
25 | base.Type = (int)TYPE;
26 | base.Rank = RANK;
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Remote Server/ResponseClasses/ShortResponse.cs:
--------------------------------------------------------------------------------
1 | namespace ASCOM.Remote
2 | {
3 | public class ShortResponse : RestResponseBase
4 | {
5 | public ShortResponse() { }
6 |
7 | public ShortResponse(uint clientTransactionID, uint transactionID, short value)
8 | {
9 | base.ServerTransactionID = transactionID;
10 | base.ClientTransactionID = clientTransactionID;
11 | Value = value;
12 | }
13 |
14 | public short Value { get; set; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Remote Server/ResponseClasses/StringArrayResponse.cs:
--------------------------------------------------------------------------------
1 | namespace ASCOM.Remote
2 | {
3 | public class StringArrayResponse : RestResponseBase
4 | {
5 | private string[] stringArray;
6 |
7 | public StringArrayResponse() { }
8 |
9 | public StringArrayResponse(uint clientTransactionID, uint transactionID, string[] value)
10 | {
11 | base.ServerTransactionID = transactionID;
12 | stringArray = value;
13 | base.ClientTransactionID = clientTransactionID;
14 | }
15 |
16 | public string[] Value
17 | {
18 | get { return stringArray; }
19 | set { stringArray = value; }
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Remote Server/ResponseClasses/StringListResponse.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace ASCOM.Remote
4 | {
5 | public class StringListResponse:RestResponseBase
6 | {
7 | private List list;
8 |
9 | public StringListResponse() { }
10 |
11 | public StringListResponse(uint clientTransactionID, uint transactionID, List value)
12 | {
13 | base.ServerTransactionID = transactionID;
14 | list = value;
15 | base.ClientTransactionID = clientTransactionID;
16 | }
17 |
18 | public List Value
19 | {
20 | get { return list; }
21 | set { list = value; }
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Remote Server/ResponseClasses/StringResponse.cs:
--------------------------------------------------------------------------------
1 | namespace ASCOM.Remote
2 | {
3 | public class StringResponse : RestResponseBase
4 | {
5 | public StringResponse() { }
6 |
7 | public StringResponse(uint clientTransactionID, uint transactionID, string value)
8 | {
9 | base.ServerTransactionID = transactionID;
10 | base.ClientTransactionID = clientTransactionID;
11 | Value = value;
12 | }
13 |
14 | public string Value { get; set; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Remote Server/ResponseClasses/TrackingRatesResponse.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using ASCOM.Common.DeviceInterfaces;
3 |
4 | namespace ASCOM.Remote
5 | {
6 | public class TrackingRatesResponse : RestResponseBase
7 | {
8 | private List rates;
9 |
10 | public TrackingRatesResponse() { }
11 |
12 | public TrackingRatesResponse(uint clientTransactionID, uint transactionID)
13 | {
14 | base.ServerTransactionID = transactionID;
15 | base.ClientTransactionID = clientTransactionID;
16 | }
17 |
18 | public List Value
19 | {
20 | get { return rates; }
21 | set { rates = value; }
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Remote Server/ServedDevice.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Windows.Forms;
5 | using System.Runtime.InteropServices;
6 | using ASCOM.Com;
7 | using ASCOM.Common;
8 |
9 | namespace ASCOM.Remote
10 | {
11 | public partial class ServedDevice : UserControl
12 | {
13 |
14 | #region Variables
15 |
16 | int deviceNumber = 0;
17 | string description = "";
18 | string progID = "";
19 | bool devicesAreConnected = false;
20 |
21 | Profile profile;
22 | readonly List deviceTypes;
23 | readonly Dictionary deviceDictionary;
24 | SetupForm setupForm;
25 | bool recalculate = false;
26 |
27 | #endregion
28 |
29 | #region Initialisers
30 | public ServedDevice()
31 | {
32 | InitializeComponent();
33 |
34 | // Create generic lists
35 | deviceTypes = [];
36 | deviceDictionary = [];
37 |
38 | cmbDeviceType.MouseUp += CmbDeviceType_MouseUp; // To force a device number recalculation if the device type is changed
39 |
40 | // The combo boxes have to be self painted because the DropDownStyle is DropDownList, to make the list read only, and this changes the background colour to grey!
41 | cmbDevice.DrawMode = DrawMode.OwnerDrawFixed;
42 | cmbDevice.DrawItem += new DrawItemEventHandler(ComboBox_DrawItem); // Attach an event handler to draw the combo box on demand
43 | cmbDeviceType.DrawMode = DrawMode.OwnerDrawFixed;
44 | cmbDeviceType.DrawItem += new DrawItemEventHandler(ComboBox_DrawItem); // Attach an event handler to draw the combo box on demand
45 | }
46 |
47 | public void InitUI(SetupForm parent)
48 | {
49 | setupForm = parent;
50 | //ServerForm.LogMessage(0, 0, 0, "ServedDevice.InitUI", "Start");
51 | profile = new Profile();
52 | //ServerForm.LogMessage(0, 0, 0, "ServedDevice.InitUI", "Created Profile");
53 |
54 | cmbDeviceType.Items.Add(SharedConstants.DEVICE_NOT_CONFIGURED);
55 | //ServerForm.LogMessage(0, 0, 0, "ServedDevice.InitUI", "Added Device not configured");
56 |
57 |
58 | foreach (string deviceType in Devices.DeviceTypeNames())
59 | {
60 | //ServerForm.LogMessage(0, 0, 0, "ServedDevice.InitUI", "Adding item: " + deviceType);
61 | cmbDeviceType.Items.Add(deviceType);
62 | deviceTypes.Add(deviceType); // Remember the device types on this system
63 | }
64 | //ServerForm.LogMessage(0, 0, 0, "ServedDevice.InitUI", "Setting selected index to 0");
65 |
66 | cmbDeviceType.SelectedIndex = 0;
67 |
68 | //ServerForm.LogMessage(0, 0, 0, "ServedDevice.InitUI", "Finished");
69 |
70 | }
71 | #endregion
72 |
73 | #region Data accessor properties
74 |
75 | public int DeviceNumber
76 | {
77 | get
78 | {
79 | return deviceNumber;
80 | }
81 | set
82 | {
83 | deviceNumber = value;
84 | txtDeviceNumber.Text = value.ToString();
85 | }
86 | }
87 |
88 | public string DeviceType
89 | {
90 | get
91 | {
92 | try
93 | {
94 | return cmbDeviceType.SelectedItem.ToString();
95 | }
96 | catch
97 | {
98 | return "None";
99 | }
100 | }
101 | set
102 | {
103 | try
104 | {
105 | cmbDeviceType.SelectedItem = value;
106 | }
107 | catch
108 | {
109 | cmbDeviceType.SelectedIndex = -1; ;
110 | }
111 | }
112 | }
113 |
114 | public string Description
115 | {
116 | get
117 | {
118 | try
119 | {
120 | return description;
121 | }
122 | catch
123 | {
124 | return "";
125 | }
126 | }
127 | set
128 | {
129 | try
130 | {
131 | description = value;
132 | cmbDevice.SelectedItem = value.ToString();
133 | }
134 | catch { }
135 | }
136 | }
137 |
138 | public string ProgID
139 | {
140 | get
141 | {
142 | return progID;
143 | }
144 | set
145 | {
146 | progID = value;
147 | if (!DesignMode)
148 | {
149 | try
150 | {
151 | //ServerForm.LogMessage(0, 0, 0, "ServedDevice.ProgID", "Set ProgID to: " + progID);
152 | switch (progID)
153 | {
154 | case "":
155 | cmbDevice.SelectedIndex = -1;
156 | break;
157 | case SharedConstants.DEVICE_NOT_CONFIGURED:
158 | //ServerForm.LogMessage(0, 0, 0, "ServedDevice.ProgID", "Description: " + SharedConstants.DEVICE_NOT_CONFIGURED);
159 | cmbDevice.SelectedItem = 0;
160 | break;
161 | default:
162 | //ServerForm.LogMessage(0, 0, 0, "ServedDevice.ProgID", "Description: " + deviceDictionary[progID]);
163 | cmbDevice.SelectedItem = deviceDictionary[progID];
164 | break;
165 | }
166 | }
167 | catch (Exception ex)
168 | {
169 | ServerForm.LogException(0, 0, 0, "ServedDevice.ProgID", ex.ToString());
170 | cmbDevice.SelectedIndex = -1;
171 | }
172 | }
173 | }
174 | }
175 |
176 | public bool AllowConnectedSetFalse
177 | {
178 | get
179 | {
180 | return chkAllowSetConnectedFalse.Checked;
181 | }
182 | set
183 | {
184 | chkAllowSetConnectedFalse.Checked = value;
185 | }
186 | }
187 |
188 | public bool AllowConnectedSetTrue
189 | {
190 | get
191 | {
192 | return chkAllowSetConnectedTrue.Checked;
193 | }
194 | set
195 | {
196 | chkAllowSetConnectedTrue.Checked = value;
197 | }
198 | }
199 |
200 | public bool DevicesAreConnected
201 | {
202 | get
203 | {
204 | return devicesAreConnected;
205 | }
206 | set
207 | {
208 | devicesAreConnected = value;
209 | btnSetup.Enabled = !devicesAreConnected;
210 | }
211 | }
212 |
213 | public bool AllowConcurrentAccess
214 | {
215 | get
216 | {
217 | return ChkAllowConcurrentAccess.Checked;
218 | }
219 | set
220 | {
221 | ChkAllowConcurrentAccess.Checked = value;
222 | }
223 | }
224 | #endregion
225 |
226 | #region Event handlers
227 | private void CmbDeviceType_SelectedIndexChanged(object sender, EventArgs e)
228 | {
229 | try
230 | {
231 |
232 | //ServerForm.LogMessage(0, 0, 0, this.Name, "cmbDeviceType_Changed - Started");
233 | cmbDevice.Items.Clear();
234 |
235 | //ServerForm.LogMessage(0, 0, 0, this.Name, "cmbDeviceType_Changed - Setting selected index to -1");
236 | cmbDevice.SelectedIndex = -1;
237 |
238 | //ServerForm.LogMessage(0, 0, 0, this.Name, "cmbDeviceType_Changed - Resetting instance number");
239 | DeviceNumber = 0;
240 |
241 | if (cmbDeviceType.SelectedItem.ToString() == SharedConstants.DEVICE_NOT_CONFIGURED)
242 | {
243 | //ServerForm.LogMessage(0, 0, 0, this.Name, "cmbDeviceType_Changed - \"None\" device type selected");
244 | cmbDevice.Items.Clear();
245 | cmbDevice.SelectedIndex = -1;
246 | cmbDevice.ResetText();
247 | cmbDevice.Enabled = false;
248 | description = "";
249 | progID = SharedConstants.DEVICE_NOT_CONFIGURED;
250 |
251 | }
252 | else
253 | {
254 | cmbDevice.Enabled = true;
255 | //ServerForm.LogMessage(0, 0, 0, this.Name, "cmbDeviceType_Changed - Real device type has been selected");
256 | }
257 |
258 |
259 | if (recalculate)
260 | {
261 | setupForm.RecalculateDeviceNumbers();
262 | recalculate = false;
263 | }
264 |
265 | // Set up device list so we can translate ProgID to description
266 | if (cmbDeviceType.SelectedItem.ToString() != SharedConstants.DEVICE_NOT_CONFIGURED)
267 | {
268 | List installedDevices = Profile.GetDrivers(Devices.StringToDeviceType(cmbDeviceType.SelectedItem.ToString()));
269 | //ServerForm.LogMessage(0, 0, 0, this.Name, "cmbDeviceType_Changed - Created registered device array list");
270 |
271 | deviceDictionary.Clear();
272 | foreach (ASCOMRegistration kvp in installedDevices)
273 | {
274 | if (!deviceDictionary.ContainsKey(kvp.ProgID)) deviceDictionary.Add(kvp.ProgID, kvp.Name);
275 | cmbDevice.Items.Add(kvp.Name);
276 | }
277 | if (cmbDevice.Items.Count > 0) cmbDevice.SelectedIndex = 0;
278 | //ServerForm.LogMessage(0, 0, 0, this.Name, "cmbDeviceType_Changed - Finished");
279 | }
280 |
281 | }
282 | catch (Exception ex)
283 | {
284 | MessageBox.Show(ex.ToString());
285 | }
286 |
287 | }
288 |
289 | private void CmbDevice_SelectedIndexChanged(object sender, EventArgs e)
290 | {
291 | description = cmbDevice.SelectedItem.ToString();
292 | foreach (KeyValuePair kvp in deviceDictionary)
293 | {
294 | if (kvp.Value == description)
295 | {
296 | progID = kvp.Key;
297 | }
298 | }
299 | }
300 |
301 | private void CmbDeviceType_MouseUp(object sender, MouseEventArgs e)
302 | {
303 | recalculate = true;
304 | }
305 |
306 | ///
307 | /// Event handler to paint the device list combo box in the "DropDown" rather than "DropDownList" style
308 | ///
309 | /// Device to be painted
310 | /// Draw event arguments object
311 | public void ComboBox_DrawItem(object sender, DrawItemEventArgs e)
312 | {
313 | if (e.Index < 0) return;
314 |
315 | ComboBox combo = sender as ComboBox;
316 | if ((e.State & DrawItemState.Selected) == DrawItemState.Selected) // Draw the selected item in menu highlight colour
317 | {
318 | e.Graphics.FillRectangle(new SolidBrush(SystemColors.MenuHighlight), e.Bounds);
319 | e.Graphics.DrawString(combo.Items[e.Index].ToString(), e.Font, new SolidBrush(SystemColors.HighlightText), new Point(e.Bounds.X, e.Bounds.Y));
320 | }
321 | else
322 | {
323 | e.Graphics.FillRectangle(new SolidBrush(SystemColors.Window), e.Bounds);
324 | e.Graphics.DrawString(combo.Items[e.Index].ToString(), e.Font, new SolidBrush(combo.ForeColor), new Point(e.Bounds.X, e.Bounds.Y));
325 | }
326 |
327 | e.DrawFocusRectangle();
328 | }
329 |
330 | private void BtnSetup_Click(object sender, EventArgs e)
331 | {
332 | // This device's ProgID is held in the variable progID so try and run its SetupDialog method
333 | ServerForm.LogMessage(0, 0, 0, "Setup", $"Setup button pressed for device: {cmbDevice.Text}, ProgID: {progID}");
334 |
335 | try
336 | {
337 | // Get an instance of the driver from its ProgID and store this in a dynamic variable so that we can call its method directly
338 | Type ProgIdType = Type.GetTypeFromProgID(progID);
339 |
340 | dynamic oDrv = Activator.CreateInstance(ProgIdType);
341 |
342 | try
343 | {
344 | if (GetConnectdState(oDrv)) // Driver is connected and the Setup dialogue must be run with the device disconnected so ask whether we can disconnect it
345 | {
346 | DialogResult dialogResult = MessageBox.Show("Device is connected, OK to disconnect and run Setup?", "Disconnect Device?", MessageBoxButtons.OKCancel);
347 | if (dialogResult == DialogResult.OK) // OK to disconnect and run setup dialogue
348 | {
349 | try { oDrv.Connected = false; } catch { }; // Set Connected to false ignoring errors
350 | try { oDrv.Link = false; } catch { }; // Set Link to false (for IFocuserV1 devices) ignoring errors
351 |
352 | int RemainingObjectCount = Marshal.FinalReleaseComObject(oDrv);
353 |
354 | oDrv = null;
355 | oDrv = Activator.CreateInstance(ProgIdType);
356 |
357 | oDrv.SetupDialog();
358 |
359 | try
360 | {
361 | oDrv.Connected = true; // Try setting Connected to true
362 | }
363 | catch (Exception ex2) when (DeviceType.Equals("focuser", StringComparison.InvariantCultureIgnoreCase))
364 | {
365 | // Connected failed so try Link in case this is an IFocuserV1 device
366 | ServerForm.LogException(0, 0, 0, "Setup", $"Error setting Connected to true for focuser device {ProgID}, now trying Link for IFocuserV1 devices: \r\n{ex2}");
367 | oDrv.Link = true;
368 | }
369 | }
370 | else // Not OK to disconnect so just do nothing and exit
371 | {
372 | ServerForm.LogMessage(0, 0, 0, "Setup", "User did not give permission to disconnect device - no action taken");
373 | }
374 | }
375 | else // Driver is not connected
376 | {
377 | oDrv.SetupDialog();
378 |
379 | try { oDrv.Dispose(); } catch { }; // Dispose the driver if possible
380 |
381 | // Release the COM object properly
382 | try
383 | {
384 | //ServerForm.LogMessage(0, 0, 0, "Setup", " Releasing COM object");
385 | int LoopCount = 0;
386 | int RemainingObjectCount = 0;
387 |
388 | do
389 | {
390 | LoopCount += 1; // Increment the loop counter so that we don't go on for ever!
391 | RemainingObjectCount = Marshal.ReleaseComObject(oDrv);
392 | } while ((RemainingObjectCount > 0) & (LoopCount < 20));
393 | }
394 | catch (Exception ex2)
395 | {
396 | ServerForm.LogMessage(0, 0, 0, "Setup", $" ReleaseComObject Exception: {ex2.Message}");
397 | }
398 |
399 | oDrv = null;
400 | }
401 | }
402 | catch (Exception ex1)
403 | {
404 | string errMsg = $"Exception calling SetupDialog method: {ex1.Message}";
405 | MessageBox.Show(errMsg);
406 | ServerForm.LogMessage(0, 0, 0, "Setup", errMsg);
407 | ServerForm.LogException(0, 0, 0, "Setup", ex1.ToString());
408 | }
409 |
410 | }
411 | catch (Exception ex)
412 | {
413 | string errMsg = $"Exception creating driver {progID} - {ex.Message}";
414 | MessageBox.Show(errMsg);
415 | ServerForm.LogMessage(0, 0, 0, "Setup", errMsg);
416 | ServerForm.LogException(0, 0, 0, "Setup", ex.ToString());
417 | }
418 | }
419 |
420 | #endregion
421 |
422 | #region Support code
423 | private static bool GetConnectdState(dynamic driverObject)
424 | {
425 | bool connectedState;
426 |
427 | try
428 | {
429 | connectedState = driverObject.Connected;
430 | }
431 | catch
432 | {
433 | connectedState = driverObject.Link;
434 | }
435 |
436 | return connectedState;
437 | }
438 | #endregion
439 | }
440 | }
441 |
--------------------------------------------------------------------------------
/Remote Server/Settings.cs:
--------------------------------------------------------------------------------
1 | namespace ASCOM.Remote
2 | {
3 | internal class Settings
4 | {
5 | // Current version number for this settings class. Only needs to be incremented when there are breaking changes!
6 | // For example this can be left at its current level when adding new settings that have usable default values.
7 |
8 | // This value is set when values are actually persisted in ConformConfiguration.PersistSettings in order not to overwrite the value that is retrieved from the current settings file when it is read.
9 | internal const int SETTINGS_COMPATIBILTY_VERSION = 1;
10 |
11 | public int SettingsCompatibilityVersion { get; set; } = SETTINGS_COMPATIBILTY_VERSION; // Default is zero so that versions prior to introduction of the settings compatibility version number can be detected.
12 |
13 | public bool RunAs64Bit { get; set; } = false;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Remote Server/Shared Constants.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Win32;
2 |
3 | namespace ASCOM.Remote
4 | {
5 | public static class SharedConstants
6 | {
7 | // Alpaca and ASCOM error number constants
8 | public const int ASCOM_ERROR_NUMBER_OFFSET = unchecked((int)0x80040000); // Offset value that relates the ASCOM Alpaca reserved error number range to the ASCOM COM HResult error number range
9 | public const int ASCOM_ERROR_NUMBER_BASE = unchecked((int)0x80040400); // Lowest ASCOM error number
10 | public const int ASCOM_ERROR_NUMBER_MAX = unchecked((int)0x80040FFF); // Highest ASCOM error number
11 | public const int ALPACA_ERROR_CODE_BASE = 0x400; // Start of the Alpaca error code range 0x400 to 0xFFF
12 | public const int ALPACA_ERROR_CODE_MAX = 0xFFF; // End of Alpaca error code range 0x400 to 0xFFF
13 |
14 | // Device API URL element positions /api/v1/telescope/0/method
15 | public const int URL_ELEMENT_API = 0; // For /api/ URIs
16 | public const int URL_ELEMENT_API_VERSION = 1;
17 | public const int URL_ELEMENT_DEVICE_TYPE = 2;
18 | public const int URL_ELEMENT_DEVICE_NUMBER = 3;
19 | public const int URL_ELEMENT_METHOD = 4;
20 | public const int URL_ELEMENT_SERVER_COMMAND = 2; // For /server/ type URIs
21 |
22 | // Regular expressions to validate IP addresses and host names
23 | public const string ValidIpAddressRegex = @"^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$";
24 | public const string ValidHostnameRegex = @"^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$";
25 |
26 | // HTTP Parameter names shared by driver and remote server
27 | public const string RA_PARAMETER_NAME = "RightAscension";
28 | public const string DEC_PARAMETER_NAME = "Declination";
29 | public const string ALT_PARAMETER_NAME = "Altitude";
30 | public const string AZ_PARAMETER_NAME = "Azimuth";
31 | public const string AXIS_PARAMETER_NAME = "Axis";
32 | public const string RATE_PARAMETER_NAME = "Rate";
33 | public const string DIRECTION_PARAMETER_NAME = "Direction";
34 | public const string DURATION_PARAMETER_NAME = "Duration";
35 | public const string CLIENT_ID_PARAMETER_NAME = "ClientID";
36 | public const string CLIENT_TRANSACTION_ID_PARAMETER_NAME = "ClientTransactionID";
37 | public const string COMMAND_PARAMETER_NAME = "Command";
38 | public const string RAW_PARAMETER_NAME = "Raw";
39 | public const string LIGHT_PARAMETER_NAME = "Light";
40 | public const string ACTION_COMMAND_PARAMETER_NAME = "Action";
41 | public const string ACTION_PARAMETERS_PARAMETER_NAME = "Parameters";
42 | public const string ID_PARAMETER_NAME = "Id";
43 | public const string STATE_PARAMETER_NAME = "State";
44 | public const string NAME_PARAMETER_NAME = "Name";
45 | public const string VALUE_PARAMETER_NAME = "Value";
46 | public const string POSITION_PARAMETER_NAME = "Position";
47 | public const string SIDEOFPIER_PARAMETER_NAME = "SideOfPier";
48 | public const string UTCDATE_PARAMETER_NAME = "UTCDate";
49 | public const string SENSORNAME_PARAMETER_NAME = "SensorName";
50 | public const string BRIGHTNESS_PARAMETER_NAME = "Brightness";
51 |
52 | public const string ISO8601_DATE_FORMAT_STRING = "yyyy-MM-ddTHH:mm:ss.fffffff";
53 |
54 | // Remote client configuration constants
55 | public const int SOCKET_ERROR_MAXIMUM_RETRIES = 2; // The number of retries that the client will make when it receives a socket actively refused error from the remote server
56 | public const int SOCKET_ERROR_RETRY_DELAY_TIME = 1000; // The delay time (milliseconds) between socket actively refused retries
57 |
58 | // Remote server setup form constants
59 | public const string LOCALHOST_NAME_IPV4 = "localhost";
60 | public const string LOCALHOST_ADDRESS_IPV4 = "127.0.0.1"; // Get the localhost loop back address
61 | public const string LOCALHOST_ADDRESS_IPV6 = "[::1]"; // Get the localhost loop back address
62 | public const string BIND_TO_ALL_INTERFACES_DESCRIPTION = "All IP Addresses"; // Text describing requirement to bind to all interfaces
63 | public const string BIND_TO_ALL_INTERFACES_IP_ADDRESS_STRONG = "+"; // IP address value that causes binding to all available IP addresses
64 | public const string BIND_TO_ALL_INTERFACES_IP_ADDRESS_WEAK = "*"; // IP address value that causes binding to all available IP addresses
65 |
66 | // Constants shared by Remote Client Drivers and the ASCOM Remote Server
67 | public const string API_URL_BASE = "/api/"; // This constant must always be lower case to make the logic tests work properly
68 | public const string API_VERSION_V1 = "v1"; // This constant must always be lower case to make the logic tests work properly
69 | public static readonly int[] MANAGEMENT_SUPPORTED_INTERFACE_VERSIONS = [1]; // Array of supported interface versions that is returned through the management API
70 | public const string REMOTE_SERVER_MANAGEMENT_URL_BASE = "/server/"; // Management commands unique to the remote server. This constant must always be lower case to make the logic tests work properly
71 | public const string ALPACA_DEVICE_MANAGEMENT_URL_BASE = "/management/"; // management commands common to all Alpaca devices. This constant must always be lower case to make the logic tests work properly
72 | public const string ALPACA_DEVICE_SETUP_URL_BASE = "/setup/"; // management commands common to all Alpaca devices. This constant must always be lower case to make the logic tests work properly
73 |
74 | // Remote server management API interface constants
75 | public const string REMOTE_SERVER_MANGEMENT_GET_PROFILE = "profile";
76 | public const string REMOTE_SERVER_MANGEMENT_GET_CONFIGURATION = "configuration";
77 | public const string REMOTE_SERVER_MANGEMENT_GET_CONCURRENT_CALLS = "concurrency";
78 | public const string REMOTE_SERVER_MANGEMENT_RESTART_SERVER = "restart";
79 | public const string REMOTE_SERVER_MANGEMENT_REBOOT_SERVER = "reboot";
80 | public const string REMOTE_SERVER_MANGEMENT_SHUTDOWN_SERVER = "shutdown";
81 | public const string ALPACA_DEVICE_MANAGEMENT_APIVERSIONS = "apiversions";
82 | public const string ALPACA_DEVICE_MANAGEMENT_DESCRIPTION = "description";
83 | public const string ALPACA_DEVICE_MANAGEMENT_CONFIGURED_DEVICES = "configureddevices";
84 | public const string ALPACA_DEVICE_MANAGEMENT_MANUFACTURER = "Peter Simpson";
85 | public const string ALPACA_DEVICE_MANAGEMENT_SERVERNAME = "ASCOM Remote Server";
86 |
87 | // Remote server browser interface URL constants
88 | public const string BROWSER_URL_SETUP = "setup";
89 |
90 | // Constants used to set network permissions
91 | public const string SET_NETWORK_PERMISSIONS_EXE_PATH = @"\ASCOM\RemoteServer\SetNetworkPermissions\ASCOM.SetNetworkPermissions.exe"; //Relative path of the SetNetworkPermissions exe from C:\Program Files (or x86 on 64bit OS). Must match the location where the installer puts the exe!
92 | public const string ENABLE_REMOTE_SERVER_MANAGEMENT_URI_COMMAND_NAME = "setremoteservermanagementuriacl";
93 | public const string ENABLE_ALPACA_DEVICE_MANAGEMENT_URI_COMMAND_NAME = "setalpacamanagementurl";
94 | public const string ENABLE_ALPACA_SETUP_URI_COMMAND_NAME = "setalpacasetupurl";
95 | public const string ENABLE_API_URI_COMMAND_NAME = "setapiuriacl";
96 | public const string ENABLE_HTTP_DOT_SYS_PORT_COMMAND_NAME = "enablehttpdotsysport";
97 | public const string SET_LOCAL_SERVER_PATH_COMMAND_NAME = "localserverpath";
98 | public const string SET_REMOTE_SERVER_PATH_COMMAND_NAME = "remoteserverpath";
99 | public const string USER_NAME_COMMAND_NAME = "username";
100 |
101 | // Client driver profile persistence constants
102 | public const string TRACE_LEVEL_PROFILENAME = "Trace Level"; public const bool CLIENT_TRACE_LEVEL_DEFAULT = true;
103 | public const string DEBUG_TRACE_PROFILENAME = "Include Debug Trace"; public const bool DEBUG_TRACE_DEFAULT = false;
104 | public const string IPADDRESS_PROFILENAME = "IP Address"; public const string IPADDRESS_DEFAULT = SharedConstants.LOCALHOST_ADDRESS_IPV4;
105 | public const string PORTNUMBER_PROFILENAME = "Port Number"; public const decimal PORTNUMBER_DEFAULT = 11111;
106 | public const string REMOTE_DEVICE_NUMBER_PROFILENAME = "Remote Device Number"; public const decimal REMOTE_DEVICE_NUMBER_DEFAULT = 0;
107 | public const string SERVICE_TYPE_PROFILENAME = "Service Type"; public const string SERVICE_TYPE_DEFAULT = "http";
108 | public const string ESTABLISH_CONNECTION_TIMEOUT_PROFILENAME = "Establish Connection Timeout"; public const int ESTABLISH_CONNECTION_TIMEOUT_DEFAULT = 10;
109 | public const string STANDARD_SERVER_RESPONSE_TIMEOUT_PROFILENAME = "Standard Server Response Timeout"; public const int STANDARD_SERVER_RESPONSE_TIMEOUT_DEFAULT = 10;
110 | public const string LONG_SERVER_RESPONSE_TIMEOUT_PROFILENAME = "Long Server Response Timeout"; public const int LONG_SERVER_RESPONSE_TIMEOUT_DEFAULT = 120;
111 | public const string USERNAME_PROFILENAME = "User Name"; public const string USERNAME_DEFAULT = "";
112 | public const string PASSWORD_PROFILENAME = "Password"; public const string PASSWORD_DEFAULT = "";
113 | public const string MANAGE_CONNECT_LOCALLY_PROFILENAME = "Manage Connect Locally"; public const bool MANAGE_CONNECT_LOCALLY_DEFAULT = false;
114 | public const string IMAGE_ARRAY_TRANSFER_TYPE_PROFILENAME = "Image Array Transfer Type"; public const ImageArrayTransferType IMAGE_ARRAY_TRANSFER_TYPE_DEFAULT = DEFAULT_IMAGE_ARRAY_TRANSFER_TYPE;
115 | public const string IMAGE_ARRAY_COMPRESSION_PROFILENAME = "Image Array Compression"; public const ImageArrayCompression IMAGE_ARRAY_COMPRESSION_DEFAULT = DEFAULT_IMAGE_ARRAY_COMPRESSION;
116 |
117 | // Driver naming constants
118 | public const string DRIVER_DISPLAY_NAME = "ASCOM Remote Client";
119 | public const string DRIVER_PROGID_BASE = "ASCOM.Remote";
120 | public const string NOT_CONNECTED_MESSAGE = "is not connected."; // This is appended to the driver display name + driver number and displayed when the driver is not connected
121 | public const string TRACELOGGER_NAME_FORMAT_STRING = "Remote{0}.{1}";
122 |
123 | // Enum to describe Camera.ImageArray and ImageArrayVCariant array types
124 | public enum ImageArrayElementTypes
125 | {
126 | Unknown = 0,
127 | Int16 = 1,
128 | Int32 = 2,
129 | Double = 3,
130 | Single = 4,
131 | Byte = 5,
132 | Int64 = 6
133 | }
134 |
135 | // Enum used by the remote client to indicate what type of Alpaca image array transfer should be used
136 | public enum ImageArrayTransferType
137 | {
138 | JSON = 0,
139 | Base64HandOff = 1,
140 | }
141 |
142 | // Enum used by the remote client to indicate what type of compression should be used in Alpaca responses
143 | public enum ImageArrayCompression
144 | {
145 | None = 0,
146 | Deflate = 1,
147 | GZip = 2,
148 | GZipOrDeflate = 3
149 | }
150 |
151 | // Default image array transfer constants
152 | public const ImageArrayCompression DEFAULT_IMAGE_ARRAY_COMPRESSION = ImageArrayCompression.None;
153 | public const ImageArrayTransferType DEFAULT_IMAGE_ARRAY_TRANSFER_TYPE = ImageArrayTransferType.JSON;
154 |
155 | // Image array base64 hand-off support constants
156 | public const string BASE64_HANDOFF_HEADER = "base64handoff"; // Name of HTTP header used to affirm binary serialisation support for image array data
157 | public const string BASE64_HANDOFF_SUPPORTED = "true"; // Value of HTTP header to indicate support for binary serialised image array data
158 | public const string BASE64_HANDOFF_FILE_DOWNLOAD_URI_EXTENSION = "base64"; // Addition to the ImageArray and ImageArrayVariant method names from which base64 serialised image files can be downloaded
159 |
160 | // Image bytes constants
161 | public const string ACCEPT_HEADER_NAME = "Accept"; // Name of HTTP header used to affirm ImageBytes support for image array data
162 | public const string IMAGE_BYTES_MIME_TYPE = "application/imagebytes";
163 |
164 | // Registry key where the Web Server configuration will be stored
165 | public const RegistryHive ASCOM_REMOTE_CONFIGURATION_HIVE = RegistryHive.CurrentUser;
166 | public const string ASCOM_REMOTE_CONFIGURATION_KEY = @"Software\ASCOM Remote";
167 |
168 | public const string REQUEST_RECEIVED_STRING = "RequestReceived";
169 |
170 | public const string DEVICE_NOT_CONFIGURED = "None"; // ProgID / UniqueID / device type value indicating no device configured
171 |
172 | public const string CORS_DEFAULT_PERMISSION = "*"; // Default permission for CORS origins (The * value means "permit all origins")
173 | public const string CORS_SERIALISATION_SEPARATOR = "|";
174 |
175 | // Alpaca discovery constants
176 | public const string ALPACA_DISCOVERY_BROADCAST_ID = "alpacadiscovery";
177 | public const int ALPACA_DISCOVERY_PORT = 32227;
178 | public const string ALPACA_DISCOVERY_RESPONSE_STRING = "alpacaport";
179 | public const string ALPACA_DISCOVERY_MULTICAST_GROUP = "ff12::a1:9aca";
180 |
181 | }
182 | }
183 |
--------------------------------------------------------------------------------
/Remote Server/SharedResources.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace ASCOM.Remote
4 | {
5 | public static class Library
6 | {
7 | ///
8 | /// Convert 3D 32bit Integer array to double array
9 | ///
10 | /// 32bit integer array to be converted
11 | /// 3D double array containing the integer values
12 | public static double[,] Array2DToDouble(Array inputArray)
13 | {
14 | double[,] outputArray = new double[inputArray.GetLength(0), inputArray.GetLength(1)];
15 |
16 | for (int j = 0; j <= inputArray.GetUpperBound(1); j++)
17 | {
18 | for (int i = 0; i <= inputArray.GetUpperBound(0); i++)
19 | {
20 | outputArray[i, j] = Convert.ToDouble(inputArray.GetValue(i, j));
21 | }
22 | }
23 | return outputArray;
24 | }
25 |
26 | ///
27 | /// Convert 3D array to double array
28 | ///
29 | /// 32bit integer array to be converted
30 | /// 3D double array containing the integer values
31 | public static double[,,] Array3DToDouble(Array inputArray)
32 | {
33 | double[,,] outputArray = new double[inputArray.GetLength(0), inputArray.GetLength(1), inputArray.GetLength(2)];
34 |
35 | for (int k = 0; k <= inputArray.GetUpperBound(2); k++)
36 | {
37 | for (int j = 0; j <= inputArray.GetUpperBound(1); j++)
38 | {
39 | for (int i = 0; i <= inputArray.GetUpperBound(0); i++)
40 | {
41 | outputArray[i, j, k] = Convert.ToDouble(inputArray.GetValue(i, j, k));
42 | }
43 | }
44 | }
45 | return outputArray;
46 | }
47 |
48 | ///
49 | /// Convert 3D 32bit Integer array to double array
50 | ///
51 | /// 32bit integer array to be converted
52 | /// 3D double array containing the integer values
53 | public static int[,] Array2DToInt(Array inputArray)
54 | {
55 | int[,] outputArray = new int[inputArray.GetLength(0), inputArray.GetLength(1)];
56 |
57 | for (int j = 0; j <= inputArray.GetUpperBound(1); j++)
58 | {
59 | for (int i = 0; i <= inputArray.GetUpperBound(0); i++)
60 | {
61 | outputArray[i, j] = Convert.ToInt32(inputArray.GetValue(i, j));
62 | }
63 | }
64 | return outputArray;
65 | }
66 |
67 | ///
68 | /// Convert 3D array to double array
69 | ///
70 | /// 32bit integer array to be converted
71 | /// 3D double array containing the integer values
72 | public static int[,,] Array3DToInt(Array inputArray)
73 | {
74 | int[,,] outputArray = new int[inputArray.GetLength(0), inputArray.GetLength(1), inputArray.GetLength(2)];
75 |
76 | for (int k = 0; k <= inputArray.GetUpperBound(2); k++)
77 | {
78 | for (int j = 0; j <= inputArray.GetUpperBound(1); j++)
79 | {
80 | for (int i = 0; i <= inputArray.GetUpperBound(0); i++)
81 | {
82 | outputArray[i, j, k] = Convert.ToInt32(inputArray.GetValue(i, j, k));
83 | }
84 | }
85 | }
86 | return outputArray;
87 | }
88 |
89 | ///
90 | /// Convert 3D 32bit Integer array to double array
91 | ///
92 | /// 32bit integer array to be converted
93 | /// 3D double array containing the integer values
94 | public static short[,] Array2DToShort(Array inputArray)
95 | {
96 | short[,] outputArray = new short[inputArray.GetLength(0), inputArray.GetLength(1)];
97 |
98 | for (int j = 0; j <= inputArray.GetUpperBound(1); j++)
99 | {
100 | for (int i = 0; i <= inputArray.GetUpperBound(0); i++)
101 | {
102 | outputArray[i, j] = Convert.ToInt16(inputArray.GetValue(i, j));
103 | }
104 | }
105 | return outputArray;
106 | }
107 |
108 | ///
109 | /// Convert 3D array to double array
110 | ///
111 | /// 32bit integer array to be converted
112 | /// 3D double array containing the integer values
113 | public static short[,,] Array3DToShort(Array inputArray)
114 | {
115 | short[,,] outputArray = new short[inputArray.GetLength(0), inputArray.GetLength(1), inputArray.GetLength(2)];
116 |
117 | for (int k = 0; k <= inputArray.GetUpperBound(2); k++)
118 | {
119 | for (int j = 0; j <= inputArray.GetUpperBound(1); j++)
120 | {
121 | for (int i = 0; i <= inputArray.GetUpperBound(0); i++)
122 | {
123 | outputArray[i, j, k] = Convert.ToInt16(inputArray.GetValue(i, j, k));
124 | }
125 | }
126 | }
127 | return outputArray;
128 | }
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/Remote Server/StringValue.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 |
3 | namespace ASCOM.Remote
4 | {
5 | ///
6 | /// Class to hold a string value for use with the data grid view control.
7 | /// This is required in order for the data grid view control to be able to bind to a List variable
8 | /// String values are trimmed to ensure that searches for the "*" wild card character succeed even if the user pre or postpends spaces when entering the value.
9 | ///
10 | public class StringValue(string s)
11 | {
12 | string stringValue = s.Trim();
13 |
14 | [DisplayName("Permitted CORS Origins")]
15 | public string Value
16 | {
17 | get // Return the string value
18 | {
19 | return stringValue;
20 | }
21 | set // Set the string value, trimming it first
22 | {
23 | stringValue = value.Trim();
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Remote Server/Updates/GitHubReleases.cs:
--------------------------------------------------------------------------------
1 | using Octokit;
2 | using Semver;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 |
8 | namespace ASCOM.Remote
9 | {
10 | public static class GitHubReleases
11 | {
12 | public static Task> GetReleases(string owner, string name)
13 | {
14 | if (string.IsNullOrEmpty(owner))
15 | {
16 | throw new ArgumentNullException(nameof(owner));
17 | }
18 |
19 | if (string.IsNullOrEmpty(name))
20 | {
21 | throw new ArgumentNullException(nameof(name));
22 | }
23 |
24 | var Github = new GitHubClient(new ProductHeaderValue(name + @"-UpdateCheck"));
25 |
26 | return Github.Repository.Release.GetAll(owner, name);
27 | }
28 |
29 | public static Release LatestRelease(this IEnumerable releases)
30 | {
31 | ArgumentNullException.ThrowIfNull(releases);
32 | return releases.Where(rp => !rp.Prerelease).Latest();
33 | }
34 |
35 | public static Release LatestPrerelease(this IEnumerable releases)
36 | {
37 | ArgumentNullException.ThrowIfNull(releases);
38 | return releases.Where(rp => rp.Prerelease).Latest();
39 |
40 | }
41 |
42 | public static Release Latest(this IEnumerable releases)
43 | {
44 | ArgumentNullException.ThrowIfNull(releases);
45 | if (releases.Any())
46 | {
47 | return releases.OrderBy(rp => rp.ReleaseSemVersionFromTag()).LastOrDefault();
48 | }
49 | return null;
50 | }
51 |
52 | public static SemVersion ReleaseSemVersionFromTag(this Release release)
53 | {
54 | ArgumentNullException.ThrowIfNull(release);
55 | if (!string.IsNullOrEmpty(release.TagName) && SemVersion.TryParse(release.TagName, SemVersionStyles.AllowV, out SemVersion _latest_release_version))
56 | {
57 | return _latest_release_version;
58 | }
59 | return SemVersion.ParsedFrom(0, 0, 0, release.TagName ?? "No Tag");
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/Remote Server/Updates/Updates.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | using Semver;
5 | using System.Reflection;
6 | using System.Threading.Tasks;
7 | using Octokit;
8 |
9 | namespace ASCOM.Remote
10 | {
11 | internal class Updates
12 | {
13 | #region Internal properties
14 |
15 | ///
16 | /// True if a newer release verison is available
17 | ///
18 | internal static bool HasNewerRelease { get; set; }
19 |
20 | ///
21 | /// Latest release name
22 | ///
23 | internal static string LatestReleaseName { get; set; } = "";
24 | ///
25 | /// Latest release version
26 | ///
27 | internal static string LatestReleaseVersion { get; set; } = "";
28 |
29 | ///
30 | /// Download URL for the latest release version
31 | ///
32 | internal static string ReleaseUrl { get; set; }
33 |
34 | ///
35 | /// True if a new preview version is available
36 | ///
37 | internal static bool HasNewerPreview { get; set; }
38 |
39 | ///
40 | /// Latest preview version
41 | ///
42 | internal static string LatestPreviewName { get; set; } = "";
43 |
44 | ///
45 | /// Latest preview version
46 | ///
47 | internal static string LatestPreviewVersion { get; set; } = "";
48 |
49 | ///
50 | /// Download URL for the latest preview version
51 | ///
52 | internal static string PreviewURL { get; set; } = "";
53 |
54 | ///
55 | /// True if the client is running the latest release version
56 | ///
57 | internal static bool UpToDate { get; set; }
58 |
59 | ///
60 | /// True if the client has a version that is ahead of the latest preview release
61 | ///
62 | internal static bool AheadOfPreview { get; set; } = false;
63 |
64 | ///
65 | /// True if the client has a version that is ahead of the latest main release
66 | ///
67 | internal static bool AheadOfRelease { get; set; } = false;
68 |
69 | ///
70 | /// True if some releases have been retrieved from GitHub
71 | ///
72 | internal static bool HasReleases { get => Releases.Count > 0; }
73 |
74 | ///
75 | /// List of releases
76 | ///
77 | internal static IReadOnlyList Releases { get; set; } = new List(); //null;
78 |
79 | internal static string AscomRemoteVersion => $"{Assembly.GetEntryAssembly().GetCustomAttribute().InformationalVersion}";
80 |
81 | internal static string AscomRemoteVersionDisplayString
82 | {
83 | get
84 | {
85 | string informationalVersion = Assembly.GetEntryAssembly().GetCustomAttribute().InformationalVersion;
86 | string shortGitId = $"{Assembly.GetEntryAssembly().GetCustomAttribute().Value}";
87 |
88 | SemVersion.TryParse(informationalVersion, SemVersionStyles.AllowV, out SemVersion semver);
89 | if (semver is not null)
90 | return $"{semver.Major}.{semver.Minor}.{semver.Patch}{(semver.Prerelease == "" ? "" : "-")}{semver.Prerelease} (Build {shortGitId})";
91 | else
92 | return $" Bad informational version string: ##{informationalVersion}##";
93 | }
94 | }
95 | #endregion
96 |
97 | #region Internal methods
98 |
99 | internal static async Task> GetReleases()
100 | {
101 | try
102 | {
103 | LogDebug("GetReleases", "Getting release details");
104 | Releases = await GitHubReleases.GetReleases("ASCOMInitiative", "ASCOMRemote");
105 | SetProperties();
106 | LogDebug("GetReleases", $"Found {Releases.Count} releases");
107 |
108 | foreach (Octokit.Release release in Releases)
109 | {
110 | LogDebug("CheckForUpdatesSync", $"Found release: {release.Name}, ReleaseSemVersionFromTag: {release.ReleaseSemVersionFromTag()}, Published on: {release.PublishedAt.GetValueOrDefault()}, Major: {release.ReleaseSemVersionFromTag().Major}, Minor: {release.ReleaseSemVersionFromTag().Minor}, Patch: {release.ReleaseSemVersionFromTag().Patch}, Pre-release: {release.Prerelease}");
111 | }
112 |
113 | return Releases;
114 | }
115 | catch (Exception ex)
116 | {
117 | LogDebug("GetReleases", $"Exception: {ex}");
118 | throw;
119 | }
120 | }
121 |
122 | internal async static Task CheckForUpdates()
123 | {
124 | try
125 | {
126 | LogDebug("CheckForUpdates", "Getting release details");
127 | Releases = await Task.Run(() => { return GitHubReleases.GetReleases("ASCOMInitiative", "ASCOMRemote"); });
128 | SetProperties();
129 | LogDebug("CheckForUpdates", $"Found {Releases.Count} releases");
130 |
131 | foreach (Octokit.Release release in Releases)
132 | {
133 | LogDebug("CheckForUpdates", $"Found release: {release.Name}, ReleaseSemVersionFromTag: {release.ReleaseSemVersionFromTag()}, Published on: {release.PublishedAt.GetValueOrDefault()}, Major: {release.ReleaseSemVersionFromTag().Major}, Minor: {release.ReleaseSemVersionFromTag().Minor}, Patch: {release.ReleaseSemVersionFromTag().Patch}, Pre-release: {release.Prerelease}");
134 | }
135 | }
136 | catch (Exception ex)
137 | {
138 | LogDebug("CheckForUpdates", $"Exception: {ex}");
139 | throw;
140 | }
141 | }
142 |
143 | internal static bool UpdateAvailable()
144 | {
145 | try
146 | {
147 | if (Releases != null)
148 | {
149 | if (Releases.Count > 0)
150 | {
151 | if (SemVersion.TryParse(Updates.AscomRemoteVersion, SemVersionStyles.AllowV, out SemVersion currentversion))
152 | {
153 | LogDebug("UpdateAvailable", $"Application semver - Major: {currentversion.Major}, Minor: {currentversion.Minor}, Patch: {currentversion.Patch}, Pre-release: {currentversion.Prerelease}, Metadata: {currentversion.Metadata}");
154 | Octokit.Release Release = Releases?.Latest();
155 |
156 | if (Release != null)
157 | {
158 | if (SemVersion.TryParse(Release.TagName, SemVersionStyles.AllowV, out SemVersion latestrelease))
159 | {
160 | LogDebug("UpdateAvailable", $"Found release semver - Major: {latestrelease.Major}, Minor: {latestrelease.Minor}, Patch: {latestrelease.Patch}, Pre-release: {latestrelease.Prerelease}, Metadata: {latestrelease.Metadata}");
161 | return SemVersion.ComparePrecedence(currentversion, latestrelease) == -1;
162 | }
163 | }
164 | }
165 | else
166 | {
167 | throw new InvalidValueException($"The informational product version set in the project file is not a valid SEMVER string: {Updates.AscomRemoteVersion}");
168 | }
169 | }
170 | }
171 | }
172 | catch (Exception ex)
173 | {
174 | LogDebug("UpdateAvailable", $"Exception: {ex}");
175 | }
176 | return false;
177 | }
178 |
179 | #endregion
180 |
181 | #region Support code
182 | ///
183 | /// Set properties according to the releases returned
184 | ///
185 | /// ConfgormLogger instance to record operational messages
186 | private static void SetProperties()
187 | {
188 | try
189 | {
190 | LogDebug("SetProperties", $"Running...");
191 | if (SemVersion.TryParse(Updates.AscomRemoteVersion, SemVersionStyles.AllowV, out SemVersion installedVersion))
192 | {
193 | LogDebug("SetProperties", $"Installed version: {installedVersion}");
194 |
195 | Release latestRelease = Updates.Releases?.LatestRelease();
196 | Release latestPreRelease = Updates.Releases?.LatestPrerelease();
197 | if ((latestRelease is not null) & (latestPreRelease is not null))
198 | {
199 |
200 | bool latesOk = SemVersion.TryParse(latestRelease.TagName, SemVersionStyles.AllowV, out SemVersion latestVersion);
201 |
202 | bool latestPreOk = SemVersion.TryParse(latestPreRelease.TagName, SemVersionStyles.AllowV, out SemVersion latestPreReleaseVersion);
203 |
204 | LogDebug("SetProperties", $"latestrelease: {latestVersion}, latestprerelease: {latestPreReleaseVersion}");
205 |
206 | if ((SemVersion.ComparePrecedence(installedVersion, latestVersion) == 0) || (SemVersion.ComparePrecedence(installedVersion, latestPreReleaseVersion) == 0))
207 | {
208 | UpToDate = true;
209 | }
210 |
211 | if (latestVersion != null)
212 | {
213 | if (SemVersion.ComparePrecedence(installedVersion, latestVersion) == -1) //(installedRelease < latestrelease)
214 | {
215 | HasNewerRelease = true;
216 | LatestReleaseVersion = latestRelease.TagName;
217 | LatestReleaseName = latestRelease.Name;
218 | ReleaseUrl = latestRelease.HtmlUrl;
219 | }
220 |
221 | if (SemVersion.ComparePrecedence(installedVersion, latestVersion) == 1) //(installedRelease > latestrelease)
222 | {
223 | LogDebug("SetProperties", $"Setting AheadOfRelease True");
224 | AheadOfRelease = true;
225 | }
226 | }
227 | else
228 | {
229 | latestVersion = new SemVersion(0);
230 | }
231 |
232 | if (latestPreReleaseVersion != null)
233 | {
234 | LogDebug("SetProperties", $"(SemVersion.ComparePrecedence(installedVersion, latestPreReleaseVersion) == -1) && (SemVersion.ComparePrecedence(latestVersion, latestPreReleaseVersion) == -1): {(SemVersion.ComparePrecedence(installedVersion, latestPreReleaseVersion) == -1) && (SemVersion.ComparePrecedence(latestVersion, latestPreReleaseVersion) == -1)}");
235 | if ((SemVersion.ComparePrecedence(installedVersion, latestPreReleaseVersion) == -1) && (SemVersion.ComparePrecedence(latestVersion, latestPreReleaseVersion) == -1)) //installedVersion < latestPreReleaseVersion && latestVersion < latestPreReleaseVersion
236 | {
237 | HasNewerPreview = true;
238 | LatestPreviewVersion = latestPreRelease.TagName;
239 | LatestPreviewName = latestPreRelease.Name;
240 | PreviewURL = latestPreRelease.HtmlUrl;
241 | }
242 |
243 | LogDebug("SetProperties", $"(SemVersion.ComparePrecedence(installedVersion, latestPreReleaseVersion) == -1) && (SemVersion.ComparePrecedence(latestVersion, latestPreReleaseVersion) == 1): {(SemVersion.ComparePrecedence(installedVersion, latestPreReleaseVersion) == 1) && (SemVersion.ComparePrecedence(latestVersion, latestPreReleaseVersion) == -1)}");
244 | if ((SemVersion.ComparePrecedence(installedVersion, latestPreReleaseVersion) == 1) && (SemVersion.ComparePrecedence(latestVersion, latestPreReleaseVersion) == -1)) //(installedVersion > latestPreReleaseVersion && latestVersion < latestPreReleaseVersion)
245 | {
246 | AheadOfPreview = true;
247 | }
248 | }
249 | LogDebug("SetProperties", $"UpToDate: {UpToDate}, HasNewerRelease: {HasNewerRelease}, HasNewerPreview: {HasNewerPreview}, AheadOfPreview: {AheadOfPreview}, LatestVersion: {LatestReleaseVersion}, URL: {ReleaseUrl}, LatestPreviewVersion: {LatestPreviewVersion}, PreviewURL: {PreviewURL}");
250 | }
251 | }
252 | else
253 | {
254 | LogDebug("SetProperties", $"Failed to parse {Updates.AscomRemoteVersion}");
255 | }
256 | }
257 | catch (Exception ex)
258 | {
259 | LogDebug("SetProperties", $"Exception: {ex}");
260 | }
261 | }
262 |
263 | static void LogDebug(string prefix, string message)
264 | {
265 | if (ServerForm.DebugTraceState)
266 | ServerForm.LogMessage(0, 0, 0, $"* {prefix}", message);
267 | }
268 |
269 | #endregion
270 | }
271 | }
272 |
--------------------------------------------------------------------------------
/Remote Server/ascomicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ASCOMInitiative/ASCOMRemote/e4d60019d54692a0dafd788895d1dde6a778a28e/Remote Server/ascomicon.ico
--------------------------------------------------------------------------------
/Remote Server/servedDevice.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace ASCOM.Remote
2 | {
3 | partial class ServedDevice
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Component Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | cmbDeviceType = new System.Windows.Forms.ComboBox();
32 | txtDeviceNumber = new System.Windows.Forms.TextBox();
33 | cmbDevice = new System.Windows.Forms.ComboBox();
34 | chkAllowSetConnectedTrue = new System.Windows.Forms.CheckBox();
35 | chkAllowSetConnectedFalse = new System.Windows.Forms.CheckBox();
36 | btnSetup = new System.Windows.Forms.Button();
37 | ChkAllowConcurrentAccess = new System.Windows.Forms.CheckBox();
38 | SuspendLayout();
39 | //
40 | // cmbDeviceType
41 | //
42 | cmbDeviceType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
43 | cmbDeviceType.FormattingEnabled = true;
44 | cmbDeviceType.Location = new System.Drawing.Point(0, 1);
45 | cmbDeviceType.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
46 | cmbDeviceType.Name = "cmbDeviceType";
47 | cmbDeviceType.Size = new System.Drawing.Size(192, 23);
48 | cmbDeviceType.TabIndex = 0;
49 | cmbDeviceType.SelectedIndexChanged += CmbDeviceType_SelectedIndexChanged;
50 | //
51 | // txtDeviceNumber
52 | //
53 | txtDeviceNumber.BackColor = System.Drawing.SystemColors.Window;
54 | txtDeviceNumber.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
55 | txtDeviceNumber.Location = new System.Drawing.Point(233, 1);
56 | txtDeviceNumber.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
57 | txtDeviceNumber.Name = "txtDeviceNumber";
58 | txtDeviceNumber.ReadOnly = true;
59 | txtDeviceNumber.Size = new System.Drawing.Size(28, 23);
60 | txtDeviceNumber.TabIndex = 1;
61 | txtDeviceNumber.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
62 | //
63 | // cmbDevice
64 | //
65 | cmbDevice.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
66 | cmbDevice.FormattingEnabled = true;
67 | cmbDevice.Location = new System.Drawing.Point(338, 1);
68 | cmbDevice.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
69 | cmbDevice.Name = "cmbDevice";
70 | cmbDevice.Size = new System.Drawing.Size(345, 23);
71 | cmbDevice.TabIndex = 3;
72 | cmbDevice.SelectedIndexChanged += CmbDevice_SelectedIndexChanged;
73 | //
74 | // chkAllowSetConnectedTrue
75 | //
76 | chkAllowSetConnectedTrue.AutoSize = true;
77 | chkAllowSetConnectedTrue.Location = new System.Drawing.Point(985, 5);
78 | chkAllowSetConnectedTrue.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
79 | chkAllowSetConnectedTrue.Name = "chkAllowSetConnectedTrue";
80 | chkAllowSetConnectedTrue.Size = new System.Drawing.Size(15, 14);
81 | chkAllowSetConnectedTrue.TabIndex = 5;
82 | chkAllowSetConnectedTrue.UseVisualStyleBackColor = true;
83 | //
84 | // chkAllowSetConnectedFalse
85 | //
86 | chkAllowSetConnectedFalse.AutoSize = true;
87 | chkAllowSetConnectedFalse.Location = new System.Drawing.Point(915, 5);
88 | chkAllowSetConnectedFalse.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
89 | chkAllowSetConnectedFalse.Name = "chkAllowSetConnectedFalse";
90 | chkAllowSetConnectedFalse.Size = new System.Drawing.Size(15, 14);
91 | chkAllowSetConnectedFalse.TabIndex = 4;
92 | chkAllowSetConnectedFalse.UseVisualStyleBackColor = true;
93 | //
94 | // btnSetup
95 | //
96 | btnSetup.Location = new System.Drawing.Point(751, 1);
97 | btnSetup.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
98 | btnSetup.Name = "btnSetup";
99 | btnSetup.Size = new System.Drawing.Size(88, 22);
100 | btnSetup.TabIndex = 6;
101 | btnSetup.Text = "Setup";
102 | btnSetup.UseVisualStyleBackColor = true;
103 | btnSetup.Click += BtnSetup_Click;
104 | //
105 | // ChkAllowConcurrentAccess
106 | //
107 | ChkAllowConcurrentAccess.AutoSize = true;
108 | ChkAllowConcurrentAccess.Location = new System.Drawing.Point(1083, 5);
109 | ChkAllowConcurrentAccess.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
110 | ChkAllowConcurrentAccess.Name = "ChkAllowConcurrentAccess";
111 | ChkAllowConcurrentAccess.Size = new System.Drawing.Size(15, 14);
112 | ChkAllowConcurrentAccess.TabIndex = 7;
113 | ChkAllowConcurrentAccess.UseVisualStyleBackColor = true;
114 | //
115 | // ServedDevice
116 | //
117 | AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
118 | AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
119 | Controls.Add(ChkAllowConcurrentAccess);
120 | Controls.Add(btnSetup);
121 | Controls.Add(chkAllowSetConnectedTrue);
122 | Controls.Add(chkAllowSetConnectedFalse);
123 | Controls.Add(cmbDevice);
124 | Controls.Add(txtDeviceNumber);
125 | Controls.Add(cmbDeviceType);
126 | Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
127 | Name = "ServedDevice";
128 | Size = new System.Drawing.Size(1142, 25);
129 | ResumeLayout(false);
130 | PerformLayout();
131 | }
132 |
133 | #endregion
134 |
135 | private System.Windows.Forms.ComboBox cmbDeviceType;
136 | private System.Windows.Forms.TextBox txtDeviceNumber;
137 | private System.Windows.Forms.ComboBox cmbDevice;
138 | private System.Windows.Forms.CheckBox chkAllowSetConnectedTrue;
139 | private System.Windows.Forms.CheckBox chkAllowSetConnectedFalse;
140 | private System.Windows.Forms.Button btnSetup;
141 | private System.Windows.Forms.CheckBox ChkAllowConcurrentAccess;
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/Remote Server/servedDevice.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | text/microsoft-resx
50 |
51 |
52 | 2.0
53 |
54 |
55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
56 |
57 |
58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
59 |
60 |
--------------------------------------------------------------------------------
/SetNetworkPermissions/ASCOM.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ASCOMInitiative/ASCOMRemote/e4d60019d54692a0dafd788895d1dde6a778a28e/SetNetworkPermissions/ASCOM.ico
--------------------------------------------------------------------------------
/SetNetworkPermissions/Options.cs:
--------------------------------------------------------------------------------
1 | using CommandLine;
2 |
3 | namespace ASCOM.Remote
4 | {
5 | ///
6 | /// Specify command line options that can be supplied to this executable through the CommandLine reference
7 | ///
8 | class Options
9 | {
10 | [Option('l', Program.SET_LOCAL_SERVER_PATH_COMMAND_NAME, Required = false, Default = Program.NOT_PRESENT_FLAG, HelpText = "Path to the local server executable")]
11 | public string LocalServerPath { get; set; }
12 |
13 | [Option('a', Program.ENABLE_API_URI_COMMAND_NAME, Required = false, Default = Program.NOT_PRESENT_FLAG, HelpText = "Set the API URI ACL")]
14 | public string SetApiUriAcl { get; set; }
15 |
16 | [Option('m', Program.ENABLE_REMOTE_SERVER_MANAGEMENT_URI_COMMAND_NAME, Required = false, Default = Program.NOT_PRESENT_FLAG, HelpText = "Set the Remote Server management URI ACL")]
17 | public string SetRemoteServerManagementUriAcl { get; set; }
18 |
19 | [Option('p', Program.ENABLE_ALPACA_DEVICE_MANAGEMENT_URI_COMMAND_NAME, Required = false, Default = Program.NOT_PRESENT_FLAG, HelpText = "Set the Alpaca device management URI ACL")]
20 | public string SetAlpacaManagementUriAcl { get; set; }
21 |
22 | [Option('s', Program.ENABLE_ALPACA_SETUP_URI_COMMAND_NAME, Required = false, Default = Program.NOT_PRESENT_FLAG, HelpText = "Set the Alpaca HTML setup URI ACL")]
23 | public string SetAlpacaSetupUriAcl { get; set; }
24 |
25 | [Option('h', Program.ENABLE_HTTP_DOT_SYS_PORT_COMMAND_NAME, Required = false, Default = Program.NOT_PRESENT_FLAG, HelpText = "Enable the specified firewall port on which HTTP.SYS will listen")]
26 | public string HttpDotSysPort { get; set; }
27 |
28 | [Option('h', Program.USER_NAME_COMMAND_NAME, Required = false, Default = Program.NOT_PRESENT_FLAG, HelpText = "Set the user name for which the HTTP.SYS permission will be enabled")]
29 | public string UserName { get; set; }
30 | }
31 | }
--------------------------------------------------------------------------------
/SetNetworkPermissions/SetNetworkPermissions.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | Exe
4 | ASCOM.Remote
5 | ASCOM.SetNetworkPermissions
6 | net8.0-windows
7 | true
8 | Set Network Permissions
9 | SetNetworkPemissions
10 | Copyright © 2024 ASCOM Initiative
11 | bin\$(Configuration)\
12 | AnyCPU;x86;x64
13 |
14 |
15 | embedded
16 |
17 |
18 | embedded
19 |
20 |
21 | embedded
22 |
23 |
24 | embedded
25 | false
26 |
27 |
28 | embedded
29 | false
30 |
31 |
32 | embedded
33 | false
34 |
35 |
36 | app.manifest
37 |
38 |
39 | ASCOM.ico
40 | True
41 | ..\Remote Server Key.snk
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/SetNetworkPermissions/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/SetNetworkPermissions/app.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
52 |
59 |
60 |
61 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/Setup/ASCOM Remote Setup.iss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ASCOMInitiative/ASCOMRemote/e4d60019d54692a0dafd788895d1dde6a778a28e/Setup/ASCOM Remote Setup.iss
--------------------------------------------------------------------------------
/Setup/ASCOM.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ASCOMInitiative/ASCOMRemote/e4d60019d54692a0dafd788895d1dde6a778a28e/Setup/ASCOM.ico
--------------------------------------------------------------------------------
/Setup/ASCOMLogo.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ASCOMInitiative/ASCOMRemote/e4d60019d54692a0dafd788895d1dde6a778a28e/Setup/ASCOMLogo.bmp
--------------------------------------------------------------------------------
/Setup/NewWizardImage.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ASCOMInitiative/ASCOMRemote/e4d60019d54692a0dafd788895d1dde6a778a28e/Setup/NewWizardImage.bmp
--------------------------------------------------------------------------------
/SignASCOMRemote.cmd:
--------------------------------------------------------------------------------
1 | @echo on
2 | call "C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\Tools\VsDevCmd.bat" -startdir=none -arch=x64 -host_arch=x64
3 |
4 | "C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x86\signtool" sign /a /fd SHA256 /n "Peter Simpson" /tr http://rfc3161timestamp.globalsign.com/advanced /td SHA256 %1
5 |
6 |
7 |
8 |
9 | rem @echo on
10 | rem @echo Setting up variables
11 | rem call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x86
12 | rem @echo " "
13 | rem @echo Parameter: %1
14 |
15 | rem echo "%1" | findstr /C:"uninst" 1>nul
16 |
17 | rem We only need to sign these executables once, so do this when the uninstaller is created.
18 | rem if errorlevel 1 (
19 | rem echo Signing main installer - Not signing other executables
20 | rem ) ELSE (
21 | rem echo Signing uninstaller - Signing other exectutables too.
22 |
23 | rem echo signtool sign /a /fd SHA256 /tr http://rfc3161timestamp.globalsign.com/advanced /td SHA256 "J:\ASCOMRemote\Remote Server\bin\Debug\ASCOM.RemoteServer.exe"
24 | rem echo signtool sign /a /fd SHA256 /tr http://rfc3161timestamp.globalsign.com/advanced /td SHA256 "J:\ASCOMRemote\Remote Server\bin\Debug\ASCOM.Common.dll"
25 | rem echo signtool sign /a /fd SHA256 /tr http://rfc3161timestamp.globalsign.com/advanced /td SHA256 "J:\ASCOMRemote\SetNetworkPermissions\bin\Debug\ASCOM.SetNetworkPermissions.exe"
26 | rem echo signtool sign /a /fd SHA256 /tr http://rfc3161timestamp.globalsign.com/advanced /td SHA256 "J:\ASCOMRemote\SetNetworkPermissions\bin\Debug\WindowsFirewallHelper.dll"
27 | rem echo signtool sign /a /fd SHA256 /tr http://rfc3161timestamp.globalsign.com/advanced /td SHA256 "J:\ASCOMRemote\SetNetworkPermissions\bin\Debug\CommandLine.dll"
28 | rem echo signtool sign /a /fd SHA256 /tr http://rfc3161timestamp.globalsign.com/advanced /td SHA256 "J:\ASCOMRemote\SetNetworkPermissions\bin\Debug\NetStandard.dll"
29 |
30 | rem signtool sign /a /fd SHA256 /tr http://rfc3161timestamp.globalsign.com/advanced /td SHA256 "J:\ASCOMRemote\Remote Server\bin\Debug\ASCOM.RemoteServer.exe"
31 | rem signtool sign /a /fd SHA256 /tr http://rfc3161timestamp.globalsign.com/advanced /td SHA256 "J:\ASCOMRemote\Remote Server\bin\Debug\ASCOM.Common.dll"
32 | rem signtool sign /a /fd SHA256 /tr http://rfc3161timestamp.globalsign.com/advanced /td SHA256 "J:\ASCOMRemote\SetNetworkPermissions\bin\Debug\ASCOM.SetNetworkPermissions.exe"
33 | rem signtool sign /a /fd SHA256 /tr http://rfc3161timestamp.globalsign.com/advanced /td SHA256 "J:\ASCOMRemote\SetNetworkPermissions\bin\Debug\WindowsFirewallHelper.dll"
34 | rem signtool sign /a /fd SHA256 /tr http://rfc3161timestamp.globalsign.com/advanced /td SHA256 "J:\ASCOMRemote\SetNetworkPermissions\bin\Debug\CommandLine.dll"
35 | rem signtool sign /a /fd SHA256 /tr http://rfc3161timestamp.globalsign.com/advanced /td SHA256 "J:\ASCOMRemote\SetNetworkPermissions\bin\Debug\NetStandard.dll"
36 |
37 | rem echo signtool sign /a /fd SHA256 /tr http://rfc3161timestamp.globalsign.com/advanced /td SHA256 "J:\ASCOMRemote\Remote Server\bin\Release\ASCOM.RemoteServer.exe"
38 | rem echo signtool sign /a /fd SHA256 /tr http://rfc3161timestamp.globalsign.com/advanced /td SHA256 "J:\ASCOMRemote\Remote Server\bin\Release\ASCOM.Common.dll"
39 | rem echo signtool sign /a /fd SHA256 /tr http://rfc3161timestamp.globalsign.com/advanced /td SHA256 "J:\ASCOMRemote\SetNetworkPermissions\bin\Release\ASCOM.SetNetworkPermissions.exe"
40 | rem echo signtool sign /a /fd SHA256 /tr http://rfc3161timestamp.globalsign.com/advanced /td SHA256 "J:\ASCOMRemote\SetNetworkPermissions\bin\Release\WindowsFirewallHelper.dll"
41 | rem echo signtool sign /a /fd SHA256 /tr http://rfc3161timestamp.globalsign.com/advanced /td SHA256 "J:\ASCOMRemote\SetNetworkPermissions\bin\Release\CommandLine.dll"
42 | rem echo signtool sign /a /fd SHA256 /tr http://rfc3161timestamp.globalsign.com/advanced /td SHA256 "J:\ASCOMRemote\SetNetworkPermissions\bin\Release\NetStandard.dll"
43 |
44 | rem signtool sign /a /fd SHA256 /tr http://rfc3161timestamp.globalsign.com/advanced /td SHA256 "J:\ASCOMRemote\Remote Server\bin\Release\ASCOM.RemoteServer.exe"
45 | rem signtool sign /a /fd SHA256 /tr http://rfc3161timestamp.globalsign.com/advanced /td SHA256 "J:\ASCOMRemote\Remote Server\bin\Release\ASCOM.Common.dll"
46 | rem signtool sign /a /fd SHA256 /tr http://rfc3161timestamp.globalsign.com/advanced /td SHA256 "J:\ASCOMRemote\SetNetworkPermissions\bin\Release\ASCOM.SetNetworkPermissions.exe"
47 | rem signtool sign /a /fd SHA256 /tr http://rfc3161timestamp.globalsign.com/advanced /td SHA256 "J:\ASCOMRemote\SetNetworkPermissions\bin\Release\WindowsFirewallHelper.dll"
48 | rem signtool sign /a /fd SHA256 /tr http://rfc3161timestamp.globalsign.com/advanced /td SHA256 "J:\ASCOMRemote\SetNetworkPermissions\bin\Release\CommandLine.dll"
49 | rem signtool sign /a /fd SHA256 /tr http://rfc3161timestamp.globalsign.com/advanced /td SHA256 "J:\ASCOMRemote\SetNetworkPermissions\bin\Release\NetStandard.dll"
50 |
51 | )
52 |
53 | rem Wait for 1 second to allow Inno to release a file handle, which prevents signtool from working correctly.
54 | rem timeout 1
55 |
56 | rem Sign the installer or uninstaller whose filename was supplied as the first parameter
57 | rem echo signtool sign /a /fd SHA256 /tr http://rfc3161timestamp.globalsign.com/advanced /td SHA256 %1
58 | rem signtool sign /a /fd SHA256 /tr http://rfc3161timestamp.globalsign.com/advanced /td SHA256 %1
59 |
60 | rem pause
61 |
--------------------------------------------------------------------------------
/Swagger/bugt300square.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ASCOMInitiative/ASCOMRemote/e4d60019d54692a0dafd788895d1dde6a778a28e/Swagger/bugt300square.jpg
--------------------------------------------------------------------------------
/Swagger/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ASCOMInitiative/ASCOMRemote/e4d60019d54692a0dafd788895d1dde6a778a28e/Swagger/favicon-16x16.png
--------------------------------------------------------------------------------
/Swagger/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ASCOMInitiative/ASCOMRemote/e4d60019d54692a0dafd788895d1dde6a778a28e/Swagger/favicon-32x32.png
--------------------------------------------------------------------------------
/Swagger/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ASCOM Alpaca API
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
163 |
164 |
165 |
--------------------------------------------------------------------------------
/Swagger/oauth2-redirect.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
68 |
--------------------------------------------------------------------------------
/Swagger/redoclyconfig.yaml:
--------------------------------------------------------------------------------
1 | extends:
2 | - recommended
3 |
4 | rules:
5 | operation-operationId: off
6 | no-empty-servers: off
7 |
--------------------------------------------------------------------------------
/redocly.yaml:
--------------------------------------------------------------------------------
1 | extends:
2 | - recommended
3 | rules:
4 | security-defined: off
5 | operation-operationId: off
6 | info-license: off
7 |
--------------------------------------------------------------------------------