1
0
mirror of https://bitbucket.org/cjdskunkworks/lynxastrodewcontroller.git synced 2026-05-03 09:18:51 +00:00

Version 1 of the LynxAstro.DewController.Switch driver

This commit is contained in:
2021-02-17 19:48:23 +00:00
parent 7be023be2c
commit 7fe6d52363
65 changed files with 6381 additions and 0 deletions
+222
View File
@@ -0,0 +1,222 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
build/
bld/
[Bb]in/
[Oo]bj/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
*.cachefile
# Visual Studio profiler
*.psess
*.vsp
*.vspx
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
*ncrunchsolution.user
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# Windows Azure Build Output
csx/
*.build.csdef
# Windows Store app package directory
AppPackages/
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# nCrunch items
*.ncrunchsolution
*.DotSettings
*.ncrunchproject
@@ -0,0 +1,349 @@
Conform Report Hash (V1): 5A431672269EA8E8AC10FDAB37C418D8AC06BDA9D013E7B57D8D46B4494A80B03209D002BC052DA6FDDC36320956A15ECA4AA1ED59B40D7BE27F35854C5B8CAF
ConformanceCheck ASCOM Device Conformance Checker Version 6.5.7500.22514, Build time: 14/07/2020 13:30:28
ConformanceCheck Running on: ASCOM Platform 6.5 SP1 6.5.1.3234
ConformanceCheck Driver ProgID: ASCOM.LynxAstro.DewController.Switch
Error handling
Error number for "Not Implemented" is: 80040400
Error number for "Invalid Value 1" is: 80040405
Error number for "Value Not Set 1" is: 80040402
Error number for "Value Not Set 2" is: 80040403
Error messages will not be interpreted to infer state.
19:28:43.452 Driver Access Checks OK
19:28:44.135 AccessChecks OK Successfully created driver using late binding
19:28:44.176 AccessChecks OK Successfully connected using late binding
19:28:44.179 AccessChecks INFO The driver is a .NET object
19:28:44.183 AccessChecks INFO The AssemblyQualifiedName is: ASCOM.LynxAstro.DewController.Switch, ASCOM.LynxAstro.DewController.Switch,
19:28:44.186 AccessChecks INFO The driver implements interface: ASCOM.DeviceInterface.ISwitchV2
19:28:44.850 AccessChecks INFO Device does not expose interface ISwitch
19:28:44.876 AccessChecks INFO Device exposes interface ISwitchV2
19:28:45.546 AccessChecks OK Successfully created driver using driver access toolkit
19:28:45.574 AccessChecks OK Successfully connected using driver access toolkit
Conform is using ASCOM.DriverAccess.Switch to get a Switch object
19:28:45.612 ConformanceCheck OK Driver instance created successfully
19:28:45.700 ConformanceCheck OK Connected OK
Common Driver Methods
19:28:45.750 InterfaceVersion OK 2
19:28:45.790 Connected OK True
19:28:45.836 Description OK ASCOM Switch Driver for LynxAstro.DewController
19:28:45.883 DriverInfo OK ASCOM Switch Driver for LynxAstro.DewController .net driver. Version: 6.5.1.0
19:28:45.928 DriverVersion OK 6.5.1.0
19:28:45.975 Name OK LynxAstro.DewController
19:28:46.022 CommandString INFO Conform cannot test the CommandString method
19:28:46.026 CommandBlind INFO Conform cannot test the CommandBlind method
19:28:46.031 CommandBool INFO Conform cannot test the CommandBool method
19:28:46.036 Action INFO Conform cannot test the Action method
19:28:46.041 SupportedActions OK Driver returned an empty action list
Properties
19:28:46.198 MaxSwitch OK 4
Methods
19:28:46.314 SwitchNumber OK Switch device threw an InvalidOperationException when a switch ID below 0 was used in method: CanWrite
19:28:46.320 SwitchNumber OK Switch device threw an InvalidOperationException when a switch ID above MaxSwitch was used in method: CanWrite
19:28:46.326 SwitchNumber OK Switch device threw an InvalidOperationException when a switch ID below 0 was used in method: GetSwitch
19:28:46.331 SwitchNumber OK Switch device threw an InvalidOperationException when a switch ID above MaxSwitch was used in method: GetSwitch
19:28:46.337 SwitchNumber OK Switch device threw an InvalidOperationException when a switch ID below 0 was used in method: GetSwitchDescription
19:28:46.343 SwitchNumber OK Switch device threw an InvalidOperationException when a switch ID above MaxSwitch was used in method: GetSwitchDescription
19:28:46.350 SwitchNumber OK Switch device threw an InvalidOperationException when a switch ID below 0 was used in method: GetSwitchName
19:28:46.356 SwitchNumber OK Switch device threw an InvalidOperationException when a switch ID above MaxSwitch was used in method: GetSwitchName
19:28:46.362 SwitchNumber OK Switch device threw an InvalidOperationException when a switch ID below 0 was used in method: GetSwitchValue
19:28:46.368 SwitchNumber OK Switch device threw an InvalidOperationException when a switch ID above MaxSwitch was used in method: GetSwitchValue
19:28:46.374 SwitchNumber OK Switch device threw an InvalidOperationException when a switch ID below 0 was used in method: MaxSwitchValue
19:28:46.380 SwitchNumber OK Switch device threw an InvalidOperationException when a switch ID above MaxSwitch was used in method: MaxSwitchValue
19:28:46.387 SwitchNumber OK Switch device threw an InvalidOperationException when a switch ID below 0 was used in method: MinSwitchValue
19:28:46.393 SwitchNumber OK Switch device threw an InvalidOperationException when a switch ID above MaxSwitch was used in method: MinSwitchValue
19:28:46.400 SwitchNumber OK Switch device threw an InvalidOperationException when a switch ID below 0 was used in method: SetSwitch
19:28:46.406 SwitchNumber OK Switch device threw an InvalidOperationException when a switch ID above MaxSwitch was used in method: SetSwitch
19:28:46.414 SwitchNumber OK Switch device threw an InvalidOperationException when a switch ID below 0 was used in method: SetSwitchValue
19:28:46.420 SwitchNumber OK Switch device threw an InvalidOperationException when a switch ID above MaxSwitch was used in method: SetSwitchValue
19:28:46.427 SwitchNumber OK Switch device threw an InvalidOperationException when a switch ID below 0 was used in method: SwitchStep
19:28:46.434 SwitchNumber OK Switch device threw an InvalidOperationException when a switch ID above MaxSwitch was used in method: SwitchStep
19:28:49.553 GetSwitchName OK Found switch 0
19:28:49.559 GetSwitchName OK Name:
19:28:49.566 GetSwitchDescription OK Description: Control Knob
19:28:49.572 MinSwitchValue OK Minimum: 0
19:28:49.579 MaxSwitchValue OK Maximum: 1023
19:28:49.586 SwitchStep OK Step size: 1
19:28:49.593 SwitchStep OK Step size is greater than zero
19:28:49.600 SwitchStep OK Step size is less than the range of possible values
19:28:49.607 SwitchStep OK The switch range is an integer multiple of the step size.
19:28:49.615 CanWrite OK CanWrite: True
19:28:49.623 GetSwitch OK False
19:28:49.633 GetSwitchValue OK 0
19:28:49.690 SetSwitch OK GetSwitch returned False after SetSwitch(False)
19:28:49.699 SetSwitch OK GetSwitchValue returned MINIMUM_VALUE after SetSwitch(False)
19:28:49.799 SetSwitch OK GetSwitch read True after SetSwitch(True)
19:28:49.809 SetSwitch OK GetSwitchValue returned MAXIMUM_VALUE after SetSwitch(True)
19:28:49.953 SetSwitchValue OK GetSwitch returned False after SetSwitchValue(MINIMUM_VALUE)
19:28:49.961 SetSwitchValue OK GetSwitchValue returned MINIMUM_VALUE after SetSwitchValue(MINIMUM_VALUE)
19:28:50.014 SetSwitchValue OK Switch threw an InvalidOperationException when a value below SwitchMinimum was set: -1
19:28:50.155 SetSwitchValue OK GetSwitch returned True after SetSwitchValue(MAXIMUM_VALUE)
19:28:50.165 SetSwitchValue OK GetSwitchValue returned MAXIMUM_VALUE after SetSwitchValue(MAXIMUM_VALUE)
19:28:50.215 SetSwitchValue OK Switch threw an InvalidOperationException when a value above SwitchMaximum was set: 1024
19:28:50.309 SetSwitchValue INFO Testing with steps that are 0% offset from integer SwitchStep values
19:28:50.402 SetSwitchValue Offset: 0% OK Set and read match: 0
19:28:50.572 SetSwitchValue Offset: 0% OK Set and read match: 102
19:28:50.743 SetSwitchValue Offset: 0% OK Set and read match: 205
19:28:50.913 SetSwitchValue Offset: 0% OK Set and read match: 307
19:28:51.083 SetSwitchValue Offset: 0% OK Set and read match: 409
19:28:51.253 SetSwitchValue Offset: 0% OK Set and read match: 512
19:28:51.423 SetSwitchValue Offset: 0% OK Set and read match: 614
19:28:51.594 SetSwitchValue Offset: 0% OK Set and read match: 716
19:28:51.764 SetSwitchValue Offset: 0% OK Set and read match: 818
19:28:51.934 SetSwitchValue Offset: 0% OK Set and read match: 921
19:28:52.105 SetSwitchValue Offset: 0% OK Set and read match: 1023
19:28:52.226 SetSwitchValue INFO Testing with steps that are 25% offset from integer SwitchStep values
19:28:52.320 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 0.25, Read: 0
19:28:52.491 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 102.25, Read: 102
19:28:52.661 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 205.25, Read: 205
19:28:52.831 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 307.25, Read: 307
19:28:53.002 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 409.25, Read: 409
19:28:53.172 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 512.25, Read: 512
19:28:53.342 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 614.25, Read: 614
19:28:53.512 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 716.25, Read: 716
19:28:53.682 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 818.25, Read: 818
19:28:53.853 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 921.25, Read: 921
19:28:54.005 SetSwitchValue INFO Testing with steps that are 50% offset from integer SwitchStep values
19:28:54.100 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 0.5, Read: 1
19:28:54.270 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 102.5, Read: 103
19:28:54.440 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 205.5, Read: 206
19:28:54.611 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 307.5, Read: 308
19:28:54.781 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 409.5, Read: 410
19:28:54.951 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 512.5, Read: 513
19:28:55.121 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 614.5, Read: 615
19:28:55.291 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 716.5, Read: 717
19:28:55.462 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 818.5, Read: 819
19:28:55.632 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 921.5, Read: 922
19:28:55.785 SetSwitchValue INFO Testing with steps that are 75% offset from integer SwitchStep values
19:28:55.879 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 0.75, Read: 1
19:28:56.050 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 102.75, Read: 103
19:28:56.220 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 205.75, Read: 206
19:28:56.390 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 307.75, Read: 308
19:28:56.561 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 409.75, Read: 410
19:28:56.731 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 512.75, Read: 513
19:28:56.901 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 614.75, Read: 615
19:28:57.071 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 716.75, Read: 717
19:28:57.241 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 818.75, Read: 819
19:28:57.396 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 921.75, Read: 922
19:28:57.551 SetSwitchValue OK Switch has been reset to its original state
19:28:57.692 GetSwitchName OK Found switch 1
19:28:57.700 GetSwitchName OK Name:
19:28:57.710 GetSwitchDescription OK Description: Control Knob
19:28:57.719 MinSwitchValue OK Minimum: 0
19:28:57.729 MaxSwitchValue OK Maximum: 1023
19:28:57.738 SwitchStep OK Step size: 1
19:28:57.747 SwitchStep OK Step size is greater than zero
19:28:57.756 SwitchStep OK Step size is less than the range of possible values
19:28:57.766 SwitchStep OK The switch range is an integer multiple of the step size.
19:28:57.775 CanWrite OK CanWrite: True
19:28:57.786 GetSwitch OK True
19:28:57.798 GetSwitchValue OK 470
19:28:57.860 SetSwitch OK GetSwitch returned False after SetSwitch(False)
19:28:57.871 SetSwitch OK GetSwitchValue returned MINIMUM_VALUE after SetSwitch(False)
19:28:58.015 SetSwitch OK GetSwitch read True after SetSwitch(True)
19:28:58.030 SetSwitch OK GetSwitchValue returned MAXIMUM_VALUE after SetSwitch(True)
19:28:58.216 SetSwitchValue OK GetSwitch returned False after SetSwitchValue(MINIMUM_VALUE)
19:28:58.227 SetSwitchValue OK GetSwitchValue returned MINIMUM_VALUE after SetSwitchValue(MINIMUM_VALUE)
19:28:58.276 SetSwitchValue OK Switch threw an InvalidOperationException when a value below SwitchMinimum was set: -1
19:28:58.417 SetSwitchValue OK GetSwitch returned True after SetSwitchValue(MAXIMUM_VALUE)
19:28:58.429 SetSwitchValue OK GetSwitchValue returned MAXIMUM_VALUE after SetSwitchValue(MAXIMUM_VALUE)
19:28:58.524 SetSwitchValue OK Switch threw an InvalidOperationException when a value above SwitchMaximum was set: 1024
19:28:58.616 SetSwitchValue INFO Testing with steps that are 0% offset from integer SwitchStep values
19:28:58.711 SetSwitchValue Offset: 0% OK Set and read match: 0
19:28:58.882 SetSwitchValue Offset: 0% OK Set and read match: 102
19:28:59.052 SetSwitchValue Offset: 0% OK Set and read match: 205
19:28:59.222 SetSwitchValue Offset: 0% OK Set and read match: 307
19:28:59.392 SetSwitchValue Offset: 0% OK Set and read match: 409
19:28:59.562 SetSwitchValue Offset: 0% OK Set and read match: 512
19:28:59.732 SetSwitchValue Offset: 0% OK Set and read match: 614
19:28:59.903 SetSwitchValue Offset: 0% OK Set and read match: 716
19:29:00.057 SetSwitchValue Offset: 0% OK Set and read match: 818
19:29:00.228 SetSwitchValue Offset: 0% OK Set and read match: 921
19:29:00.398 SetSwitchValue Offset: 0% OK Set and read match: 1023
19:29:00.520 SetSwitchValue INFO Testing with steps that are 25% offset from integer SwitchStep values
19:29:00.583 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 0.25, Read: 0
19:29:00.754 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 102.25, Read: 102
19:29:00.924 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 205.25, Read: 205
19:29:01.094 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 307.25, Read: 307
19:29:01.264 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 409.25, Read: 409
19:29:01.435 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 512.25, Read: 512
19:29:01.605 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 614.25, Read: 614
19:29:01.775 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 716.25, Read: 716
19:29:01.945 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 818.25, Read: 818
19:29:02.116 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 921.25, Read: 921
19:29:02.268 SetSwitchValue INFO Testing with steps that are 50% offset from integer SwitchStep values
19:29:02.363 SetSwitchValue Offset: 50% INFO Set/Read differ by >100% of SwitchStep. Set: 0.5, Read: 468
19:29:02.533 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 102.5, Read: 103
19:29:02.703 SetSwitchValue Offset: 50% INFO Set/Read differ by >100% of SwitchStep. Set: 205.5, Read: 475
19:29:02.874 SetSwitchValue Offset: 50% INFO Set/Read differ by >100% of SwitchStep. Set: 307.5, Read: 469
19:29:03.044 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 409.5, Read: 410
19:29:03.214 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 512.5, Read: 513
19:29:03.384 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 614.5, Read: 615
19:29:03.554 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 716.5, Read: 717
19:29:03.724 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 818.5, Read: 819
19:29:03.895 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 921.5, Read: 922
19:29:04.047 SetSwitchValue INFO Testing with steps that are 75% offset from integer SwitchStep values
19:29:04.142 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 0.75, Read: 1
19:29:04.312 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 102.75, Read: 103
19:29:04.467 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 205.75, Read: 206
19:29:04.637 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 307.75, Read: 308
19:29:04.808 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 409.75, Read: 410
19:29:04.978 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 512.75, Read: 513
19:29:05.148 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 614.75, Read: 615
19:29:05.318 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 716.75, Read: 717
19:29:05.488 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 818.75, Read: 819
19:29:05.658 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 921.75, Read: 922
19:29:05.814 SetSwitchValue OK Switch has been reset to its original state
19:29:05.954 GetSwitchName OK Found switch 2
19:29:05.963 GetSwitchName OK Name:
19:29:05.972 GetSwitchDescription OK Description: Control Knob
19:29:05.981 MinSwitchValue OK Minimum: 0
19:29:05.991 MaxSwitchValue OK Maximum: 1023
19:29:06.001 SwitchStep OK Step size: 1
19:29:06.010 SwitchStep OK Step size is greater than zero
19:29:06.020 SwitchStep OK Step size is less than the range of possible values
19:29:06.029 SwitchStep OK The switch range is an integer multiple of the step size.
19:29:06.039 CanWrite OK CanWrite: True
19:29:06.051 GetSwitch OK False
19:29:06.061 GetSwitchValue OK 0
19:29:06.122 SetSwitch OK GetSwitch returned False after SetSwitch(False)
19:29:06.133 SetSwitch OK GetSwitchValue returned MINIMUM_VALUE after SetSwitch(False)
19:29:06.231 SetSwitch OK GetSwitch read True after SetSwitch(True)
19:29:06.244 SetSwitch OK GetSwitchValue returned MAXIMUM_VALUE after SetSwitch(True)
19:29:06.431 SetSwitchValue OK GetSwitch returned False after SetSwitchValue(MINIMUM_VALUE)
19:29:06.442 SetSwitchValue OK GetSwitchValue returned MINIMUM_VALUE after SetSwitchValue(MINIMUM_VALUE)
19:29:06.492 SetSwitchValue OK Switch threw an InvalidOperationException when a value below SwitchMinimum was set: -1
19:29:06.634 SetSwitchValue OK GetSwitch returned True after SetSwitchValue(MAXIMUM_VALUE)
19:29:06.646 SetSwitchValue OK GetSwitchValue returned MAXIMUM_VALUE after SetSwitchValue(MAXIMUM_VALUE)
19:29:06.740 SetSwitchValue OK Switch threw an InvalidOperationException when a value above SwitchMaximum was set: 1024
19:29:06.832 SetSwitchValue INFO Testing with steps that are 0% offset from integer SwitchStep values
19:29:06.896 SetSwitchValue Offset: 0% OK Set and read match: 0
19:29:07.066 SetSwitchValue Offset: 0% OK Set and read match: 102
19:29:07.237 SetSwitchValue Offset: 0% OK Set and read match: 205
19:29:07.407 SetSwitchValue Offset: 0% OK Set and read match: 307
19:29:07.577 SetSwitchValue Offset: 0% OK Set and read match: 409
19:29:07.747 SetSwitchValue Offset: 0% OK Set and read match: 512
19:29:07.917 SetSwitchValue Offset: 0% OK Set and read match: 614
19:29:08.088 SetSwitchValue Offset: 0% OK Set and read match: 716
19:29:08.258 SetSwitchValue Offset: 0% OK Set and read match: 818
19:29:08.428 SetSwitchValue Offset: 0% OK Set and read match: 921
19:29:08.599 SetSwitchValue Offset: 0% OK Set and read match: 1023
19:29:08.720 SetSwitchValue INFO Testing with steps that are 25% offset from integer SwitchStep values
19:29:08.814 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 0.25, Read: 0
19:29:08.985 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 102.25, Read: 102
19:29:09.155 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 205.25, Read: 205
19:29:09.325 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 307.25, Read: 307
19:29:09.481 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 409.25, Read: 409
19:29:09.650 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 512.25, Read: 512
19:29:09.821 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 614.25, Read: 614
19:29:09.991 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 716.25, Read: 716
19:29:10.161 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 818.25, Read: 818
19:29:10.331 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 921.25, Read: 921
19:29:10.484 SetSwitchValue INFO Testing with steps that are 50% offset from integer SwitchStep values
19:29:10.578 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 0.5, Read: 1
19:29:10.749 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 102.5, Read: 103
19:29:10.921 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 205.5, Read: 206
19:29:11.059 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 307.5, Read: 308
19:29:11.229 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 409.5, Read: 410
19:29:11.400 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 512.5, Read: 513
19:29:11.569 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 614.5, Read: 615
19:29:11.739 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 716.5, Read: 717
19:29:11.910 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 818.5, Read: 819
19:29:12.080 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 921.5, Read: 922
19:29:12.233 SetSwitchValue INFO Testing with steps that are 75% offset from integer SwitchStep values
19:29:12.327 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 0.75, Read: 1
19:29:12.497 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 102.75, Read: 103
19:29:12.668 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 205.75, Read: 206
19:29:12.838 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 307.75, Read: 308
19:29:13.008 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 409.75, Read: 410
19:29:13.178 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 512.75, Read: 513
19:29:13.349 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 614.75, Read: 615
19:29:13.519 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 716.75, Read: 717
19:29:13.689 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 818.75, Read: 819
19:29:13.859 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 921.75, Read: 922
19:29:14.014 SetSwitchValue OK Switch has been reset to its original state
19:29:14.155 GetSwitchName OK Found switch 3
19:29:14.165 GetSwitchName OK Name:
19:29:14.174 GetSwitchDescription OK Description: Control Knob
19:29:14.184 MinSwitchValue OK Minimum: 0
19:29:14.194 MaxSwitchValue OK Maximum: 1023
19:29:14.205 SwitchStep OK Step size: 1
19:29:14.214 SwitchStep OK Step size is greater than zero
19:29:14.224 SwitchStep OK Step size is less than the range of possible values
19:29:14.233 SwitchStep OK The switch range is an integer multiple of the step size.
19:29:14.243 CanWrite OK CanWrite: True
19:29:14.254 GetSwitch OK False
19:29:14.265 GetSwitchValue OK 0
19:29:14.385 SetSwitch OK GetSwitch returned False after SetSwitch(False)
19:29:14.396 SetSwitch OK GetSwitchValue returned MINIMUM_VALUE after SetSwitch(False)
19:29:14.494 SetSwitch OK GetSwitch read True after SetSwitch(True)
19:29:14.506 SetSwitch OK GetSwitchValue returned MAXIMUM_VALUE after SetSwitch(True)
19:29:14.694 SetSwitchValue OK GetSwitch returned False after SetSwitchValue(MINIMUM_VALUE)
19:29:14.707 SetSwitchValue OK GetSwitchValue returned MINIMUM_VALUE after SetSwitchValue(MINIMUM_VALUE)
19:29:14.802 SetSwitchValue OK Switch threw an InvalidOperationException when a value below SwitchMinimum was set: -1
19:29:14.943 SetSwitchValue OK GetSwitch returned True after SetSwitchValue(MAXIMUM_VALUE)
19:29:14.954 SetSwitchValue OK GetSwitchValue returned MAXIMUM_VALUE after SetSwitchValue(MAXIMUM_VALUE)
19:29:15.049 SetSwitchValue OK Switch threw an InvalidOperationException when a value above SwitchMaximum was set: 1024
19:29:15.142 SetSwitchValue INFO Testing with steps that are 0% offset from integer SwitchStep values
19:29:15.236 SetSwitchValue Offset: 0% OK Set and read match: 0
19:29:15.407 SetSwitchValue Offset: 0% OK Set and read match: 102
19:29:15.577 SetSwitchValue Offset: 0% OK Set and read match: 205
19:29:15.747 SetSwitchValue Offset: 0% OK Set and read match: 307
19:29:15.917 SetSwitchValue Offset: 0% OK Set and read match: 409
19:29:16.087 SetSwitchValue Offset: 0% OK Set and read match: 512
19:29:16.258 SetSwitchValue Offset: 0% OK Set and read match: 614
19:29:16.428 SetSwitchValue Offset: 0% OK Set and read match: 716
19:29:16.583 SetSwitchValue Offset: 0% OK Set and read match: 818
19:29:16.753 SetSwitchValue Offset: 0% OK Set and read match: 921
19:29:16.924 SetSwitchValue Offset: 0% OK Set and read match: 1023
19:29:17.045 SetSwitchValue INFO Testing with steps that are 25% offset from integer SwitchStep values
19:29:17.139 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 0.25, Read: 0
19:29:17.310 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 102.25, Read: 102
19:29:17.480 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 205.25, Read: 205
19:29:17.650 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 307.25, Read: 307
19:29:17.821 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 409.25, Read: 409
19:29:17.991 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 512.25, Read: 512
19:29:18.161 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 614.25, Read: 614
19:29:18.331 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 716.25, Read: 716
19:29:18.501 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 818.25, Read: 818
19:29:18.671 SetSwitchValue Offset: 25% INFO Set/Read differ by 20-30% of SwitchStep. Set: 921.25, Read: 921
19:29:18.824 SetSwitchValue INFO Testing with steps that are 50% offset from integer SwitchStep values
19:29:18.918 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 0.5, Read: 1
19:29:19.089 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 102.5, Read: 103
19:29:19.260 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 205.5, Read: 206
19:29:19.415 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 307.5, Read: 308
19:29:19.584 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 409.5, Read: 410
19:29:19.754 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 512.5, Read: 513
19:29:19.925 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 614.5, Read: 615
19:29:20.095 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 716.5, Read: 717
19:29:20.265 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 818.5, Read: 819
19:29:20.435 SetSwitchValue Offset: 50% INFO Set/Read differ by 40-50% of SwitchStep. Set: 921.5, Read: 922
19:29:20.588 SetSwitchValue INFO Testing with steps that are 75% offset from integer SwitchStep values
19:29:20.682 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 0.75, Read: 1
19:29:20.853 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 102.75, Read: 103
19:29:21.023 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 205.75, Read: 206
19:29:21.194 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 307.75, Read: 308
19:29:21.364 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 409.75, Read: 410
19:29:21.534 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 512.75, Read: 513
19:29:21.704 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 614.75, Read: 615
19:29:21.874 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 716.75, Read: 717
19:29:22.045 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 818.75, Read: 819
19:29:22.199 SetSwitchValue Offset: 75% INFO Set/Read differ by 20-30% of SwitchStep. Set: 921.75, Read: 922
19:29:22.354 SetSwitchValue OK Switch has been reset to its original state
Conformance test complete
No errors, warnings or issues found: your driver passes ASCOM validation!!
Driver Hash Value: 2324CFC7AD89514CA3132538F5949BD837ABDF01A2CB27A7E8B4F11F6E34A60F1D0A054FDD9B71AAAEBDE250B552785A4FD3EE2521E13C2AFFDD32F423269B1E
@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<?include $(sys.CURRENTDIR)\Config.wxi?>
<Fragment>
<DirectoryRef Id="INSTALLFOLDER"/>
<ComponentGroup Id="cgAscomLocalServer" Directory="INSTALLFOLDER">
<Component Id="cmpAscomLocalServer" Guid="*" Win64="no">
<File Id="filLocalServerAssembly"
Source="$(var.LynxAstro.DewController.TargetPath)"
KeyPath="yes"
Vital="yes"
Assembly=".net"
AssemblyApplication="filLocalServerAssembly" />
</Component>
</ComponentGroup>
<CustomAction Id="RegisterEXE"
Directory="INSTALLFOLDER"
ExeCommand="&quot;[#filLocalServerAssembly]&quot; /register"
Execute="deferred"
Return="ignore"
Impersonate="no"
/>
<CustomAction Id="UnRegisterEXE"
Directory="INSTALLFOLDER"
ExeCommand="&quot;[#filLocalServerAssembly]&quot; /unregister"
Execute="deferred"
Return="ignore"
Impersonate="no"
/>
<InstallExecuteSequence>
<Custom Action='RegisterEXE' Before="InstallFinalize">
<![CDATA[(NOT Installed)]]>
</Custom>
<Custom Action="UnRegisterEXE" After="InstallInitialize">
<![CDATA[(REMOVE ~= "ALL" AND NOT UPGRADINGPRODUCTCODE)]]>
</Custom>
</InstallExecuteSequence>
</Fragment>
</Wix>
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<?include $(sys.CURRENTDIR)\Config.wxi?>
<!--
ASCOM Switch Driver with COM registry entries suitable for a LocalServer Served Class
-->
<Fragment>
<DirectoryRef Id="INSTALLFOLDER" />
<ComponentGroup Id="cgAscomSwitchDriver">
<Component Id="cmpAscomSwitchDriver"
Directory="INSTALLFOLDER"
Guid="*"
Win64="no">
<File Id="filSwitchDriverAssembly"
Source="$(var.LynxAstro.DewController.Switch.TargetPath)"
KeyPath="yes"
Vital="yes"
Assembly=".net"
AssemblyApplication="filSwitchDriverAssembly" />
</Component>
</ComponentGroup>
</Fragment>
</Wix>
+44
View File
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8" ?>
<Include>
<!--
User Configuration - you must ensure all these variables have correct values for your project.
GUIDs specified here must match those used in the project files, and must be unique to this product.
The LocalServerAppId is defined in the Server project, in LocalServer.cs
Driver Class IDs are defined in each driver class, in the [Guid()] attribute.
Driver ProgIDs must match those used in the source code, typically this will be defined in the LocalServer
project as a constant in the SharedResources static class.
UpgradeCode must be unique to this product and should not be changed for the product lifetime.
-->
<?define InstallName = "ASCOM LynxAstro.DewController" ?>
<?define Manufacturer = "cjdawson.com" ?>
<?define UpgradeCode = "{57597bb6-f207-4998-97f4-8a041950d062}" ?>
<?define INSTALLFOLDER = "$(var.InstallName)" ?>
<?define LocalServerAppId = "{5EBBCD3B-3FC9-4D9F-868D-E0C2D085A58B}" ?>
<?define CopyrightNotice="Copyright © 2021 cjdawson.com, all rights reserved" ?>
<?define SwitchDriverClassId="{A3C01556-C4CD-4259-AB1F-5C08061BACA0}" ?>
<?define SwitchDriverProgId="LynxAstro.DewController.Switch" ?>
<?define SwitchDriverDescription="LynxAstro.DewController"?>
<!-- End of User Configuration - do not edit anything beyond this point -->
<!-- Define platform-specific names and locations -->
<!-- <?if $(var.Platform) = x64 ?>
<?define ProductName = "$(var.InstallName) (x64)" ?>
<?define Win64 = "yes" ?>
<?define PlatformProgramFilesFolder = "ProgramFiles64Folder" ?>
<?define PlatformCommonFilesFolder = "CommonFiles64Folder" ?>
<?else ?>-->
<?define ProductName = "$(var.InstallName) (x86)" ?>
<?define Win64 = "no" ?>
<?define PlatformProgramFilesFolder = "ProgramFilesFolder" ?>
<?define PlatformCommonFilesFolder = "CommonFilesFolder" ?>
<!-- <?endif ?> -->
<!-- Set installer version based on the file version of the main assembly. -->
<?define ProductVersion="!(bind.FileVersion.filLocalServerAssembly)"?>
<!--<?define ProductVersion="0.7.0.0"?>-->
</Include>
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<?include $(sys.CURRENTDIR)\Config.wxi?>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="dirManufacturer" Name="$(var.Manufacturer)">
<Directory Id="INSTALLFOLDER" Name="$(var.InstallName)"/>
</Directory>
</Directory>
</Directory>
</Fragment>
</Wix>
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" >
<?include $(sys.CURRENTDIR)\Config.wxi?>
<Fragment>
<FeatureGroup Id="fgRoot" >
<Feature Id="featAscomDrivers" Title="ASCOM drivers" Level="1" Absent="disallow"
Display="expand" >
<ComponentGroupRef Id="cgAscomLocalServer" />
<ComponentGroupRef Id="cgAscomSwitchDriver"/>
</Feature>
</FeatureGroup>
</Fragment>
</Wix>
@@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
<!--
First-time install dialog sequence:
- WixUI_WelcomeDlg
- WixUI_LicenseAgreementDlg
- WixUI_InstallDirDlg
- WixUI_VerifyReadyDlg
- WixUI_DiskCostDlg
Maintenance dialog sequence:
- WixUI_MaintenanceWelcomeDlg
- WixUI_MaintenanceTypeDlg
- WixUI_InstallDirDlg
- WixUI_VerifyReadyDlg
Patch dialog sequence:
- WixUI_WelcomeDlg
- WixUI_VerifyReadyDlg
-->
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<UI Id="InstallationUI">
<TextStyle Id="WixUI_Font_Normal" FaceName="Tahoma" Size="8" />
<TextStyle Id="WixUI_Font_Bigger" FaceName="Tahoma" Size="12" />
<TextStyle Id="WixUI_Font_Title" FaceName="Tahoma" Size="9" Bold="yes" />
<Property Id="DefaultUIFont" Value="WixUI_Font_Normal" />
<Property Id="WixUI_Mode" Value="InstallDir" />
<DialogRef Id="BrowseDlg" />
<DialogRef Id="DiskCostDlg" />
<DialogRef Id="ErrorDlg" />
<DialogRef Id="FatalError" />
<DialogRef Id="FilesInUse" />
<DialogRef Id="MsiRMFilesInUse" />
<DialogRef Id="PrepareDlg" />
<DialogRef Id="ProgressDlg" />
<DialogRef Id="ResumeDlg" />
<DialogRef Id="UserExit" />
<Publish Dialog="BrowseDlg" Control="OK" Event="DoAction" Value="WixUIValidatePath" Order="3">1</Publish>
<Publish Dialog="BrowseDlg" Control="OK" Event="SpawnDialog" Value="InvalidDirDlg" Order="4"><![CDATA[NOT WIXUI_DONTVALIDATEPATH AND WIXUI_INSTALLDIR_VALID<>"1"]]></Publish>
<Publish Dialog="ExitDialog" Control="Finish" Event="EndDialog" Value="Return" Order="999">1</Publish>
<Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="LicenseAgreementDlg">NOT Installed</Publish>
<Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg">Installed AND PATCH</Publish>
<Publish Dialog="LicenseAgreementDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg">1</Publish>
<Publish Dialog="LicenseAgreementDlg" Control="Next" Event="NewDialog" Value="InstallDirDlg">LicenseAccepted = "1"</Publish>
<Publish Dialog="InstallDirDlg" Control="Back" Event="NewDialog" Value="LicenseAgreementDlg">1</Publish>
<Publish Dialog="InstallDirDlg" Control="Next" Event="SetTargetPath" Value="[WIXUI_INSTALLDIR]" Order="1">1</Publish>
<Publish Dialog="InstallDirDlg" Control="Next" Event="DoAction" Value="WixUIValidatePath" Order="2">NOT WIXUI_DONTVALIDATEPATH</Publish>
<Publish Dialog="InstallDirDlg" Control="Next" Event="SpawnDialog" Value="InvalidDirDlg" Order="3"><![CDATA[NOT WIXUI_DONTVALIDATEPATH AND WIXUI_INSTALLDIR_VALID<>"1"]]></Publish>
<Publish Dialog="InstallDirDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg" Order="4">WIXUI_DONTVALIDATEPATH OR WIXUI_INSTALLDIR_VALID="1"</Publish>
<Publish Dialog="InstallDirDlg" Control="ChangeFolder" Property="_BrowseProperty" Value="[WIXUI_INSTALLDIR]" Order="1">1</Publish>
<Publish Dialog="InstallDirDlg" Control="ChangeFolder" Event="SpawnDialog" Value="BrowseDlg" Order="2">1</Publish>
<Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="InstallDirDlg" Order="1">NOT Installed</Publish>
<Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="MaintenanceTypeDlg" Order="2">Installed AND NOT PATCH</Publish>
<Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg" Order="2">Installed AND PATCH</Publish>
<Publish Dialog="MaintenanceWelcomeDlg" Control="Next" Event="NewDialog" Value="MaintenanceTypeDlg">1</Publish>
<Publish Dialog="MaintenanceTypeDlg" Control="RepairButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish>
<Publish Dialog="MaintenanceTypeDlg" Control="RemoveButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish>
<Publish Dialog="MaintenanceTypeDlg" Control="Back" Event="NewDialog" Value="MaintenanceWelcomeDlg">1</Publish>
<Property Id="ARPNOMODIFY" Value="1" />
</UI>
<UIRef Id="WixUI_Common" />
</Fragment>
</Wix>
Binary file not shown.
@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" InitialTargets="EnsureWixToolsetInstalled" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProductVersion>3.10</ProductVersion>
<ProjectGuid>{1073a462-d9a4-4c72-9c3f-a345b307153a}</ProjectGuid>
<SchemaVersion>2.0</SchemaVersion>
<OutputName>LynxAstro.DewController.Setup</OutputName>
<OutputType>Package</OutputType>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<OutputPath>bin\$(Configuration)\</OutputPath>
<IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
<DefineConstants>Debug</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<OutputPath>bin\$(Configuration)\</OutputPath>
<IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
</PropertyGroup>
<ItemGroup>
<Compile Include="AscomLocalServer.wxs" />
<Compile Include="AscomSwitchDriver.wxs" />
<Compile Include="Directories.wxs" />
<Compile Include="FeatureTree.wxs" />
<Compile Include="InstallationUI.wxs" />
<Compile Include="Product.wxs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LynxAstro.DewController.Switch\LynxAstro.DewController.Switch.csproj">
<Name>LynxAstro.DewController.Switch</Name>
<Project>{64308775-bd4a-469c-bcab-3ed830b811af}</Project>
<Private>True</Private>
<DoNotHarvest>True</DoNotHarvest>
<RefProjectOutputGroups>Binaries;Content;Satellites</RefProjectOutputGroups>
<RefTargetDir>INSTALLFOLDER</RefTargetDir>
</ProjectReference>
<ProjectReference Include="..\LynxAstro.DewController\LynxAstro.DewController.csproj">
<Name>LynxAstro.DewController</Name>
<Project>{c708e487-e3a9-4073-a545-294b88674225}</Project>
<Private>True</Private>
<DoNotHarvest>True</DoNotHarvest>
<RefProjectOutputGroups>Binaries;Content;Satellites</RefProjectOutputGroups>
<RefTargetDir>INSTALLFOLDER</RefTargetDir>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<WixExtension Include="WixUIExtension">
<HintPath>$(WixExtDir)\WixUIExtension.dll</HintPath>
<Name>WixUIExtension</Name>
</WixExtension>
<WixExtension Include="WixNetFxExtension">
<HintPath>$(WixExtDir)\WixNetFxExtension.dll</HintPath>
<Name>WixNetFxExtension</Name>
</WixExtension>
</ItemGroup>
<ItemGroup>
<Content Include="Config.wxi" />
<Content Include="License.rtf" />
</ItemGroup>
<Import Project="$(WixTargetsPath)" Condition=" '$(WixTargetsPath)' != '' " />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets" Condition=" '$(WixTargetsPath)' == '' AND Exists('$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets') " />
<Target Name="EnsureWixToolsetInstalled" Condition=" '$(WixTargetsImported)' != 'true' ">
<Error Text="The WiX Toolset v3.11 (or newer) build tools must be installed to build this project. To download the WiX Toolset, see http://wixtoolset.org/releases/" />
</Target>
<!--
To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Wix.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
+48
View File
@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<?include $(sys.CURRENTDIR)\Config.wxi?>
<Product Id="*"
Name="$(var.InstallName)"
Language="1033"
Version="$(var.ProductVersion)"
Manufacturer="$(var.Manufacturer)"
UpgradeCode="$(var.UpgradeCode)">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate EmbedCab="yes" />
<Property Id="ASCOMPLATFORMVERSION">
<RegistrySearch Id="AscomPlatformVersion"
Root="HKLM"
Key="SOFTWARE\ASCOM\Platform"
Name="Platform Version"
Type="raw" />
</Property>
<Condition Message="This application requires Ascom Platform 6.4 SP1 or higher. Please install this before installing the driver.">
<![CDATA[Installed OR ASCOMPLATFORMVERSION >= "6.4.1"]]>
</Condition>
<PropertyRef Id="NETFRAMEWORK45"/>
<Condition Message="This application requires .NET Framework 4.5 or higher. Please install the .NET Framework then run this installer again.">
<![CDATA[Installed OR NETFRAMEWORK45]]>
</Condition>
<!-- <Condition Message="Please use the correct installer for your operating system - x86 for 32-bit, x64 for 64-bit.">
<?if $(var.Win64) = "yes" ?>
VersionNT64
<?else?>
NOT VersionNT64
<?endif?>
</Condition> -->
<UIRef Id="InstallationUI"/>
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLFOLDER" />
<WixVariable Id="WixUILicenseRtf" Value="License.rtf" />
<FeatureGroupRef Id="fgRoot"/>
</Product>
</Wix>
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\NUnit.3.13.1\build\NUnit.props" Condition="Exists('..\packages\NUnit.3.13.1\build\NUnit.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{AFA5A4A4-188C-4180-B910-7C5BA7D5C11F}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>LynxAstro.DewController.Switch.UnitTests</RootNamespace>
<AssemblyName>LynxAstro.DewController.Switch.UnitTests</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="ASCOM.Astrometry, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>..\packages\ASCOM.Platform.6.5.2\lib\net40\ASCOM.Astrometry.dll</HintPath>
</Reference>
<Reference Include="ASCOM.Attributes, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>..\packages\ASCOM.Platform.6.5.2\lib\net40\ASCOM.Attributes.dll</HintPath>
</Reference>
<Reference Include="ASCOM.Cache, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>..\packages\ASCOM.Platform.6.5.2\lib\net40\ASCOM.Cache.dll</HintPath>
</Reference>
<Reference Include="ASCOM.Controls, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>..\packages\ASCOM.Platform.6.5.2\lib\net40\ASCOM.Controls.dll</HintPath>
</Reference>
<Reference Include="ASCOM.DeviceInterfaces, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>..\packages\ASCOM.Platform.6.5.2\lib\net40\ASCOM.DeviceInterfaces.dll</HintPath>
</Reference>
<Reference Include="ASCOM.DriverAccess, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>..\packages\ASCOM.Platform.6.5.2\lib\net40\ASCOM.DriverAccess.dll</HintPath>
</Reference>
<Reference Include="ASCOM.Exceptions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>..\packages\ASCOM.Platform.6.5.2\lib\net40\ASCOM.Exceptions.dll</HintPath>
</Reference>
<Reference Include="ASCOM.Internal.Extensions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>..\packages\ASCOM.Platform.6.5.2\lib\net40\ASCOM.Internal.Extensions.dll</HintPath>
</Reference>
<Reference Include="ASCOM.SettingsProvider, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>..\packages\ASCOM.Platform.6.5.2\lib\net40\ASCOM.SettingsProvider.dll</HintPath>
</Reference>
<Reference Include="ASCOM.Utilities, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>..\packages\ASCOM.Platform.6.5.2\lib\net40\ASCOM.Utilities.dll</HintPath>
</Reference>
<Reference Include="ASCOM.Utilities.Video, Version=6.1.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>..\packages\ASCOM.Platform.6.5.2\lib\net40\ASCOM.Utilities.Video.dll</HintPath>
</Reference>
<Reference Include="Castle.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
<HintPath>..\packages\Castle.Core.4.4.0\lib\net45\Castle.Core.dll</HintPath>
</Reference>
<Reference Include="Moq, Version=4.16.0.0, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
<HintPath>..\packages\Moq.4.16.0\lib\net45\Moq.dll</HintPath>
</Reference>
<Reference Include="nunit.framework, Version=3.13.1.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<HintPath>..\packages\NUnit.3.13.1\lib\net45\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="SwitchUnitTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LynxAstro.DewController.Switch\LynxAstro.DewController.Switch.csproj">
<Project>{64308775-bd4a-469c-bcab-3ed830b811af}</Project>
<Name>LynxAstro.DewController.Switch</Name>
</ProjectReference>
<ProjectReference Include="..\LynxAstro.DewController\LynxAstro.DewController.csproj">
<Project>{c708e487-e3a9-4073-a545-294b88674225}</Project>
<Name>LynxAstro.DewController</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\NUnit.3.13.1\build\NUnit.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NUnit.3.13.1\build\NUnit.props'))" />
</Target>
</Project>
@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("LynxAstro.DewController.Switch.UnitTests")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("LynxAstro.DewController.Switch.UnitTests")]
[assembly: AssemblyCopyright("Copyright © 2021")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("afa5a4a4-188c-4180-b910-7c5ba7d5c11f")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
@@ -0,0 +1,27 @@
using ASCOM.LynxAstro.DewController;
using Moq;
using NUnit.Framework;
namespace LynxAstro.DewController.Switch.UnitTests
{
[TestFixture]
public class SwitchUnitTests
{
private ASCOM.LynxAstro.DewController.Switch _switch;
private Mock<ISharedResourcesWrapper> _sharedResourcesWrapperMock;
[SetUp]
public void Setup()
{
_sharedResourcesWrapperMock = new Mock<ISharedResourcesWrapper>();
_switch = new ASCOM.LynxAstro.DewController.Switch();
}
[Test]
public void CheckThatClassCreatedProperly()
{
Assert.That(_switch, Is.Not.Null);
}
}
}
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="ASCOM.Platform" version="6.5.2" targetFramework="net472" />
<package id="Castle.Core" version="4.4.0" targetFramework="net472" />
<package id="Moq" version="4.16.0" targetFramework="net472" />
<package id="NUnit" version="3.13.1" targetFramework="net472" />
<package id="System.Runtime.CompilerServices.Unsafe" version="4.5.3" targetFramework="net472" />
<package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net472" />
</packages>
Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

@@ -0,0 +1,151 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{64308775-BD4A-469C-BCAB-3ED830B811AF}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>ASCOM.LynxAstro.DewController</RootNamespace>
<AssemblyName>ASCOM.LynxAstro.DewController.Switch</AssemblyName>
<FileUpgradeFlags>
</FileUpgradeFlags>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
<OldToolsVersion>3.5</OldToolsVersion>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<ApplicationIcon>ASCOM.ico</ApplicationIcon>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>ASCOMDriverTemplate.snk</AssemblyOriginatorKeyFile>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<RegisterForComInterop>true</RegisterForComInterop>
<PlatformTarget>AnyCPU</PlatformTarget>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>AnyCPU</PlatformTarget>
<RegisterForComInterop>false</RegisterForComInterop>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="ASCOM.Astrometry, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL" />
<Reference Include="ASCOM.Attributes, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL" />
<Reference Include="ASCOM.Controls, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL" />
<Reference Include="ASCOM.DeviceInterfaces, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL" />
<Reference Include="ASCOM.Exceptions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL" />
<Reference Include="ASCOM.SettingsProvider, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL" />
<Reference Include="ASCOM.Utilities, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL" />
<Reference Include="ASCOM.Utilities.Video, Version=6.1.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL" />
<Reference Include="System" />
<Reference Include="System.configuration" />
<Reference Include="System.Configuration.Install" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Switch.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
<DependentUpon>Settings.settings</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Properties\Resources.resx">
<SubType>Designer</SubType>
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="ASCOM.png" />
<None Include="ASCOMDriverTemplate.snk" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Content Include="ASCOM.ico" />
<Content Include="ReadMe.htm" />
<None Include="Resources\ASCOM.bmp" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
<Visible>False</Visible>
<ProductName>Windows Installer 3.1</ProductName>
<Install>true</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LynxAstro.DewController\LynxAstro.DewController.csproj">
<Project>{c708e487-e3a9-4073-a545-294b88674225}</Project>
<Name>LynxAstro.DewController</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PreBuildEvent>
</PreBuildEvent>
</PropertyGroup>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
@@ -0,0 +1,38 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
//
// TODO - Add your authorship information here
[assembly: AssemblyTitle("ASCOM.LynxAstro.DewController.Switch")]
[assembly: AssemblyDescription("ASCOM Switch driver for LynxAstro.DewController")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("The ASCOM Initiative")]
[assembly: AssemblyProduct("ASCOM Switch driver for LynxAstro.DewController")]
[assembly: AssemblyCopyright("Copyright © 2021 The ASCOM Initiative")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(true)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("a567b01c-a066-45ce-af3d-0192bad973ea")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
//
// TODO - Set your driver's version here
[assembly: AssemblyVersion("6.5.1.0")]
[assembly: AssemblyFileVersion("6.5.1.0")]
@@ -0,0 +1,96 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace ASCOM.LynxAstro.DewController.Properties
{
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources
{
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources()
{
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if (object.ReferenceEquals(resourceMan, null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ASCOM.LynxAstro.DewController.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap ASCOM
{
get
{
object obj = ResourceManager.GetObject("ASCOM", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
/// </summary>
internal static System.Drawing.Icon DefaultIcon
{
get
{
object obj = ResourceManager.GetObject("DefaultIcon", resourceCulture);
return ((System.Drawing.Icon)(obj));
}
}
}
}
@@ -0,0 +1,127 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="ASCOM" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\ASCOM.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="DefaultIcon" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\ASCOM.ico;System.Drawing.Icon, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>
@@ -0,0 +1,30 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace ASCOM.LynxAstro.DewController.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.4.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
return defaultInstance;
}
}
}
}
@@ -0,0 +1,5 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles />
<Settings />
</SettingsFile>
+147
View File
@@ -0,0 +1,147 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=windows-1252">
<TITLE>Untitled Document</TITLE>
<META NAME="GENERATOR" CONTENT="OpenOffice.org 3.2 (Win32)">
<META NAME="CREATED" CONTENT="0;0">
<META NAME="CHANGEDBY" CONTENT="Chris Rowland">
<META NAME="CHANGED" CONTENT="20110918;14150500">
<STYLE TYPE="text/css">
<!--
@page { margin: 2cm }
P { font-family: "Verdana", "Arial", "Helvetica", sans-serif; font-weight: normal }
TD P { font-family: "Verdana", "Arial", "Helvetica", sans-serif; font-weight: normal }
H3 { font-family: "Arial", "Helvetica", sans-serif }
H2 { font-family: "Arial", "Helvetica", sans-serif }
H4 { font-family: "Arial", "Helvetica", sans-serif }
TD P.note { background: #33ffff; font-family: "Verdana", "Arial", "Helvetica", sans-serif; font-weight: normal }
TD P.underline { font-family: "Verdana", "Arial", "Helvetica", sans-serif; font-weight: normal; text-decoration: underline }
-->
</STYLE>
</HEAD>
<BODY LANG="en-GB" DIR="LTR">
<TABLE WIDTH=100% BORDER=0 CELLPADDING=4 CELLSPACING=0>
<TR>
<TD>
<H2>ASCOM Switch Driver (C#)</H2>
</TD>
</TR>
</TABLE>
<P><BR><BR>
</P>
<H4>You have just created the skeleton of an ASCOM
Switch driver in C#. It produces an in-process
(assembly) based driver.</H4>
<HR>
<P CLASS="note">Prior to developing your first driver, please
familiarize yourself with the <A HREF="https://ascom-standards.org/developer.html">developer
information we've provided</A> at the ASCOM Initiative web site
(internet required).
</P>
<P CLASS="underline">You must do the following in order to complete
your implementation:</P>
<OL>
<LI><P STYLE="margin-bottom: 0cm">Switch to the Debug configuration
and build the template now. It should build without errors.
</P>
<LI><P STYLE="margin-bottom: 0cm">Add a test project to the
solution. There are templates that can be used to add either a
console or a Windows Forms application:</P>
</OL>
<UL>
<LI><P STYLE="margin-bottom: 0cm">Select the <FONT FACE="Consolas, monospace">ASCOM
Test Forms App (CS)</FONT> or <FONT FACE="Consolas, monospace">ASCOM
Test Console App (CS)</FONT> template.</P>
<LI><P STYLE="margin-bottom: 0cm">Set a name for the test
application and click on OK.</P>
<LI><P STYLE="margin-bottom: 0cm">In the Wizard: set the same device
type and model name as for the driver and select Create to build the
test project.</P>
<LI><P STYLE="margin-bottom: 0cm">Set the Test Application to Run at
Startup.</P>
<LI><P STYLE="margin-bottom: 0cm">Click on Debug and the test
application should run. You should be able to select your
application in the chooser. Selecting Properties should show the
default setup dialog for your driver.</P>
<LI><P STYLE="margin-bottom: 0cm">Trying to continue will generate
errors because the additional properties have not been implemented.</P>
</UL>
<OL START=4>
<LI><P STYLE="margin-bottom: 0cm">Go through the Driver.cs file and
replace the System.NotImplemented exceptions with code to implement
your driver's functionality. See the ASCOM ISwitchV2
spec. If a property or method is not implemented in your driver the
System.NotImplemented exception must be replaced by an
ASCOM.PropertyNotImplemented or ASCOM.MethodNotImplemented
exception.</P>
<LI><P>Customize the Setup Dialog (SetupDialogForm) to provide the
settings and other controls for your driver. You can bind settings
directly to controls on your dialog form, there's no need to manage
settings manually. A custom Settings class takes care of managing
your settings behind the scenes.
</P>
</OL>
<H3>Notes:</H3>
<UL>
<LI><P STYLE="margin-bottom: 0cm">Successfully building the driver,
as well as using <FONT FACE="Lucida Console, Courier New, Courier, monospace">regasm</FONT>
on the assembly, registers it for both COM and ASCOM (the Chooser).
See the code in the ASCOM Registration region of Driver.vb.
</P>
<LI><P STYLE="margin-bottom: 0cm">Doing a Clean for the project, as
well doing a <FONT FACE="Lucida Console, Courier New, Courier, monospace">regasm
-u</FONT> on the assembly, unregisters it for both COM and ASCOM
(the Chooser).
</P>
<LI><P>Place a breakpoint in your driver class constructor, then
start debugging (go, F5). Your breakpoint will be hit when the test
application creates an instance of your driver (after selecting it
in the Chooser). You can now single step, examine variables, etc.
Please review the test application and make changes and additions to
activate various parts of your driver during debugging.</P>
<LI><P>The project's Debug configuration is already configured (The
test application creates an instance of your driver (after selecting
it in the Chooser). You can now single step, examine variables, etc.
Please review the test application and feel free to make changes and
additions to activate various parts of your driver during debugging.
</P>
</UL>
<DIV ALIGN=RIGHT>
<TABLE WIDTH=100% BORDER=0 CELLPADDING=4 CELLSPACING=0>
<TR>
<TD>
<TABLE WIDTH=100% BORDER=0 CELLPADDING=4 CELLSPACING=0>
<TR>
<TD>
<H3>ASCOM Initiative</H3>
</TD>
<TD>
<IMG SRC="ASCOM.png" NAME="graphics1" ALIGN=RIGHT WIDTH=48 HEIGHT=56 BORDER=0></TD>
</TR>
</TABLE>
<P><BR><BR>
</P>
</TD>
</TR>
<TR>
<TD>
<P>The ASCOM Initiative consists of a group of astronomy software
developers and instrument vendors whose goals are to promote the
driver/client model and scripting automation.
</P>
<P>See the <A HREF="https://ascom-standards.org/" TARGET="browser">ASCOM
web site</A> for more information. Please participate in the
<A HREF="https://ascomtalk.groups.io/g/Help/topics" TARGET="browser">ASCOM-Talk
Groups.IO forum</A>.
</P>
</TD>
</TR>
</TABLE>
</DIV>
<P><BR><BR>
</P><P>
<BR><BR>
</P>
</BODY>
</HTML>
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

+695
View File
@@ -0,0 +1,695 @@
#define Switch
using System;
using System.Runtime.InteropServices;
using ASCOM.Utilities;
using ASCOM.DeviceInterface;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
namespace ASCOM.LynxAstro.DewController
{
//
// Your driver's DeviceID is ASCOM.LynxAstro.DewController.Switch
//
// The Guid attribute sets the CLSID for ASCOM.LynxAstro.DewController.Switch
// The ClassInterface/None attribute prevents an empty interface called
// _LynxAstro.DewController from being created and used as the [default] interface
//
// TODO Replace the not implemented exceptions with code to implement the function or
// throw the appropriate ASCOM exception.
//
/// <summary>
/// ASCOM Switch Driver for LynxAstro.DewController.
/// </summary>
[Guid("3a29744a-f33f-4843-a7e0-6938d9bd50ba")]
[ProgId("ASCOM.LynxAstro.DewController.Switch")]
[ServedClassName("LynxAstro.DewController")]
[ClassInterface(ClassInterfaceType.None)]
public class Switch : ISwitchV2
{
/// <summary>
/// ASCOM DeviceID (COM ProgID) for this driver.
/// The DeviceID is used by ASCOM applications to load the driver at runtime.
/// </summary>
internal static string DriverId = Marshal.GenerateProgIdForType(MethodBase.GetCurrentMethod().DeclaringType ?? throw new System.InvalidOperationException());
/// <summary>
/// Driver description that displays in the ASCOM Chooser.
/// </summary>
private static string DriverDescription = "ASCOM Switch Driver for LynxAstro.DewController";
protected static string ComPort; // Variables to hold the currrent device configuration
protected static TraceLogger Tl;
protected readonly ISharedResourcesWrapper SharedResourcesWrapper;
/// <summary>
/// Initializes a new instance of the <see cref="LynxAstro.DewController"/> class.
/// Must be public for COM registration.
/// </summary>
/// <param name="tl"></param>
public Switch()
{
SharedResourcesWrapper = new SharedResourcesWrapper();
Initialise(nameof(Switch));
}
public Switch(ISharedResourcesWrapper sharedResourcesWrapper)
{
SharedResourcesWrapper = sharedResourcesWrapper;
Initialise(nameof(Switch));
}
protected void Initialise(string className)
{
Tl = new TraceLogger("", $"LynxAstro.DewController.{className}");
ReadProfile(); // Read device configuration from the ASCOM Profile store
IsConnected = false; // Initialise connected to false
LogMessage(className, "Completed initialisation");
LogMessage(className, $"Driver version: {DriverVersion}");
}
//
// PUBLIC COM INTERFACE ISwitchV2 IMPLEMENTATION
//
#region Common properties and methods.
/// <summary>
/// Displays the Setup Dialog form.
/// If the user clicks the OK button to dismiss the form, then
/// the new settings are saved, otherwise the old values are reloaded.
/// THIS IS THE ONLY PLACE WHERE SHOWING USER INTERFACE IS ALLOWED!
/// </summary>
public void SetupDialog()
{
LogMessage("SetupDialog", "Opening setup dialog");
SharedResourcesWrapper.SetupDialog();
ReadProfile();
LogMessage("SetupDialog", "complete");
}
public ArrayList SupportedActions
{
get
{
Tl.LogMessage("SupportedActions Get", "Returning empty arraylist");
return new ArrayList();
}
}
public string Action(string actionName, string actionParameters)
{
LogMessage("", "Action {0}, parameters {1} not implemented", actionName, actionParameters);
throw new ASCOM.ActionNotImplementedException("Action " + actionName + " is not implemented by this driver");
}
public void CommandBlind(string command, bool raw)
{
CheckConnected("CommandBlind");
SharedResourcesWrapper.SendBlind(command);
}
public bool CommandBool(string command, bool raw)
{
CheckConnected("CommandBool");
throw new ASCOM.MethodNotImplementedException("CommandBool");
}
public string CommandString(string command, bool raw)
{
CheckConnected("CommandString");
return SharedResourcesWrapper.SendString(command);
}
public void Dispose()
{
// Clean up the trace logger and util objects
Tl.Enabled = false;
Tl.Dispose();
Tl = null;
}
private string DecodeResult(string pattern, string encodedString)
{
var decodedString = encodedString.Substring(pattern.Length).TrimEnd('#');
return decodedString;
}
public bool Connected
{
get
{
LogMessage("Connected", "Get {0}", IsConnected);
return IsConnected;
}
set
{
LogMessage("Connected", "Set {0}", value);
if (value == IsConnected)
return;
if (value)
{
try
{
ReadProfile();
LogMessage("Connected Set", "Connecting to port {0}", ComPort);
var connectionInfo = SharedResourcesWrapper.Connect("Serial", DriverId, Tl);
try
{
LogMessage("Connected Set", $"Connected to port {ComPort}. Version:{SharedResourcesWrapper.FirmwareVersion}");
IsConnected = true;
LogMessage("Connected Set", $"Connected OK.");
var maxSwitch = MaxSwitch;
}
catch (Exception)
{
SharedResourcesWrapper.Disconnect("Serial", DriverId);
throw;
}
}
catch (Exception ex)
{
LogMessage("Connected Set", "Error connecting to port {0} - {1}", ComPort, ex.Message);
}
}
else
{
LogMessage("Connected Set", "Disconnecting from port {0}", ComPort);
SharedResourcesWrapper.Disconnect("Serial", DriverId);
IsConnected = false;
}
}
}
public string Description
{
get
{
Tl.LogMessage("Description Get", DriverDescription);
return DriverDescription;
}
}
public string DriverInfo
{
get
{
string driverInfo = $"{Description} .net driver. Version: {DriverVersion}";
LogMessage("DriverInfo Get", driverInfo);
return driverInfo;
}
}
public string DriverVersion
{
get
{
Version version = Assembly.GetExecutingAssembly().GetName().Version;
string driverVersion = $"{version.Major}.{version.Minor}.{version.Build}.{version.Revision}";
LogMessage("DriverVersion Get", driverVersion);
return driverVersion;
}
}
public short InterfaceVersion
{
// set by the driver wizard
get
{
LogMessage("InterfaceVersion Get", "2");
return Convert.ToInt16("2");
}
}
public string Name
{
get
{
string name = "LynxAstro.DewController";
Tl.LogMessage("Name Get", name);
return name;
}
}
#endregion
#region ISwitchV2 Implementation
private short numSwitch = 0;
private List<string> switchNames = new List<string>();
/// <summary>
/// The number of switches managed by this driver
/// </summary>
public short MaxSwitch
{
get
{
CheckConnected("MaxSwitch Get");
var result = SharedResourcesWrapper.SendString(":GD#");
var decoded = DecodeResult(":GD", result);
this.numSwitch = short.Parse(decoded);
//Command: :GD#
//Purpose: Get the device type, i.e.the number of channels the dew controller has.
//Response: :GDX# where X is either 1 or 4 depending on the number of channels this device has
Tl.LogMessage("MaxSwitch Get", numSwitch.ToString());
return this.numSwitch;
}
}
/// <summary>
/// Return the name of switch n
/// </summary>
/// <param name="id">The switch number to return</param>
/// <returns>
/// The name of the switch
/// </returns>
public string GetSwitchName(short id)
{
Validate("GetSwitchName", id);
ReadProfile();
return switchNames.Count > id ? switchNames[id] : string.Empty;
}
/// <summary>
/// Sets a switch name to a specified value
/// </summary>
/// <param name="id">The number of the switch whose name is to be set</param>
/// <param name="name">The name of the switch</param>
public void SetSwitchName(short id, string name)
{
Validate("SetSwitchName", id);
ReadProfile();
while (id > switchNames.Count)
switchNames.Add(string.Empty);
switchNames[id] = name;
WriteSwitchNames();
}
/// <summary>
/// Gets the switch description.
/// </summary>
/// <param name="id">The id.</param>
/// <returns></returns>
public string GetSwitchDescription(short id)
{
Validate("GetSwitchDescription", id);
return "Control Knob";
}
/// <summary>
/// Reports if the specified switch can be written to.
/// This is false if the switch cannot be written to, for example a limit switch or a sensor.
/// The default is true.
/// </summary>
/// <param name="id">The number of the switch whose write state is to be returned</param><returns>
/// <c>true</c> if the switch can be written to, otherwise <c>false</c>.
/// </returns>
/// <exception cref="MethodNotImplementedException">If the method is not implemented</exception>
/// <exception cref="InvalidValueException">If id is outside the range 0 to MaxSwitch - 1</exception>
public bool CanWrite(short id)
{
Validate("CanWrite", id);
// default behavour is to report true
Tl.LogMessage("CanWrite", string.Format("CanWrite({0}) - default true", id));
return true;
// implementation should report the correct behaviour
//tl.LogMessage("CanWrite", string.Format("CanWrite({0}) - not implemented", id));
//throw new MethodNotImplementedException("CanWrite");
}
#region boolean switch members
/// <summary>
/// Return the state of switch n
/// a multi-value switch must throw a not implemented exception
/// </summary>
/// <param name="id">The switch number to return</param>
/// <returns>
/// True or false
/// </returns>
public bool GetSwitch(short id)
{
var value = GetSwitchValue(id);
return value > 0;
}
/// <summary>
/// Sets a switch to the specified state
/// If the switch cannot be set then throws a MethodNotImplementedException.
/// A multi-value switch must throw a not implemented exception
/// setting it to false will set it to its minimum value.
/// </summary>
/// <param name="id"></param>
/// <param name="state"></param>
public void SetSwitch(short id, bool state)
{
Validate("SetSwitch", id);
if (!CanWrite(id))
{
var str = string.Format("SetSwitch({0}) - Cannot Write", id);
Tl.LogMessage("SetSwitch", str);
throw new MethodNotImplementedException(str);
}
SetSwitchValue(id, state ? 1023 : 0);
}
#endregion
#region analogue members
/// <summary>
/// returns the maximum value for this switch
/// boolean switches must return 1.0
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public double MaxSwitchValue(short id)
{
Validate("MaxSwitchValue", id);
// boolean switch implementation:
return 1023;
// or
//tl.LogMessage("MaxSwitchValue", string.Format("MaxSwitchValue({0}) - not implemented", id));
//throw new MethodNotImplementedException("MaxSwitchValue");
}
/// <summary>
/// returns the minimum value for this switch
/// boolean switches must return 0.0
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public double MinSwitchValue(short id)
{
Validate("MinSwitchValue", id);
// boolean switch implementation:
return 0;
// or
//tl.LogMessage("MinSwitchValue", string.Format("MinSwitchValue({0}) - not implemented", id));
//throw new MethodNotImplementedException("MinSwitchValue");
}
/// <summary>
/// returns the step size that this switch supports. This gives the difference between
/// successive values of the switch.
/// The number of values is ((MaxSwitchValue - MinSwitchValue) / SwitchStep) + 1
/// boolean switches must return 1.0, giving two states.
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public double SwitchStep(short id)
{
Validate("SwitchStep", id);
// boolean switch implementation:
return 1;
// or
//tl.LogMessage("SwitchStep", string.Format("SwitchStep({0}) - not implemented", id));
//throw new MethodNotImplementedException("SwitchStep");
}
/// <summary>
/// returns the analogue switch value for switch id
/// boolean switches must throw a not implemented exception
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public double GetSwitchValue(short id)
{
Validate("GetSwitchValue", id);
Tl.LogMessage("GetSwitchValue", string.Format("GetSwitchValue({0}) - not implemented", id));
var channel = ChannelToLetter(id);
var encoded = SharedResourcesWrapper.SendString($":GC{channel}#");
var decoded = DecodeResult(":GC", encoded);
return double.Parse(decoded.TrimStart(channel));
//Command: :GCX# where X is the channel A, B, C or D to retrieve.
//Purpose: Get the current power setting for a specific channel.
//Response: :GCXVVVV# where X is the channel A, B, C or D returned and VVVV is the power level between 0 - 1023.
//Possible Errors
//:ER5# = Channel out of range, e.g. channel B on a 1 channel device.
}
private char ChannelToLetter(short id)
{
UInt16 ord = (UInt16) 'A';
ord += (ushort)id;
return (char)ord;
}
/// <summary>
/// set the analogue value for this switch.
/// If the switch cannot be set then throws a MethodNotImplementedException.
/// If the value is not between the maximum and minimum then throws an InvalidValueException
/// boolean switches must throw a not implemented exception.
/// </summary>
/// <param name="id"></param>
/// <param name="value"></param>
public void SetSwitchValue(short id, double value)
{
Validate("SetSwitchValue", id, value);
if (!CanWrite(id))
{
Tl.LogMessage("SetSwitchValue", string.Format("SetSwitchValue({0}) - Cannot write", id));
throw new ASCOM.MethodNotImplementedException(string.Format("SetSwitchValue({0}) - Cannot write", id));
}
//Tl.LogMessage("SetSwitchValue", string.Format("SetSwitchValue({0}) = {1} - not implemented", id, value));
//throw new MethodNotImplementedException("SetSwitchValue");
//Command: :SCXVVVV# where X is the channel A, B, C or D to set and VVVV is the power level
//between 0 - 1023.The power level must be 4 digits long so pad with leading zeros if necessary.
//Purpose: Set the current power setting for a specific channel.
//Response: :SC1# indicates success. Run a GA or GC command to verify.
//Possible Errors
//:ER4# = Not enough data received - make sure you zero pad the power level.
//:ER5# = Channel or power level out of range, e.g. channel B on a 1 channel device or power above 1023.
var channel = ChannelToLetter(id);
var encoded = SharedResourcesWrapper.SendString($":SC{channel}{value:0000}#");
var decoded = DecodeResult(":SC", encoded);
if (decoded != "1")
{
throw new InvalidValueException($"Unable to set switch {{id}} to value {value}");
}
//return double.Parse(decoded.TrimStart(channel));
}
#endregion
#endregion
#region private methods
/// <summary>
/// Checks that the switch id is in range and throws an InvalidValueException if it isn't
/// </summary>
/// <param name="message">The message.</param>
/// <param name="id">The id.</param>
private void Validate(string message, short id)
{
if (id < 0 || id >= numSwitch)
{
Tl.LogMessage(message, string.Format("Switch {0} not available, range is 0 to {1}", id, numSwitch - 1));
throw new InvalidValueException(message, id.ToString(), string.Format("0 to {0}", numSwitch - 1));
}
}
/// <summary>
/// Checks that the switch id and value are in range and throws an
/// InvalidValueException if they are not.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="id">The id.</param>
/// <param name="value">The value.</param>
private void Validate(string message, short id, double value)
{
Validate(message, id);
var min = MinSwitchValue(id);
var max = MaxSwitchValue(id);
if (value < min || value > max)
{
Tl.LogMessage(message, string.Format("Value {1} for Switch {0} is out of the allowed range {2} to {3}", id, value, min, max));
throw new InvalidValueException(message, value.ToString(), string.Format("Switch({0}) range {1} to {2}", id, min, max));
}
}
/// <summary>
/// Checks that the number of states for the switch is correct and throws a methodNotImplemented exception if not.
/// Boolean switches must have 2 states and multi-value switches more than 2.
/// </summary>
/// <param name="message"></param>
/// <param name="id"></param>
/// <param name="expectBoolean"></param>
//private void Validate(string message, short id, bool expectBoolean)
//{
// Validate(message, id);
// var ns = (int)(((MaxSwitchValue(id) - MinSwitchValue(id)) / SwitchStep(id)) + 1);
// if ((expectBoolean && ns != 2) || (!expectBoolean && ns <= 2))
// {
// tl.LogMessage(message, string.Format("Switch {0} has the wriong number of states", id, ns));
// throw new MethodNotImplementedException(string.Format("{0}({1})", message, id));
// }
//}
#endregion
#region Private properties and methods
// here are some useful properties and methods that can be used as required
// to help with driver development
#region ASCOM Registration
// Register or unregister driver for ASCOM. This is harmless if already
// registered or unregistered.
//
/// <summary>
/// Register or unregister the driver with the ASCOM Platform.
/// This is harmless if the driver is already registered/unregistered.
/// </summary>
/// <param name="bRegister">If <c>true</c>, registers the driver, otherwise unregisters it.</param>
private static void RegUnregASCOM(bool bRegister)
{
using (var P = new ASCOM.Utilities.Profile())
{
P.DeviceType = "Switch";
if (bRegister)
{
P.Register(DriverId, DriverDescription);
}
else
{
P.Unregister(DriverId);
}
}
}
/// <summary>
/// This function registers the driver with the ASCOM Chooser and
/// is called automatically whenever this class is registered for COM Interop.
/// </summary>
/// <param name="t">Type of the class being registered, not used.</param>
/// <remarks>
/// This method typically runs in two distinct situations:
/// <list type="numbered">
/// <item>
/// In Visual Studio, when the project is successfully built.
/// For this to work correctly, the option <c>Register for COM Interop</c>
/// must be enabled in the project settings.
/// </item>
/// <item>During setup, when the installer registers the assembly for COM Interop.</item>
/// </list>
/// This technique should mean that it is never necessary to manually register a driver with ASCOM.
/// </remarks>
[ComRegisterFunction]
public static void RegisterASCOM(Type t)
{
RegUnregASCOM(true);
}
/// <summary>
/// This function unregisters the driver from the ASCOM Chooser and
/// is called automatically whenever this class is unregistered from COM Interop.
/// </summary>
/// <param name="t">Type of the class being registered, not used.</param>
/// <remarks>
/// This method typically runs in two distinct situations:
/// <list type="numbered">
/// <item>
/// In Visual Studio, when the project is cleaned or prior to rebuilding.
/// For this to work correctly, the option <c>Register for COM Interop</c>
/// must be enabled in the project settings.
/// </item>
/// <item>During uninstall, when the installer unregisters the assembly from COM Interop.</item>
/// </list>
/// This technique should mean that it is never necessary to manually unregister a driver from ASCOM.
/// </remarks>
[ComUnregisterFunction]
public static void UnregisterASCOM(Type t)
{
RegUnregASCOM(false);
}
#endregion
protected bool IsConnected { get; set; }
/// <summary>
/// Use this function to throw an exception if we aren't connected to the hardware
/// </summary>
/// <param name="message"></param>
private void CheckConnected(string message)
{
if (!IsConnected)
{
throw new ASCOM.NotConnectedException(message);
}
}
/// <summary>
/// Read the device configuration from the ASCOM Profile store
/// </summary>
protected void ReadProfile()
{
var profileProperties = SharedResourcesWrapper.ReadProfile();
Tl.Enabled = profileProperties.TraceLogger;
ComPort = profileProperties.ComPort;
switchNames.Clear();
switchNames.AddRange(profileProperties.SwitchNames);
LogMessage("ReadProfile", $"Trace logger enabled: {Tl.Enabled}");
LogMessage("ReadProfile", $"Com Port: {ComPort}");
}
protected void WriteSwitchNames()
{
var profileProperties = SharedResourcesWrapper.ReadProfile();
profileProperties.SwitchNames.Clear();
profileProperties.SwitchNames.AddRange(switchNames);
SharedResourcesWrapper.WriteProfile(profileProperties);
}
/// <summary>
/// Log helper function that takes formatted strings and arguments
/// </summary>
/// <param name="identifier"></param>
/// <param name="message"></param>
/// <param name="args"></param>
internal void LogMessage(string identifier, string message, params object[] args)
{
var msg = string.Format(message, args);
Tl.LogMessage(identifier, msg);
}
#endregion
}
}
@@ -0,0 +1,8 @@
<?xml version="1.0"?>
<configuration>
<configSections>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<section name="ASCOM.DeviceName.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false"/>
</sectionGroup>
</configSections>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/></startup></configuration>
@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{D5207217-61C7-4E94-8097-91DBACE57D2A}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>ASCOM.LynxAstro.DewController</RootNamespace>
<AssemblyName>ASCOM.LynxAstro.DewController.TestConsole</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<PlatformTarget>x86</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="ASCOM.DeviceInterfaces, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL" />
<Reference Include="ASCOM.DriverAccess, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
@@ -0,0 +1,78 @@
// This implements a console application that can be used to test an ASCOM driver
//
// This is used to define code in the template that is specific to one class implementation
// unused code can be deleted and this definition removed.
#define Switch
// remove this to bypass the code that uses the chooser to select the driver
//#define UseChooser
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ASCOM
{
class Program
{
static void Main(string[] args)
{
// Uncomment the code that's required
#if UseChooser
// choose the device
string id = ASCOM.DriverAccess.Switch.Choose("");
if (string.IsNullOrEmpty(id))
return;
// create this device
ASCOM.DriverAccess.Switch device = new ASCOM.DriverAccess.Switch(id);
#else
// this can be replaced by this code, it avoids the chooser and creates the driver class directly.
ASCOM.DriverAccess.Switch device = new ASCOM.DriverAccess.Switch("ASCOM.LynxAstro.DewController.Switch");
#endif
// now run some tests, adding code to your driver so that the tests will pass.
// these first tests are common to all drivers.
Console.WriteLine("name " + device.Name);
Console.WriteLine("description " + device.Description);
Console.WriteLine("DriverInfo " + device.DriverInfo);
Console.WriteLine("driverVersion " + device.DriverVersion);
// TODO add more code to test the driver.
device.Connected = true;
Console.WriteLine("Number of switches: " + device.MaxSwitch);
for (short i = 0; i < device.MaxSwitch; i++)
{
var min = device.MinSwitchValue(i);
var max = device.MaxSwitchValue(i);
var step = device.SwitchStep(i);
var value = device.GetSwitchValue(i);
Console.WriteLine($"switch {i}: {min} - {max} stepsize {step}: {value}");
}
for (short i = 0; i < device.MaxSwitch; i++)
{
device.SetSwitchValue(i, 500);
}
for (short i = 0; i < device.MaxSwitch; i++)
{
var min = device.MinSwitchValue(i);
var max = device.MaxSwitchValue(i);
var step = device.SwitchStep(i);
var value = device.GetSwitchValue(i);
Console.WriteLine($"switch {i}: {min} - {max} stepsize {step}: {value}");
}
device.Connected = false;
Console.WriteLine("Press Enter to finish");
Console.ReadLine();
}
}
}
@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("LynxAstro.DewController Test Application")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("ASCOM Initiative")]
[assembly: AssemblyProduct("LynxAstro.DewController")]
[assembly: AssemblyCopyright("Copyright © ASCOM Initiative 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("c7008f94-e3b9-4481-b720-3b56557860c6")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("6.4.0.0")]
[assembly: AssemblyFileVersion("6.4.0.0")]
@@ -0,0 +1,3 @@
<?xml version="1.0"?>
<configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/></startup></configuration>
@@ -0,0 +1,115 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\NUnit.3.13.1\build\NUnit.props" Condition="Exists('..\packages\NUnit.3.13.1\build\NUnit.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{BDED8EBB-7F9F-4710-8B74-59298C2DFCAD}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>LynxAstro.DewController.UnitTests</RootNamespace>
<AssemblyName>LynxAstro.DewController.UnitTests</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="ASCOM.Astrometry, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>..\packages\ASCOM.Platform.6.5.2\lib\net40\ASCOM.Astrometry.dll</HintPath>
</Reference>
<Reference Include="ASCOM.Attributes, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>..\packages\ASCOM.Platform.6.5.2\lib\net40\ASCOM.Attributes.dll</HintPath>
</Reference>
<Reference Include="ASCOM.Cache, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>..\packages\ASCOM.Platform.6.5.2\lib\net40\ASCOM.Cache.dll</HintPath>
</Reference>
<Reference Include="ASCOM.Controls, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>..\packages\ASCOM.Platform.6.5.2\lib\net40\ASCOM.Controls.dll</HintPath>
</Reference>
<Reference Include="ASCOM.DeviceInterfaces, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>..\packages\ASCOM.Platform.6.5.2\lib\net40\ASCOM.DeviceInterfaces.dll</HintPath>
</Reference>
<Reference Include="ASCOM.DriverAccess, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>..\packages\ASCOM.Platform.6.5.2\lib\net40\ASCOM.DriverAccess.dll</HintPath>
</Reference>
<Reference Include="ASCOM.Exceptions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>..\packages\ASCOM.Platform.6.5.2\lib\net40\ASCOM.Exceptions.dll</HintPath>
</Reference>
<Reference Include="ASCOM.Internal.Extensions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>..\packages\ASCOM.Platform.6.5.2\lib\net40\ASCOM.Internal.Extensions.dll</HintPath>
</Reference>
<Reference Include="ASCOM.SettingsProvider, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>..\packages\ASCOM.Platform.6.5.2\lib\net40\ASCOM.SettingsProvider.dll</HintPath>
</Reference>
<Reference Include="ASCOM.Utilities, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>..\packages\ASCOM.Platform.6.5.2\lib\net40\ASCOM.Utilities.dll</HintPath>
</Reference>
<Reference Include="ASCOM.Utilities.Video, Version=6.1.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>..\packages\ASCOM.Platform.6.5.2\lib\net40\ASCOM.Utilities.Video.dll</HintPath>
</Reference>
<Reference Include="Castle.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
<HintPath>..\packages\Castle.Core.4.4.0\lib\net45\Castle.Core.dll</HintPath>
</Reference>
<Reference Include="Moq, Version=4.16.0.0, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
<HintPath>..\packages\Moq.4.16.0\lib\net45\Moq.dll</HintPath>
</Reference>
<Reference Include="nunit.framework, Version=3.13.1.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<HintPath>..\packages\NUnit.3.13.1\lib\net45\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="SharedResourcesUnitTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LynxAstro.DewController\LynxAstro.DewController.csproj">
<Project>{c708e487-e3a9-4073-a545-294b88674225}</Project>
<Name>LynxAstro.DewController</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\NUnit.3.13.1\build\NUnit.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NUnit.3.13.1\build\NUnit.props'))" />
</Target>
</Project>
@@ -0,0 +1,35 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("LynxAstro.DewController.UnitTests")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("LynxAstro.DewController.UnitTests")]
[assembly: AssemblyCopyright("Copyright © 2021")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("bded8ebb-7f9f-4710-8b74-59298c2dfcad")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
@@ -0,0 +1,189 @@
using System;
using System.Security.Cryptography.X509Certificates;
using ASCOM.LynxAstro.DewController;
using ASCOM.Utilities.Interfaces;
using Moq;
using NUnit.Framework;
namespace LynxAstro.DewController.UnitTests
{
[TestFixture]
public class SharedResourcesUnitTests
{
private Mock<ISerial> _serialMock;
private Mock<ITraceLogger> _traceLoggerMock;
[SetUp]
public void Setup()
{
_serialMock = new Mock<ISerial>();
_serialMock.SetupAllProperties();
_traceLoggerMock = new Mock<ITraceLogger>();
SharedResources.SharedSerial = _serialMock.Object;
}
[Test]
public void CheckThatSerialPortIsSetToUseMock()
{
Assert.That(SharedResources.SharedSerial, Is.EqualTo(_serialMock.Object));
}
[Test]
public void SendBlind_WhenCalled_Then_ClearsBuffersAndSendsMessage()
{
var expectedMessage = "Test";
SharedResources.SendBlind(expectedMessage);
_serialMock.Verify(x => x.ClearBuffers(), Times.Once);
_serialMock.Verify(x => x.Transmit(expectedMessage), Times.Once);
}
[Test]
public void SendChar_WhenCalled_ThenSendsMessageAndReadsExpectedNumberOfCharacters()
{
var expectedMessage = "Test";
var expectedResult = "A";
_serialMock.Setup(x => x.ReceiveCounted(1)).Returns(expectedResult);
var result = SharedResources.SendChar(expectedMessage);
_serialMock.Verify(x => x.ClearBuffers(), Times.Once);
_serialMock.Verify(x => x.Transmit(expectedMessage), Times.Once);
_serialMock.Verify(x => x.ReceiveCounted(1), Times.Once);
Assert.That(result, Is.EqualTo(expectedResult));
}
[Test]
public void SendString_WhenCalled_ThenSendsMessageAndReadsResultUntilTerminatorFound()
{
var expectedMessage = "Test";
var expectedResult = "TestMessage#";
_serialMock.Setup(x => x.ReceiveTerminated("#")).Returns(expectedResult);
var result = SharedResources.SendString(expectedMessage);
_serialMock.Verify(x => x.ClearBuffers(), Times.Once);
_serialMock.Verify(x => x.Transmit(expectedMessage), Times.Once);
_serialMock.Verify(x => x.ReceiveTerminated("#"), Times.Once);
Assert.That(result, Is.EqualTo(expectedResult.TrimEnd('#')));
}
[Test]
public void ReadTerminated_WhenCalled_ThenReadsResultUntilTerminatorFound()
{
var expectedResult = "TestMessage#";
_serialMock.Setup(x => x.ReceiveTerminated("#")).Returns(expectedResult);
var result = SharedResources.ReadTerminated();
_serialMock.Verify(x => x.ReceiveTerminated("#"), Times.Once);
Assert.That(result, Is.EqualTo(expectedResult));
}
[Test]
public void ReadCharacters_WhenCalled_ThenReadsSpecificNumberOfCharacters()
{
var numberOfCharacters = 5;
SharedResources.ReadCharacters(numberOfCharacters);
_serialMock.Verify(x => x.ReceiveCounted(numberOfCharacters), Times.Once);
}
[Test]
public void WriteProfile_WhenCalled_WritesExpectedProfileSettings()
{
string DriverId = "ASCOM.MeadeGeneric.Telescope";
Mock<IProfileWrapper> profileWrapperMock = new Mock<IProfileWrapper>();
profileWrapperMock.SetupAllProperties();
IProfileWrapper profeWrapper = profileWrapperMock.Object;
Mock<IProfileFactory> profileFactoryMock = new Mock<IProfileFactory>();
profileFactoryMock.Setup(x => x.Create()).Returns(profileWrapperMock.Object);
SharedResources.ProfileFactory = profileFactoryMock.Object;
var profileProperties = new ProfileProperties
{
TraceLogger = false,
ComPort = "TestComPort"
};
SharedResources.WriteProfile(profileProperties);
Assert.That(profeWrapper.DeviceType, Is.EqualTo("Telescope"));
profileWrapperMock.Verify(x => x.WriteValue(DriverId, "Trace Level", profileProperties.TraceLogger.ToString()), Times.Once);
profileWrapperMock.Verify(x => x.WriteValue(DriverId, "COM Port", profileProperties.ComPort), Times.Once);
}
[Test]
public void ReadProfile_WhenCalled_ReturnsExpectedDefaultValues()
{
string DriverId = "ASCOM.MeadeGeneric.Telescope";
string ComPortDefault = "COM1";
string TraceStateDefault = "false";
string GuideRateProfileNameDefault = "10.077939"; //67% of sidereal rate
string PrecisionDefault = "Unchanged";
string GuidingStyleDefault = "Auto";
string BacklashCompensationDefault = "3000";
string ReverseFocuserDiectionDefault = "true";
Mock<IProfileWrapper> profileWrapperMock = new Mock<IProfileWrapper>();
profileWrapperMock.SetupAllProperties();
profileWrapperMock.Setup(x => x.GetValue(DriverId, "Trace Level", string.Empty, TraceStateDefault))
.Returns(() =>
TraceStateDefault);
profileWrapperMock.Setup(x => x.GetValue(DriverId, "COM Port", string.Empty, ComPortDefault))
.Returns(ComPortDefault);
profileWrapperMock
.Setup(x => x.GetValue(DriverId, "Guide Rate Arc Seconds Per Second", string.Empty,
GuideRateProfileNameDefault)).Returns(GuideRateProfileNameDefault);
profileWrapperMock.Setup(x => x.GetValue(DriverId, "Precision", string.Empty, PrecisionDefault))
.Returns(PrecisionDefault);
profileWrapperMock.Setup(x => x.GetValue(DriverId, "Guiding Style", string.Empty, GuidingStyleDefault))
.Returns(GuidingStyleDefault);
profileWrapperMock.Setup(x =>
x.GetValue(DriverId, "Backlash Compensation", string.Empty, BacklashCompensationDefault))
.Returns(BacklashCompensationDefault);
profileWrapperMock.Setup(x =>
x.GetValue(DriverId, "Reverse Focuser Direction", string.Empty, ReverseFocuserDiectionDefault))
.Returns(() => ReverseFocuserDiectionDefault);
profileWrapperMock.Setup(x =>
x.GetValue(DriverId, It.IsRegex("^SwitchName_[0-9{1}]$"), string.Empty, It.IsAny<string>()))
.Returns((string driverId, string name, string subKey, string defaultValue) => defaultValue);
IProfileWrapper profeWrapper = profileWrapperMock.Object;
Mock<IProfileFactory> profileFactoryMock = new Mock<IProfileFactory>();
profileFactoryMock.Setup(x => x.Create()).Returns(profileWrapperMock.Object);
SharedResources.ProfileFactory = profileFactoryMock.Object;
var profileProperties = SharedResources.ReadProfile();
Assert.That(profeWrapper.DeviceType, Is.EqualTo("Telescope"));
Assert.That(profileProperties.ComPort, Is.EqualTo(ComPortDefault));
Assert.That(profileProperties.TraceLogger, Is.EqualTo(bool.Parse(TraceStateDefault)));
}
[TestCase("TCP")]
[TestCase("Carrier Pigeon")]
public void Connect_WhenDeviceIdIsNotSerial_ThenThrowsException(string deviceId)
{
var result = Assert.Throws<ArgumentException>(() => { SharedResources.Connect(deviceId, string.Empty, _traceLoggerMock.Object); });
Assert.That(result.Message, Is.EqualTo($"deviceId {deviceId} not currently supported"));
}
}
}
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="ASCOM.Platform" version="6.5.2" targetFramework="net472" />
<package id="Castle.Core" version="4.4.0" targetFramework="net472" />
<package id="Moq" version="4.16.0" targetFramework="net472" />
<package id="NUnit" version="3.13.1" targetFramework="net472" />
<package id="System.Runtime.CompilerServices.Unsafe" version="4.5.3" targetFramework="net472" />
<package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net472" />
</packages>
+88
View File
@@ -0,0 +1,88 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29905.134
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LynxAstro.DewController", "LynxAstro.DewController\LynxAstro.DewController.csproj", "{C708E487-E3A9-4073-A545-294B88674225}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LynxAstro.DewController.Switch", "LynxAstro.DewController.Switch\LynxAstro.DewController.Switch.csproj", "{64308775-BD4A-469C-BCAB-3ED830B811AF}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTests", "UnitTests", "{7CAA050A-2EB3-4A21-8A75-131EB0AC9778}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LynxAstro.DewController.UnitTests", "LynxAstro.DewController.UnitTests\LynxAstro.DewController.UnitTests.csproj", "{BDED8EBB-7F9F-4710-8B74-59298C2DFCAD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LynxAstro.DewController.Switch.UnitTests", "LynxAstro.DewController.Switch.UnitTests\LynxAstro.DewController.Switch.UnitTests.csproj", "{AFA5A4A4-188C-4180-B910-7C5BA7D5C11F}"
EndProject
Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "LynxAstro.DewController.Setup", "LynxAstro.DewController.Setup\LynxAstro.DewController.Setup.wixproj", "{1073A462-D9A4-4C72-9C3F-A345B307153A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test Console", "Test Console", "{9B4388AE-0FB9-4C65-9C3F-000CE932E110}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LynxAstro.DewController.TestConsole", "LynxAstro.DewController.TestConsole\LynxAstro.DewController.TestConsole.csproj", "{D5207217-61C7-4E94-8097-91DBACE57D2A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C708E487-E3A9-4073-A545-294B88674225}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C708E487-E3A9-4073-A545-294B88674225}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C708E487-E3A9-4073-A545-294B88674225}.Debug|x86.ActiveCfg = Debug|Any CPU
{C708E487-E3A9-4073-A545-294B88674225}.Debug|x86.Build.0 = Debug|Any CPU
{C708E487-E3A9-4073-A545-294B88674225}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C708E487-E3A9-4073-A545-294B88674225}.Release|Any CPU.Build.0 = Release|Any CPU
{C708E487-E3A9-4073-A545-294B88674225}.Release|x86.ActiveCfg = Release|Any CPU
{C708E487-E3A9-4073-A545-294B88674225}.Release|x86.Build.0 = Release|Any CPU
{64308775-BD4A-469C-BCAB-3ED830B811AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{64308775-BD4A-469C-BCAB-3ED830B811AF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{64308775-BD4A-469C-BCAB-3ED830B811AF}.Debug|x86.ActiveCfg = Debug|Any CPU
{64308775-BD4A-469C-BCAB-3ED830B811AF}.Debug|x86.Build.0 = Debug|Any CPU
{64308775-BD4A-469C-BCAB-3ED830B811AF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{64308775-BD4A-469C-BCAB-3ED830B811AF}.Release|Any CPU.Build.0 = Release|Any CPU
{64308775-BD4A-469C-BCAB-3ED830B811AF}.Release|x86.ActiveCfg = Release|Any CPU
{64308775-BD4A-469C-BCAB-3ED830B811AF}.Release|x86.Build.0 = Release|Any CPU
{BDED8EBB-7F9F-4710-8B74-59298C2DFCAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BDED8EBB-7F9F-4710-8B74-59298C2DFCAD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BDED8EBB-7F9F-4710-8B74-59298C2DFCAD}.Debug|x86.ActiveCfg = Debug|Any CPU
{BDED8EBB-7F9F-4710-8B74-59298C2DFCAD}.Debug|x86.Build.0 = Debug|Any CPU
{BDED8EBB-7F9F-4710-8B74-59298C2DFCAD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BDED8EBB-7F9F-4710-8B74-59298C2DFCAD}.Release|Any CPU.Build.0 = Release|Any CPU
{BDED8EBB-7F9F-4710-8B74-59298C2DFCAD}.Release|x86.ActiveCfg = Release|Any CPU
{BDED8EBB-7F9F-4710-8B74-59298C2DFCAD}.Release|x86.Build.0 = Release|Any CPU
{AFA5A4A4-188C-4180-B910-7C5BA7D5C11F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AFA5A4A4-188C-4180-B910-7C5BA7D5C11F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AFA5A4A4-188C-4180-B910-7C5BA7D5C11F}.Debug|x86.ActiveCfg = Debug|Any CPU
{AFA5A4A4-188C-4180-B910-7C5BA7D5C11F}.Debug|x86.Build.0 = Debug|Any CPU
{AFA5A4A4-188C-4180-B910-7C5BA7D5C11F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AFA5A4A4-188C-4180-B910-7C5BA7D5C11F}.Release|Any CPU.Build.0 = Release|Any CPU
{AFA5A4A4-188C-4180-B910-7C5BA7D5C11F}.Release|x86.ActiveCfg = Release|Any CPU
{AFA5A4A4-188C-4180-B910-7C5BA7D5C11F}.Release|x86.Build.0 = Release|Any CPU
{1073A462-D9A4-4C72-9C3F-A345B307153A}.Debug|Any CPU.ActiveCfg = Debug|x86
{1073A462-D9A4-4C72-9C3F-A345B307153A}.Debug|Any CPU.Build.0 = Debug|x86
{1073A462-D9A4-4C72-9C3F-A345B307153A}.Debug|x86.ActiveCfg = Debug|x86
{1073A462-D9A4-4C72-9C3F-A345B307153A}.Debug|x86.Build.0 = Debug|x86
{1073A462-D9A4-4C72-9C3F-A345B307153A}.Release|Any CPU.ActiveCfg = Release|x86
{1073A462-D9A4-4C72-9C3F-A345B307153A}.Release|x86.ActiveCfg = Release|x86
{1073A462-D9A4-4C72-9C3F-A345B307153A}.Release|x86.Build.0 = Release|x86
{D5207217-61C7-4E94-8097-91DBACE57D2A}.Debug|Any CPU.ActiveCfg = Debug|x86
{D5207217-61C7-4E94-8097-91DBACE57D2A}.Debug|Any CPU.Build.0 = Debug|x86
{D5207217-61C7-4E94-8097-91DBACE57D2A}.Debug|x86.ActiveCfg = Debug|x86
{D5207217-61C7-4E94-8097-91DBACE57D2A}.Debug|x86.Build.0 = Debug|x86
{D5207217-61C7-4E94-8097-91DBACE57D2A}.Release|Any CPU.ActiveCfg = Release|x86
{D5207217-61C7-4E94-8097-91DBACE57D2A}.Release|x86.ActiveCfg = Release|x86
{D5207217-61C7-4E94-8097-91DBACE57D2A}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{BDED8EBB-7F9F-4710-8B74-59298C2DFCAD} = {7CAA050A-2EB3-4A21-8A75-131EB0AC9778}
{AFA5A4A4-188C-4180-B910-7C5BA7D5C11F} = {7CAA050A-2EB3-4A21-8A75-131EB0AC9778}
{D5207217-61C7-4E94-8097-91DBACE57D2A} = {9B4388AE-0FB9-4C65-9C3F-000CE932E110}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {343D05C4-AD6F-4A05-A971-ECAABF3294AF}
EndGlobalSection
EndGlobal
+91
View File
@@ -0,0 +1,91 @@
using System;
using System.Reflection;
namespace ASCOM.LynxAstro.DewController
{
public class AssemblyInfo
{
// The assembly information values.
//public readonly string Title = string.Empty;
//public readonly string Description = string.Empty;
//public readonly string Company = string.Empty;
public readonly string Product = string.Empty;
//public readonly string Copyright = string.Empty;
//public readonly string Trademark = string.Empty;
public readonly string AssemblyVersion;
//public readonly string FileVersion = string.Empty;
//public readonly string Guid = string.Empty;
//public readonly string NeutralLanguage = string.Empty;
//public readonly bool IsComVisible;
// Return a particular assembly attribute value.
private T GetAssemblyAttribute<T>(Assembly assembly)
where T : Attribute
{
// Get attributes of this type.
object[] attributes = assembly.GetCustomAttributes(typeof(T), true);
// If we didn't get anything, return null.
if (attributes.Length == 0)
return null;
// Convert the first attribute value into
// the desired type and return it.
return (T)attributes[0];
}
// Constructors.
public AssemblyInfo()
: this(Assembly.GetExecutingAssembly())
{
}
private AssemblyInfo(Assembly assembly)
{
// Get values from the assembly.
//var titleAttr = GetAssemblyAttribute<AssemblyTitleAttribute>(assembly);
//if (titleAttr != null)
// Title = titleAttr.Title;
//var assemblyAttr = GetAssemblyAttribute<AssemblyDescriptionAttribute>(assembly);
//if (assemblyAttr != null)
// Description = assemblyAttr.Description;
//var companyAttr =GetAssemblyAttribute<AssemblyCompanyAttribute>(assembly);
//if (companyAttr != null)
// Company = companyAttr.Company;
var productAttr = GetAssemblyAttribute<AssemblyProductAttribute>(assembly);
if (productAttr != null)
Product = productAttr.Product;
//var copyrightAttr = GetAssemblyAttribute<AssemblyCopyrightAttribute>(assembly);
//if (copyrightAttr != null)
// Copyright = copyrightAttr.Copyright;
//var trademarkAttr = GetAssemblyAttribute<AssemblyTrademarkAttribute>(assembly);
//if (trademarkAttr != null)
// Trademark = trademarkAttr.Trademark;
var version = assembly.GetName().Version;
AssemblyVersion = $"{version.Major}.{version.Minor}.{version.Build}.{version.Revision}";
//var fileVersionAttr = GetAssemblyAttribute<AssemblyFileVersionAttribute>(assembly);
//if (fileVersionAttr != null) FileVersion =
// fileVersionAttr.Version;
//var guidAttr = GetAssemblyAttribute<GuidAttribute>(assembly);
//if (guidAttr != null)
// Guid = guidAttr.Value;
//var languageAttr = GetAssemblyAttribute<NeutralResourcesLanguageAttribute>(assembly);
//if (languageAttr != null)
// NeutralLanguage = languageAttr.CultureName;
//var comAttr = GetAssemblyAttribute<ComVisibleAttribute>(assembly);
//if (comAttr != null)
// IsComVisible = comAttr.Value;
}
}
}
+244
View File
@@ -0,0 +1,244 @@
using System;
using System.Runtime.InteropServices;
using System.Collections;
namespace ASCOM.LynxAstro.DewController
{
#region C# Definition of IClassFactory
//
// Provide a definition of theCOM IClassFactory interface.
//
[
ComImport, // This interface originated from COM.
ComVisible(false), // Must not be exposed to COM!!!
InterfaceType(ComInterfaceType.InterfaceIsIUnknown), // Indicate that this interface is not IDispatch-based.
Guid("00000001-0000-0000-C000-000000000046") // This GUID is the actual GUID of IClassFactory.
]
public interface IClassFactory
{
void CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject);
void LockServer(bool fLock);
}
#endregion
//
// Universal ClassFactory. Given a type as a parameter of the
// constructor, it implements IClassFactory for any interface
// that the class implements. Magic!!!
//
public class ClassFactory : IClassFactory
{
#region Access to ole32.dll functions for class factories
// Define two common GUID objects for public usage.
public static Guid IID_IUnknown = new Guid("{00000000-0000-0000-C000-000000000046}");
public static Guid IID_IDispatch = new Guid("{00020400-0000-0000-C000-000000000046}");
[Flags]
enum CLSCTX : uint
{
CLSCTX_INPROC_SERVER = 0x1,
CLSCTX_INPROC_HANDLER = 0x2,
CLSCTX_LOCAL_SERVER = 0x4,
CLSCTX_INPROC_SERVER16 = 0x8,
CLSCTX_REMOTE_SERVER = 0x10,
CLSCTX_INPROC_HANDLER16 = 0x20,
CLSCTX_RESERVED1 = 0x40,
CLSCTX_RESERVED2 = 0x80,
CLSCTX_RESERVED3 = 0x100,
CLSCTX_RESERVED4 = 0x200,
CLSCTX_NO_CODE_DOWNLOAD = 0x400,
CLSCTX_RESERVED5 = 0x800,
CLSCTX_NO_CUSTOM_MARSHAL = 0x1000,
CLSCTX_ENABLE_CODE_DOWNLOAD = 0x2000,
CLSCTX_NO_FAILURE_LOG = 0x4000,
CLSCTX_DISABLE_AAA = 0x8000,
CLSCTX_ENABLE_AAA = 0x10000,
CLSCTX_FROM_DEFAULT_CONTEXT = 0x20000,
CLSCTX_INPROC = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER,
CLSCTX_SERVER = CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER,
CLSCTX_ALL = CLSCTX_SERVER | CLSCTX_INPROC_HANDLER
}
[Flags]
enum REGCLS : uint
{
REGCLS_SINGLEUSE = 0,
REGCLS_MULTIPLEUSE = 1,
REGCLS_MULTI_SEPARATE = 2,
REGCLS_SUSPENDED = 4,
REGCLS_SURROGATE = 8
}
//
// CoRegisterClassObject() is used to register a Class Factory
// into COM's internal table of Class Factories.
//
[DllImport("ole32.dll")]
static extern int CoRegisterClassObject(
[In] ref Guid rclsid,
[MarshalAs(UnmanagedType.IUnknown)] object pUnk,
uint dwClsContext,
uint flags,
out uint lpdwRegister);
//
// Called by a COM EXE Server that can register multiple class objects
// to inform COM about all registered classes, and permits activation
// requests for those class objects.
// This function causes OLE to inform the SCM about all the registered
// classes, and begins letting activation requests into the server process.
//
[DllImport("ole32.dll")]
static extern int CoResumeClassObjects();
//
// Prevents any new activation requests from the SCM on all class objects
// registered within the process. Even though a process may call this API,
// the process still must call CoRevokeClassObject for each CLSID it has
// registered, in the apartment it registered in.
//
[DllImport("ole32.dll")]
static extern int CoSuspendClassObjects();
//
// CoRevokeClassObject() is used to unregister a Class Factory
// from COM's internal table of Class Factories.
//
[DllImport("ole32.dll")]
static extern int CoRevokeClassObject(uint dwRegister);
#endregion
#region Constructor and Private ClassFactory Data
protected Type m_ClassType;
protected Guid m_ClassId;
protected ArrayList m_InterfaceTypes;
protected uint m_ClassContext;
protected uint m_Flags;
protected UInt32 m_locked = 0;
protected uint m_Cookie;
protected string m_progid;
public ClassFactory(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
m_ClassType = type;
//PWGS Get the ProgID from the MetaData
m_progid = Marshal.GenerateProgIdForType(type);
m_ClassId = Marshal.GenerateGuidForType(type); // Should be nailed down by [Guid(...)]
m_ClassContext = (uint)CLSCTX.CLSCTX_LOCAL_SERVER; // Default
m_Flags = (uint)REGCLS.REGCLS_MULTIPLEUSE | // Default
(uint)REGCLS.REGCLS_SUSPENDED;
m_InterfaceTypes = new ArrayList();
foreach (Type T in type.GetInterfaces()) // Save all of the implemented interfaces
m_InterfaceTypes.Add(T);
}
#endregion
#region Common ClassFactory Methods
public uint ClassContext
{
get { return m_ClassContext; }
set { m_ClassContext = value; }
}
public Guid ClassId
{
get { return m_ClassId; }
set { m_ClassId = value; }
}
public uint Flags
{
get { return m_Flags; }
set { m_Flags = value; }
}
public bool RegisterClassObject()
{
// Register the class factory
int i = CoRegisterClassObject
(
ref m_ClassId,
this,
m_ClassContext,
m_Flags,
out m_Cookie
);
return (i == 0);
}
public bool RevokeClassObject()
{
int i = CoRevokeClassObject(m_Cookie);
return (i == 0);
}
public static bool ResumeClassObjects()
{
int i = CoResumeClassObjects();
return (i == 0);
}
public static bool SuspendClassObjects()
{
int i = CoSuspendClassObjects();
return (i == 0);
}
#endregion
#region IClassFactory Implementations
//
// Implement creation of the type and interface.
//
void IClassFactory.CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject)
{
IntPtr nullPtr = new IntPtr(0);
ppvObject = nullPtr;
//
// Handle specific requests for implemented interfaces
//
foreach (Type iType in m_InterfaceTypes)
{
if (riid == Marshal.GenerateGuidForType(iType))
{
ppvObject = Marshal.GetComInterfaceForObject(Activator.CreateInstance(m_ClassType), iType);
return;
}
}
//
// Handle requests for IDispatch or IUnknown on the class
//
if (riid == IID_IDispatch)
{
ppvObject = Marshal.GetIDispatchForObject(Activator.CreateInstance(m_ClassType));
return;
}
else if (riid == IID_IUnknown)
{
ppvObject = Marshal.GetIUnknownForObject(Activator.CreateInstance(m_ClassType));
}
else
{
//
// Oops, some interface that the class doesn't implement
//
throw new COMException("No interface", unchecked((int)0x80004002));
}
}
void IClassFactory.LockServer(bool bLock)
{
if (bLock)
Server.CountLock();
else
Server.UncountLock();
// Always attempt to see if we need to shutdown this server application.
Server.ExitIf();
}
#endregion
}
}
@@ -0,0 +1,8 @@
namespace ASCOM.LynxAstro.DewController
{
public class ConnectionInfo
{
//public int Connections { get; set; }
public int SameDevice { get; set; }
}
}
@@ -0,0 +1,57 @@
using System;
using System.Threading;
namespace ASCOM.LynxAstro.DewController
{
/// <summary>
/// Summary description for GarbageCollection.
/// </summary>
class GarbageCollection
{
protected bool m_bContinueThread;
protected bool m_GCWatchStopped;
protected int m_iInterval;
protected ManualResetEvent m_EventThreadEnded;
public GarbageCollection(int iInterval)
{
m_bContinueThread = true;
m_GCWatchStopped = false;
m_iInterval = iInterval;
m_EventThreadEnded = new ManualResetEvent(false);
}
public void GCWatch()
{
// Pause for a moment to provide a delay to make threads more apparent.
while (ContinueThread())
{
GC.Collect();
Thread.Sleep(m_iInterval);
}
m_EventThreadEnded.Set();
}
protected bool ContinueThread()
{
lock (this)
{
return m_bContinueThread;
}
}
public void StopThread()
{
lock (this)
{
m_bContinueThread = false;
}
}
public void WaitForThreadToStop()
{
m_EventThreadEnded.WaitOne();
m_EventThreadEnded.Reset();
}
}
}
@@ -0,0 +1,7 @@
namespace ASCOM.LynxAstro.DewController
{
public interface IProfileFactory
{
IProfileWrapper Create();
}
}
@@ -0,0 +1,10 @@
using System;
using ASCOM.Utilities.Interfaces;
namespace ASCOM.LynxAstro.DewController
{
public interface IProfileWrapper : IProfile, IProfileExtra, IDisposable
{
}
}
@@ -0,0 +1,28 @@
using System;
using ASCOM.Utilities.Interfaces;
namespace ASCOM.LynxAstro.DewController
{
public interface ISharedResourcesWrapper
{
ConnectionInfo Connect(string deviceId, string driverId, ITraceLogger traceLogger);
void Disconnect(string deviceId, string driverId);
string FirmwareVersion { get; }
void Lock(Action action);
T Lock<T>(Func<T> func);
string SendString(string message);
void SendBlind(string message);
string SendChar(string message);
string ReadTerminated();
ProfileProperties ReadProfile();
void SetupDialog();
void WriteProfile(ProfileProperties profileProperties);
void ReadCharacters(int throwAwayCharacters);
}
}
+640
View File
@@ -0,0 +1,640 @@
//
// ASCOM.LynxAstro.DewController Local COM Server
//
// This is the core of a managed COM Local Server, capable of serving
// multiple instances of multiple interfaces, within a single
// executable. This implementes the equivalent functionality of VB6
// which has been extensively used in ASCOM for drivers that provide
// multiple interfaces to multiple clients (e.g. Meade Telescope
// and Focuser) as well as hubs (e.g., POTH).
//
// Written by: Robert B. Denny (Version 1.0.1, 29-May-2007)
// Modified by Chris Rowland and Peter Simpson to allow use with multiple devices of the same type March 2011
//
//
using System;
using System.IO;
using System.Windows.Forms;
using System.Collections;
using System.Runtime.InteropServices;
using System.Reflection;
using ASCOM.Utilities;
using Microsoft.Win32;
using System.Threading;
using System.Security.Principal;
using System.Diagnostics;
namespace ASCOM.LynxAstro.DewController
{
public static class Server
{
#region Access to kernel32.dll, user32.dll, and ole32.dll functions
[Flags]
enum CLSCTX : uint
{
CLSCTX_INPROC_SERVER = 0x1,
CLSCTX_INPROC_HANDLER = 0x2,
CLSCTX_LOCAL_SERVER = 0x4,
CLSCTX_INPROC_SERVER16 = 0x8,
CLSCTX_REMOTE_SERVER = 0x10,
CLSCTX_INPROC_HANDLER16 = 0x20,
CLSCTX_RESERVED1 = 0x40,
CLSCTX_RESERVED2 = 0x80,
CLSCTX_RESERVED3 = 0x100,
CLSCTX_RESERVED4 = 0x200,
CLSCTX_NO_CODE_DOWNLOAD = 0x400,
CLSCTX_RESERVED5 = 0x800,
CLSCTX_NO_CUSTOM_MARSHAL = 0x1000,
CLSCTX_ENABLE_CODE_DOWNLOAD = 0x2000,
CLSCTX_NO_FAILURE_LOG = 0x4000,
CLSCTX_DISABLE_AAA = 0x8000,
CLSCTX_ENABLE_AAA = 0x10000,
CLSCTX_FROM_DEFAULT_CONTEXT = 0x20000,
CLSCTX_INPROC = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER,
CLSCTX_SERVER = CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER,
CLSCTX_ALL = CLSCTX_SERVER | CLSCTX_INPROC_HANDLER
}
[Flags]
enum COINIT : uint
{
/// Initializes the thread for multi-threaded object concurrency.
COINIT_MULTITHREADED = 0x0,
/// Initializes the thread for apartment-threaded object concurrency.
COINIT_APARTMENTTHREADED = 0x2,
/// Disables DDE for Ole1 support.
COINIT_DISABLE_OLE1DDE = 0x4,
/// Trades memory for speed.
COINIT_SPEED_OVER_MEMORY = 0x8
}
[Flags]
enum REGCLS : uint
{
REGCLS_SINGLEUSE = 0,
REGCLS_MULTIPLEUSE = 1,
REGCLS_MULTI_SEPARATE = 2,
REGCLS_SUSPENDED = 4,
REGCLS_SURROGATE = 8
}
// CoInitializeEx() can be used to set the apartment model
// of individual threads.
[DllImport("ole32.dll")]
static extern int CoInitializeEx(IntPtr pvReserved, uint dwCoInit);
// CoUninitialize() is used to uninitialize a COM thread.
[DllImport("ole32.dll")]
static extern void CoUninitialize();
// PostThreadMessage() allows us to post a Windows Message to
// a specific thread (identified by its thread id).
// We will need this API to post a WM_QUIT message to the main
// thread in order to terminate this application.
[DllImport("user32.dll")]
static extern bool PostThreadMessage(uint idThread, uint Msg, UIntPtr wParam,
IntPtr lParam);
// GetCurrentThreadId() allows us to obtain the thread id of the
// calling thread. This allows us to post the WM_QUIT message to
// the main thread.
[DllImport("kernel32.dll")]
static extern uint GetCurrentThreadId();
#endregion
#region Private Data
private static int objsInUse; // Keeps a count on the total number of objects alive.
private static int serverLocks; // Keeps a lock count on this application.
private static frmMain s_MainForm = null; // Reference to our main form
private static ArrayList s_ComObjectAssys; // Dynamically loaded assemblies containing served COM objects
private static ArrayList s_ComObjectTypes; // Served COM object types
private static ArrayList s_ClassFactories; // Served COM object class factories
private static string s_appId = "{34e5f3f3-29e4-4d87-b861-c079485a5c97}"; // Our AppId
private static readonly Object lockObject = new object();
#endregion
// This property returns the main thread's id.
public static uint MainThreadId { get; private set; } // Stores the main thread's thread id.
// Used to tell if started by COM or manually
public static bool StartedByCOM { get; private set; } // True if server started by COM (-embedding)
#region Server Lock, Object Counting, and AutoQuit on COM startup
// Returns the total number of objects alive currently.
public static int ObjectsCount
{
get
{
lock (lockObject)
{
return objsInUse;
}
}
}
// This method performs a thread-safe incrementation of the objects count.
public static int CountObject()
{
// Increment the global count of objects.
return Interlocked.Increment(ref objsInUse);
}
// This method performs a thread-safe decrementation the objects count.
public static int UncountObject()
{
// Decrement the global count of objects.
return Interlocked.Decrement(ref objsInUse);
}
// Returns the current server lock count.
public static int ServerLockCount
{
get
{
lock (lockObject)
{
return serverLocks;
}
}
}
// This method performs a thread-safe incrementation the
// server lock count.
public static int CountLock()
{
// Increment the global lock count of this server.
return Interlocked.Increment(ref serverLocks);
}
// This method performs a thread-safe decrementation the
// server lock count.
public static int UncountLock()
{
// Decrement the global lock count of this server.
return Interlocked.Decrement(ref serverLocks);
}
// AttemptToTerminateServer() will check to see if the objects count and the server
// lock count have both dropped to zero.
//
// If so, and if we were started by COM, we post a WM_QUIT message to the main thread's
// message loop. This will cause the message loop to exit and hence the termination
// of this application. If hand-started, then just trace that it WOULD exit now.
//
public static void ExitIf()
{
lock (lockObject)
{
if ((ObjectsCount <= 0) && (ServerLockCount <= 0))
{
if (StartedByCOM)
{
UIntPtr wParam = new UIntPtr(0);
IntPtr lParam = new IntPtr(0);
PostThreadMessage(MainThreadId, 0x0012, wParam, lParam);
}
}
}
}
#endregion
// -----------------
// PRIVATE FUNCTIONS
// -----------------
#region Dynamic Driver Assembly Loader
//
// Load the assemblies that contain the classes that we will serve
// via COM. These will be located in the same folder as
// our executable.
//
private static bool LoadComObjectAssemblies()
{
s_ComObjectAssys = new ArrayList();
s_ComObjectTypes = new ArrayList();
// put everything into one folder, the same as the server.
string assyPath = Assembly.GetEntryAssembly().Location;
assyPath = Path.GetDirectoryName(assyPath);
DirectoryInfo d = new DirectoryInfo(assyPath);
foreach (FileInfo fi in d.GetFiles("*.dll"))
{
string aPath = fi.FullName;
//
// First try to load the assembly and get the types for
// the class and the class factory. If this doesn't work ????
//
try
{
Assembly so = Assembly.LoadFrom(aPath);
//PWGS Get the types in the assembly
Type[] types = so.GetTypes();
foreach (Type type in types)
{
// PWGS Now checks the type rather than the assembly
// Check to see if the type has the ServedClassName attribute, only use it if it does.
MemberInfo info = type;
object[] attrbutes = info.GetCustomAttributes(typeof(ServedClassNameAttribute), false);
if (attrbutes.Length > 0)
{
//MessageBox.Show("Adding Type: " + type.Name + " " + type.FullName);
s_ComObjectTypes.Add(type); //PWGS - much simpler
s_ComObjectAssys.Add(so);
}
}
}
catch (BadImageFormatException)
{
// Probably an attempt to load a Win32 DLL (i.e. not a .net assembly)
// Just swallow the exception and continue to the next item.
continue;
}
catch (Exception e)
{
MessageBox.Show("Failed to load served COM class assembly " + fi.Name + " - " + e.Message,
"LynxAstro.DewController", MessageBoxButtons.OK, MessageBoxIcon.Stop);
return false;
}
}
return true;
}
#endregion
#region COM Registration and Unregistration
//
// Test if running elevated
//
private static bool IsAdministrator
{
get
{
WindowsIdentity i = WindowsIdentity.GetCurrent();
WindowsPrincipal p = new WindowsPrincipal(i);
return p.IsInRole(WindowsBuiltInRole.Administrator);
}
}
//
// Elevate by re-running ourselves with elevation dialog
//
private static void ElevateSelf(string arg)
{
ProcessStartInfo si = new ProcessStartInfo();
si.Arguments = arg;
si.WorkingDirectory = Environment.CurrentDirectory;
si.FileName = Application.ExecutablePath;
si.Verb = "runas";
try { Process.Start(si); }
catch (System.ComponentModel.Win32Exception)
{
MessageBox.Show("The LynxAstro.DewController was not " + (arg == "/register" ? "registered" : "unregistered") +
" because you did not allow it.", "LynxAstro.DewController", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString(), "LynxAstro.DewController", MessageBoxButtons.OK, MessageBoxIcon.Stop);
}
return;
}
//
// Do everything to register this for COM. Never use REGASM on
// this exe assembly! It would create InProcServer32 entries
// which would prevent proper activation!
//
// Using the list of COM object types generated during dynamic
// assembly loading, it registers each one for COM as served by our
// exe/local server, as well as registering it for ASCOM. It also
// adds DCOM info for the local server itself, so it can be activated
// via an outboiud connection from TheSky.
//
private static void RegisterObjects()
{
if (!IsAdministrator)
{
ElevateSelf("/register");
return;
}
//
// If reached here, we're running elevated
//
Assembly assy = Assembly.GetExecutingAssembly();
Attribute attr = Attribute.GetCustomAttribute(assy, typeof(AssemblyTitleAttribute));
string assyTitle = ((AssemblyTitleAttribute)attr).Title;
attr = Attribute.GetCustomAttribute(assy, typeof(AssemblyDescriptionAttribute));
string assyDescription = ((AssemblyDescriptionAttribute)attr).Description;
//
// Local server's DCOM/AppID information
//
try
{
//
// HKCR\APPID\appid
//
using (RegistryKey key = Registry.ClassesRoot.CreateSubKey("APPID\\" + s_appId))
{
key.SetValue(null, assyDescription);
key.SetValue("AppID", s_appId);
key.SetValue("AuthenticationLevel", 1, RegistryValueKind.DWord);
key.SetValue("RunAs", "Interactive User", RegistryValueKind.String); // Added to ensure that only one copy of the local server runs if the user uses both elevated and non-elevated clients concurrently
}
//
// HKCR\APPID\exename.ext
//
using (RegistryKey key = Registry.ClassesRoot.CreateSubKey(string.Format("APPID\\{0}",
Application.ExecutablePath.Substring(Application.ExecutablePath.LastIndexOf('\\') + 1))))
{
key.SetValue("AppID", s_appId);
}
}
catch (Exception ex)
{
MessageBox.Show("Error while registering the server:\n" + ex.ToString(),
"LynxAstro.DewController", MessageBoxButtons.OK, MessageBoxIcon.Stop);
return;
}
finally
{
}
//
// For each of the driver assemblies
//
foreach (Type type in s_ComObjectTypes)
{
bool bFail = false;
try
{
//
// HKCR\CLSID\clsid
//
string clsid = Marshal.GenerateGuidForType(type).ToString("B");
string progid = Marshal.GenerateProgIdForType(type);
//PWGS Generate device type from the Class name
string deviceType = type.Name;
using (RegistryKey key = Registry.ClassesRoot.CreateSubKey(string.Format("CLSID\\{0}", clsid)))
{
key.SetValue(null, progid); // Could be assyTitle/Desc??, but .NET components show ProgId here
key.SetValue("AppId", s_appId);
using (RegistryKey key2 = key.CreateSubKey("Implemented Categories"))
{
key2.CreateSubKey("{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}");
}
using (RegistryKey key2 = key.CreateSubKey("ProgId"))
{
key2.SetValue(null, progid);
}
key.CreateSubKey("Programmable");
using (RegistryKey key2 = key.CreateSubKey("LocalServer32"))
{
key2.SetValue(null, Application.ExecutablePath);
}
}
//
// HKCR\CLSID\progid
//
using (RegistryKey key = Registry.ClassesRoot.CreateSubKey(progid))
{
key.SetValue(null, assyTitle);
using (RegistryKey key2 = key.CreateSubKey("CLSID"))
{
key2.SetValue(null, clsid);
}
}
//
// ASCOM
//
assy = type.Assembly;
// Pull the display name from the ServedClassName attribute.
attr = Attribute.GetCustomAttribute(type, typeof(ServedClassNameAttribute)); //PWGS Changed to search type for attribute rather than assembly
string chooserName = ((ServedClassNameAttribute)attr).DisplayName ?? "MultiServer";
using (var P = new Profile())
{
P.DeviceType = deviceType;
P.Register(progid, chooserName);
}
}
catch (Exception ex)
{
MessageBox.Show("Error while registering the server:\n" + ex.ToString(),
"LynxAstro.DewController", MessageBoxButtons.OK, MessageBoxIcon.Stop);
bFail = true;
}
finally
{
}
if (bFail) break;
}
}
//
// Remove all traces of this from the registry.
//
// **TODO** If the above does AppID/DCOM stuff, this would have
// to remove that stuff too.
//
private static void UnregisterObjects()
{
if (!IsAdministrator)
{
ElevateSelf("/unregister");
return;
}
//
// Local server's DCOM/AppID information
//
Registry.ClassesRoot.DeleteSubKey(string.Format("APPID\\{0}", s_appId), false);
Registry.ClassesRoot.DeleteSubKey(string.Format("APPID\\{0}",
Application.ExecutablePath.Substring(Application.ExecutablePath.LastIndexOf('\\') + 1)), false);
//
// For each of the driver assemblies
//
foreach (Type type in s_ComObjectTypes)
{
string clsid = Marshal.GenerateGuidForType(type).ToString("B");
string progid = Marshal.GenerateProgIdForType(type);
string deviceType = type.Name;
//
// Best efforts
//
//
// HKCR\progid
//
Registry.ClassesRoot.DeleteSubKey(String.Format("{0}\\CLSID", progid), false);
Registry.ClassesRoot.DeleteSubKey(progid, false);
//
// HKCR\CLSID\clsid
//
Registry.ClassesRoot.DeleteSubKey(String.Format("CLSID\\{0}\\Implemented Categories\\{{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}}", clsid), false);
Registry.ClassesRoot.DeleteSubKey(String.Format("CLSID\\{0}\\Implemented Categories", clsid), false);
Registry.ClassesRoot.DeleteSubKey(String.Format("CLSID\\{0}\\ProgId", clsid), false);
Registry.ClassesRoot.DeleteSubKey(String.Format("CLSID\\{0}\\LocalServer32", clsid), false);
Registry.ClassesRoot.DeleteSubKey(String.Format("CLSID\\{0}\\Programmable", clsid), false);
Registry.ClassesRoot.DeleteSubKey(String.Format("CLSID\\{0}", clsid), false);
try
{
//
// ASCOM
//
using (var P = new Profile())
{
P.DeviceType = deviceType;
P.Unregister(progid);
}
}
catch (Exception) { }
}
}
#endregion
#region Class Factory Support
//
// On startup, we register the class factories of the COM objects
// that we serve. This requires the class facgtory name to be
// equal to the served class name + "ClassFactory".
//
private static bool RegisterClassFactories()
{
s_ClassFactories = new ArrayList();
foreach (Type type in s_ComObjectTypes)
{
ClassFactory factory = new ClassFactory(type); // Use default context & flags
s_ClassFactories.Add(factory);
if (!factory.RegisterClassObject())
{
MessageBox.Show("Failed to register class factory for " + type.Name,
"LynxAstro.DewController", MessageBoxButtons.OK, MessageBoxIcon.Stop);
return false;
}
}
ClassFactory.ResumeClassObjects(); // Served objects now go live
return true;
}
private static void RevokeClassFactories()
{
ClassFactory.SuspendClassObjects(); // Prevent race conditions
foreach (ClassFactory factory in s_ClassFactories)
factory.RevokeClassObject();
}
#endregion
#region Command Line Arguments
//
// ProcessArguments() will process the command-line arguments
// If the return value is true, we carry on and start this application.
// If the return value is false, we terminate this application immediately.
//
private static bool ProcessArguments(string[] args)
{
bool bRet = true;
//
//**TODO** -Embedding is "ActiveX start". Prohibit non_AX starting?
//
if (args.Length > 0)
{
switch (args[0].ToLower())
{
case "-embedding":
StartedByCOM = true; // Indicate COM started us
break;
case "-register":
case @"/register":
case "-regserver": // Emulate VB6
case @"/regserver":
RegisterObjects(); // Register each served object
bRet = false;
break;
case "-unregister":
case @"/unregister":
case "-unregserver": // Emulate VB6
case @"/unregserver":
UnregisterObjects(); //Unregister each served object
bRet = false;
break;
default:
MessageBox.Show("Unknown argument: " + args[0] + "\nValid are : -register, -unregister and -embedding",
"LynxAstro.DewController", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
break;
}
}
else
StartedByCOM = false;
return bRet;
}
#endregion
#region SERVER ENTRY POINT (main)
//
// ==================
// SERVER ENTRY POINT
// ==================
//
[STAThread]
static void Main(string[] args)
{
if (!LoadComObjectAssemblies()) return; // Load served COM class assemblies, get types
if (!ProcessArguments(args)) return; // Register/Unregister
// Initialize critical member variables.
objsInUse = 0;
serverLocks = 0;
MainThreadId = GetCurrentThreadId();
Thread.CurrentThread.Name = "Main Thread";
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
s_MainForm = new frmMain();
if (StartedByCOM) s_MainForm.WindowState = FormWindowState.Minimized;
// Register the class factories of the served objects
RegisterClassFactories();
// Start up the garbage collection thread.
GarbageCollection GarbageCollector = new GarbageCollection(1000);
Thread GCThread = new Thread(new ThreadStart(GarbageCollector.GCWatch));
GCThread.Name = "Garbage Collection Thread";
GCThread.Start();
//
// Start the message loop. This serializes incoming calls to our
// served COM objects, making this act like the VB6 equivalent!
//
try
{
Application.Run(s_MainForm);
}
finally
{
// Revoke the class factories immediately.
// Don't wait until the thread has stopped before
// we perform revocation!!!
RevokeClassFactories();
// Now stop the Garbage Collector thread.
GarbageCollector.StopThread();
GarbageCollector.WaitForThreadToStop();
}
}
#endregion
}
}
Binary file not shown.
@@ -0,0 +1,191 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.50727</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{C708E487-E3A9-4073-A545-294B88674225}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>ASCOM.LynxAstro.DewController</RootNamespace>
<AssemblyName>ASCOM.LynxAstro.DewController.Server</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileUpgradeFlags>
</FileUpgradeFlags>
<OldToolsVersion>2.0</OldToolsVersion>
<UpgradeBackupLocation />
<TargetFrameworkProfile />
<IsWebBootstrapper>false</IsWebBootstrapper>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>AnyCPU</PlatformTarget>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x86</PlatformTarget>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>LocalServer.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="ASCOM.Astrometry, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>..\packages\ASCOM.Platform.6.5.2\lib\net40\ASCOM.Astrometry.dll</HintPath>
</Reference>
<Reference Include="ASCOM.Attributes, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>..\packages\ASCOM.Platform.6.5.2\lib\net40\ASCOM.Attributes.dll</HintPath>
</Reference>
<Reference Include="ASCOM.Cache, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>..\packages\ASCOM.Platform.6.5.2\lib\net40\ASCOM.Cache.dll</HintPath>
</Reference>
<Reference Include="ASCOM.Controls, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>..\packages\ASCOM.Platform.6.5.2\lib\net40\ASCOM.Controls.dll</HintPath>
</Reference>
<Reference Include="ASCOM.DeviceInterfaces, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>..\packages\ASCOM.Platform.6.5.2\lib\net40\ASCOM.DeviceInterfaces.dll</HintPath>
</Reference>
<Reference Include="ASCOM.DriverAccess, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>..\packages\ASCOM.Platform.6.5.2\lib\net40\ASCOM.DriverAccess.dll</HintPath>
</Reference>
<Reference Include="ASCOM.Exceptions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>..\packages\ASCOM.Platform.6.5.2\lib\net40\ASCOM.Exceptions.dll</HintPath>
</Reference>
<Reference Include="ASCOM.Internal.Extensions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>..\packages\ASCOM.Platform.6.5.2\lib\net40\ASCOM.Internal.Extensions.dll</HintPath>
</Reference>
<Reference Include="ASCOM.SettingsProvider, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>..\packages\ASCOM.Platform.6.5.2\lib\net40\ASCOM.SettingsProvider.dll</HintPath>
</Reference>
<Reference Include="ASCOM.Utilities, Version=6.0.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>..\packages\ASCOM.Platform.6.5.2\lib\net40\ASCOM.Utilities.dll</HintPath>
</Reference>
<Reference Include="ASCOM.Utilities.Video, Version=6.1.0.0, Culture=neutral, PublicKeyToken=565de7938946fba7, processorArchitecture=MSIL">
<HintPath>..\packages\ASCOM.Platform.6.5.2\lib\net40\ASCOM.Utilities.Video.dll</HintPath>
</Reference>
<Reference Include="JetBrains.Annotations, Version=2020.3.0.0, Culture=neutral, PublicKeyToken=1010a0d8d6380325, processorArchitecture=MSIL">
<HintPath>..\packages\JetBrains.Annotations.2020.3.0\lib\net20\JetBrains.Annotations.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
</ItemGroup>
<ItemGroup>
<Compile Include="AssemblyInfo.cs" />
<Compile Include="ClassFactory.cs" />
<Compile Include="ConnectionInfo.cs" />
<Compile Include="frmMain.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="frmMain.Designer.cs">
<DependentUpon>frmMain.cs</DependentUpon>
</Compile>
<Compile Include="GarbageCollection.cs" />
<Compile Include="IProfileFactory.cs" />
<Compile Include="IProfileWrapper.cs" />
<Compile Include="ISharedResourcesWrapper.cs" />
<Compile Include="LocalServer.cs" />
<Compile Include="ProfileFactory.cs" />
<Compile Include="ProfileProperties.cs" />
<Compile Include="ProfileWrapper.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SharedResourcesWrapper.cs" />
<EmbeddedResource Include="frmMain.resx">
<SubType>Designer</SubType>
<DependentUpon>frmMain.cs</DependentUpon>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="ReferenceCountedObject.cs" />
<Compile Include="SetupDialogForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="SetupDialogForm.designer.cs">
<DependentUpon>SetupDialogForm.cs</DependentUpon>
</Compile>
<Compile Include="SharedResources.cs" />
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="SetupDialogForm.resx">
<DependentUpon>SetupDialogForm.cs</DependentUpon>
<SubType>Designer</SubType>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Content Include="Resources\ASCOM.png" />
<Content Include="ReadMe.htm" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="LocalServer.snk" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
<Visible>False</Visible>
<ProductName>Windows Installer 3.1</ProductName>
<Install>true</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
<PropertyGroup>
<PreBuildEvent>
</PreBuildEvent>
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
</Project>
+10
View File
@@ -0,0 +1,10 @@
namespace ASCOM.LynxAstro.DewController
{
public class ProfileFactory : IProfileFactory
{
public IProfileWrapper Create()
{
return new ProfileWrapper();
}
}
}
@@ -0,0 +1,12 @@
using System.Collections.Generic;
namespace ASCOM.LynxAstro.DewController
{
public class ProfileProperties
{
// properies that are part of the profile
public string ComPort { get; set; }
public bool TraceLogger { get; set; }
public List<string> SwitchNames { get; set; } = new List<string>();
}
}
+132
View File
@@ -0,0 +1,132 @@
using System.Collections;
using ASCOM.Utilities;
namespace ASCOM.LynxAstro.DewController
{
public class ProfileWrapper : IProfileWrapper
{
private readonly Profile _profile = new Profile();
public ArrayList RegisteredDevices(string deviceType)
{
return _profile.RegisteredDevices(deviceType);
}
public bool IsRegistered(string driverId)
{
return _profile.IsRegistered(driverId);
}
public void Register(string driverId, string descriptiveName)
{
_profile.Register(driverId, descriptiveName);
}
public void Unregister(string driverId)
{
_profile.Unregister(driverId);
}
public string GetValue(string driverId, string name, string subKey, string defaultValue)
{
return _profile.GetValue(driverId, name, subKey, defaultValue);
}
public void WriteValue(string driverId, string name, string value, string subKey)
{
_profile.WriteValue(driverId, name, value);
}
public ArrayList Values(string driverId, string subKey)
{
return _profile.Values(driverId, subKey);
}
public void DeleteValue(string driverId, string name, string subKey)
{
_profile.DeleteValue(driverId, name, subKey);
}
public void CreateSubKey(string driverId, string subKey)
{
_profile.CreateSubKey(driverId, subKey);
}
public ArrayList SubKeys(string driverId, string subKey)
{
return _profile.SubKeys(driverId, subKey);
}
public void DeleteSubKey(string driverId, string subKey)
{
_profile.DeleteSubKey(driverId, subKey);
}
public string GetProfileXML(string deviceId)
{
return _profile.GetProfileXML(deviceId);
}
public void SetProfileXML(string deviceId, string xml)
{
_profile.SetProfileXML(deviceId, xml);
}
public string DeviceType
{
get => _profile.DeviceType;
set => _profile.DeviceType = value;
}
public ArrayList RegisteredDeviceTypes => _profile.RegisteredDeviceTypes;
public void MigrateProfile(string currentPlatformVersion)
{
_profile.MigrateProfile(currentPlatformVersion);
}
public void DeleteValue(string driverId, string name)
{
_profile.DeleteValue(driverId, name);
}
public string GetValue(string driverId, string name)
{
return _profile.GetValue(driverId, name);
}
public string GetValue(string driverId, string name, string subKey)
{
return _profile.GetValue(driverId, name, subKey);
}
public ArrayList SubKeys(string driverId)
{
return _profile.SubKeys(driverId);
}
public ArrayList Values(string driverId)
{
return _profile.Values(driverId);
}
public void WriteValue(string driverId, string name, string value)
{
_profile.WriteValue(driverId, name, value);
}
public ASCOMProfile GetProfile(string driverId)
{
return _profile.GetProfile(driverId);
}
public void SetProfile(string driverId, ASCOMProfile xmlProfileKey)
{
_profile.SetProfile(driverId, xmlProfileKey);
}
public void Dispose()
{
_profile.Dispose();
}
}
}
@@ -0,0 +1,26 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("ASCOM LynxAstro.DewController server")]
[assembly: AssemblyDescription("ASCOM multi-interface server for LynxAstro.DewController")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("ASCOM Initiative")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("Copyright © 2021, colin")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
[assembly: AssemblyVersion("6.4.0.0")]
[assembly: AssemblyFileVersion("6.4.0.0")]
[assembly: ComVisibleAttribute(false)]
+82
View File
@@ -0,0 +1,82 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace ASCOM.LynxAstro.DewController.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ASCOM.LynxAstro.DewController.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap ASCOM {
get {
object obj = ResourceManager.GetObject("ASCOM", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized string similar to {0} Settings ({1}).
/// </summary>
internal static string SetupDialogForm_SetupDialogForm__0__Settings___1__ {
get {
return ResourceManager.GetString("SetupDialogForm_SetupDialogForm__0__Settings___1__", resourceCulture);
}
}
}
}
@@ -0,0 +1,127 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="ASCOM" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\ASCOM.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="SetupDialogForm_SetupDialogForm__0__Settings___1__" xml:space="preserve">
<value>{0} Settings ({1})</value>
</data>
</root>
+666
View File
@@ -0,0 +1,666 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=windows-1252"/>
<TITLE>Untitled Document</TITLE>
<META NAME="GENERATOR" CONTENT="OpenOffice.org 3.2 (Win32)"/>
<META NAME="CREATED" CONTENT="0;0"/>
<META NAME="CHANGEDBY" CONTENT="Chris Rowland"/>
<META NAME="CHANGED" CONTENT="20110422;10442800"/>
<META NAME="CHANGEDBY" CONTENT="Chris Rowland"/>
<STYLE TYPE="text/css">
<!--
@page { margin: 2cm }
P { font-family: "Verdana", "Arial", "Helvetica", sans-serif; font-weight: normal }
TD P { font-family: "Verdana", "Arial", "Helvetica", sans-serif; font-weight: normal }
H3 { font-family: "Arial", "Helvetica", sans-serif }
H2 { font-family: "Arial", "Helvetica", sans-serif }
H4 { font-family: "Arial", "Helvetica", sans-serif }
PRE { margin-left: 0.18cm; margin-right: 0.18cm; margin-top: 0.18cm; margin-bottom: 0.18cm; background: #ccffff }
PRE.western { font-weight: normal }
PRE.cjk { font-family: "NSimSun", monospace; font-weight: normal }
PRE.ctl { font-weight: normal }
EM.underline { text-decoration: underline }
-->
</STYLE>
</HEAD>
<BODY LANG="en-GB" DIR="LTR">
<TABLE WIDTH="100%" BORDER="0" CELLPADDING="4" CELLSPACING="0" STYLE="page-break-before: always">
<TR>
<TD>
<H2>
ASCOM LocalServer (singleton) Host
</H2>
</TD>
</TR>
</TABLE>
<P>
<BR/>
<BR/>
</P>
<H4>
You have just created a local server (singleton) host for one or
more ASCOM driver classes.
</H4>
<HR/>
<P>
This project implements an ASCOM host server for one or more
driver classes in a single-instance executable. It can be used to
serve multiple instances of a single driver class (hub), provide
driver services for multiple devices (e.g., Telescope and Focuser) to
multiple applications and allow multiple devices of the same type to
be connected. In the latter scenario, the multiple driver classes
will often share one or more resources such as the serial connection
and a microcontroller in the combined device. From the client's
perspective, using the drivers served by the local server is exactly
the same as if the drivers are loaded into the client's process space
(in-proc servers).
</P>
<P STYLE="margin-left: 0.42cm; margin-right: 0.42cm; border: 1px solid #000000; padding: 0.21cm">
<STRONG>
<SPAN STYLE="background: #ffee88">NOTE:</SPAN>
</STRONG>
<SPAN STYLE="background: #ffee88">
Unless you are prepared to handle all of the timing issues that arise
when multiple clients are accessing the properties and methods of
your driver(s), stop now. Just because the local server serializes
the calls to your driver(s)' properties and methods does not mean
that there will be no timing or concurrency issues.<BR/>
&nbsp;<BR/>For
example, suppose the hub serves instances of a Telescope driver. One
client sets the TargetRightAscension property, then another sets
TargetRightAscension to a different value, then the first client sets
TargetDeclination, then the first client calls SlewToTarget()
followed by the second client calling SlewToTarget(). Besides the
first client's slew command sending the scope to the wrong (and
possibly dangerous) coordinates, there is the problem of the second
client trying to slew a slewing scope. Local server drivers are
tricky to get right. There is no such thing as &quot;ignorance is
bliss&quot; here.
</SPAN>
</P>
<P STYLE="margin-left: 0.42cm; margin-right: 0.42cm; border: 1px solid #000000; padding: 0.21cm">
<SPAN STYLE="background: #ffee88">
This implementation has changed
from what was defined for Platform 5.5 as follows:
</SPAN>
</P>
<P STYLE="margin-left: 0.42cm; margin-right: 0.42cm; border: 1px solid #000000; padding: 0.21cm">
<SPAN STYLE="background: #ffee88">
The drivers are now installed in
the same folder as the local server executable. This makes deployment
cleaner because the whole driver can exist in a single folder
independently of other drivers.
</SPAN>
</P>
<P STYLE="margin-left: 0.42cm; margin-right: 0.42cm; border: 1px solid #000000; padding: 0.21cm">
<SPAN STYLE="background: #ffee88">
The ProgId and friendly name as
displayed by the Chooser are defined using attributes. This allows
driver dlls to be identified clearly and so avoids confusion with
other dlls that may be required such as interop dlls.
</SPAN>
</P>
<P STYLE="margin-left: 0.42cm; margin-right: 0.42cm; border: 1px solid #000000; padding: 0.21cm">
<SPAN STYLE="background: #ffee88">
Some changes have been made that
will facilitate generating multiple drivers of the same type.
</SPAN>
</P>
<P STYLE="margin-left: 0.42cm; margin-right: 0.42cm; border: 1px solid #000000; padding: 0.21cm">
<SPAN STYLE="background: #ffee88">
I've put some additional advice and
comments in the notes below <I>in italics.</I>
</SPAN>
</P>
<P>
You're probably anxious to get going, but you really should read
through the <A HREF="#theory">Theory of Operation</A> and <A HREF="#details">
Detailed
Use and Deployment
</A> below.
</P>
<P>You must do the following in order to complete your local server:</P>
<OL>
<LI>
<P STYLE="margin-bottom: 0cm">
In the local server's project
properties, Application tab, change BOTH the AssemblyName and the
default assembly name to ASCOM.xxx (e.g., ASCOM.SuperScope). <I>
This
may be done by default now.
</I>
</P>
</LI>
<LI>
<P STYLE="margin-bottom: 0cm">
Add one or more driver skeleton
projects using the in-proc templates. You may use either the C# or
VB templates. Project name is not important (not used in ProgID)
choose something like TelescopeDriver. You will be changing the
substituted project name in these projects below. If you ensure that
the LocalServer and all the driver projects have the same NameSpace
e.g. ASCOM.SuperScope the renaming in section 6a will not be
required.
</P>
</LI>
<LI>
<P STYLE="margin-bottom: 0cm">
Develop and debug these driver
projects as normal in-process assemblies. This will be much simpler
because the driver and test code can be debugged in the same
process.
</P>
</LI>
<LI>
<P STYLE="margin-bottom: 0cm">
Build the LocalServer.
</P>
</LI>
<LI>
<P STYLE="margin-bottom: 0cm">
Set a reference to the local
server <STRONG>project</STRONG> in each of the driver skeleton
projects.
</P>
</LI>
<LI>
<P STYLE="margin-bottom: 0cm">In each skeleton driver project:</P>
<OL TYPE="a">
<LI>
<P STYLE="margin-bottom: 0cm">
Do a Find In Files for the
project name of the skeleton driver (e.g., TelescopeDriver) and
change it to match the project name of your local server (e.g.
SuperScope). You don't have to do this in the ReadMe.html file.
Everywhere else, however, is IMPORTANT. This sets the correct
namespace, progID, etc. If you're a bit more brave, you can use
Replace in Files. <I>
This may not be needed if the correct
namespace and naming conventions have been followed when the
drivers and local server were generated.
</I>
</P>
</LI>
<LI>
<P STYLE="margin-bottom: 0cm">
In project properties,
Application tab, change the assembly name to
ASCOM.<EM CLASS="underline">localserverprojectname</EM>.<EM>drivertype</EM>,
(e.g., ASCOM.SuperScope.Telescope).
</P>
</LI>
<LI>
<P STYLE="margin-bottom: 0cm">
In project properties,
Application tab, click Assembly Information...
</P>
<UL>
<LI>
<P STYLE="margin-bottom: 0cm">
Assure that Make assembly COM
visible is <STRONG>on</STRONG> (it should already be on).
</P>
</LI>
<LI>
<P STYLE="margin-bottom: 0cm">
Edit the Product Name to be the
&quot;friendly name&quot; of your driver as will be shown in the
Chooser. <I>
Not used now, use the ServedClassName attribute
instead.
</I>
</P>
</LI>
</UL>
</LI>
<LI>
<P STYLE="margin-bottom: 0cm">
In project properties, Build tab,
turn <STRONG>off</STRONG> Register for COM Interop.
</P>
</LI>
<LI>
<P>
Modify the driver class declaration to inherit from
ReferenceCountedObjectBase. Examples:<BR/>C#:
</P>
<PRE CLASS="western">
public class Telescope :
ReferenceCountedObjectBase,
ITelescope
</PRE>
<P>
VB:
</P>
<PRE CLASS="western">
Public Class Telescope
'==================================
Inherits ReferenceCountedObjectBase
Implements ITelescope
'==================================
</PRE>
</LI>
<LI>
<P STYLE="margin-bottom: 0cm">
In driver.cs/driver.vb, remove
the entire ASCOM Registration region
</P>
</LI>
<LI>
<P STYLE="margin-bottom: 0cm">
In driver.cs/driver.vb, remove
the private strings for driver ID and driver description. <I>
They
may be needed internally, and if so should be set from the
associated attributes, ServedClassName for the description and
ProgId for the driver Id.
</I>
</P>
</LI>
<LI>
<P STYLE="margin-bottom: 0cm">
Modify the class attributes by
adding the ServedClassName and ProgID attributes. The
ServedClassName attribute must be the friendly name shown as the
device name in the Chooser and the ProgId the progid of the driver
e.g. ASCOM.SuperScope.Telescope. The class header should look like
this:
</P>
<P STYLE="margin-bottom: 0cm">C#:</P>
<PRE CLASS="western" STYLE="margin-right: 0.16cm">
<FONT FACE="Consolas" SIZE="2" STYLE="font-size: 9pt">
[<FONT COLOR="#2b91af">Guid</FONT><FONT COLOR="#000000">(</FONT><FONT COLOR="#a31515">&quot;0AE8B38D-10A1-4A8D-A5B7-1B050F74B48B&quot;</FONT><FONT COLOR="#000000">)] // set by the template</FONT>
<FONT COLOR="#000000">[</FONT><FONT COLOR="#2b91af">ProgId</FONT><FONT COLOR="#000000">(</FONT><FONT COLOR="#a31515">&quot;ASCOM.SuperScope.Telescope&quot;</FONT><FONT COLOR="#000000">)]</FONT>
<FONT COLOR="#000000">[</FONT><FONT COLOR="#2b91af">ServedClassName</FONT><FONT COLOR="#000000"> (</FONT><FONT COLOR="#a31515">&quot;Super Scope Telescope&quot;</FONT><FONT COLOR="#000000">)]</FONT>
<FONT COLOR="#000000">[</FONT><FONT COLOR="#2b91af">ClassInterface</FONT><FONT COLOR="#000000">(</FONT><FONT COLOR="#2b91af">ClassInterfaceType</FONT><FONT COLOR="#000000">.None)]</FONT>
<FONT COLOR="#0000ff">public </FONT><FONT COLOR="#0000ff">class </FONT><FONT COLOR="#2b91af">Telescope </FONT><FONT COLOR="#000000">: </FONT><FONT COLOR="#2b91af">ReferenceCountedObjectBase</FONT><FONT COLOR="#000000"> , </FONT><FONT COLOR="#2b91af">ITelescope</FONT>
</FONT>
</PRE>
</LI>
</OL>
</LI>
</OL>
<P STYLE="margin-bottom: 0cm">
<BR/>
</P>
<OL>
<OL TYPE="a">
<P>VB:</P>
<PRE CLASS="western">
<FONT FACE="Consolas" SIZE="2" STYLE="font-size: 9pt">
&lt;Guid(&ldquo;<FONT COLOR="#a31515">0AE8B38D-10A1-4A8D-A5B7-1B050F74B48B</FONT>&rdquo;)&gt;
&lt;ProgId(&ldquo;ASCOM.SuperScope.Telescope&rdquo;)&gt;
&lt;ServedClassName(&ldquo;Super Scope Telescope&rdquo;)&gt;
Public Class Telescope
'==================================
Inherits ReferenceCountedObjectBase
Implements ITelescope
'==================================
</FONT>
</PRE>
</OL>
</OL>
<P STYLE="margin-left: 2.5cm">
Add the following line to the driver
constructor, this sets the driver ID using the ProgId Attribute:
</P>
<OL>
<OL TYPE="a">
<P>C#</P>
<PRE CLASS="western">
<FONT FACE="Consolas" SIZE="2" STYLE="font-size: 9pt">
s_csDriverID = <FONT COLOR="#2b91af">Marshal</FONT><FONT COLOR="#000000">.GenerateProgIdForType(</FONT><FONT COLOR="#0000ff">this</FONT><FONT COLOR="#000000">.GetType());</FONT>
</FONT>
</PRE>
<P>VB:</P>
<PRE CLASS="western">
<FONT FACE="Consolas" SIZE="2" STYLE="font-size: 9pt">
s_csDriverID = <FONT COLOR="#2b91af">Marshal</FONT><FONT COLOR="#000000">.GenerateProgIdForType(</FONT><FONT COLOR="#0000ff">Me</FONT><FONT COLOR="#000000">.GetType())</FONT>
</FONT>
</PRE>
</OL>
<LI>
<P STYLE="margin-bottom: 0cm">
Unless you're writing a
single-driver hub, you will have two or more driver types (e.g.
Telescope and Focuser) and thus two or more driver assembly projects
added. Presumably, these drivers need to share some resources (e.g.
a single COM port via Helper.Serial). <U>
Put shared resources into
the SharedResources class provided
</U>. There are some examples that
should give a clue, modify and delete these as required.
</P>
</LI>
<LI>
<P STYLE="margin-bottom: 0cm">
A shared serial port is already
provided (see SharedResources.cs) as <FONT FACE="Lucida Console, Courier New, Courier, monospace">SharedResources.SharedSerial</FONT>
and it is an ASCOM Helper Serial object. You may wish to define
additional shared resources in static member variables with public
static accessor properties as is already done for SharedSerial.
Unfortunately, if you are a Visual Basic programmer, you will have
to make these additions in C#.
</P>
</LI>
<LI>
<P STYLE="margin-bottom: 0cm">
If you are writing a hub and don't
need the serial port, in SharedResources.cs you can remove the
public static SharedSerial property, the m_SharedSerial member in
the private data region, and the line in main that initializes it.
If you don't need any other shared resources for your hub, then you
can remove the SharedResources.cs file completely.
</P>
</LI>
<LI>
<P STYLE="margin-bottom: 0cm">
If you modified the LocalServer,
build it again now. This will refresh the stuff that's visible to
the drivers.
</P>
</LI>
<LI>
<P STYLE="margin-bottom: 0cm">
Build the driver skeletons to
verify that you got all of the namespace and other variable changes.
</P>
</LI>
<LI>
<P>
The local server dynamically loads the driver assemblies from
the same folder as the local server executable. <BR/>
<BR/>During
development, you'll need to add a post-build task to each of your
driver assembly projects which puts a copy of the driver assembly
into the local server executable folder. Here is an example:
</P>
<PRE CLASS="western"> copy &quot;$(TargetPath)&quot; &quot;$(SolutionDir)\SuperScope\$(OutDir)\$(TargetFileName)&quot;</PRE>
<P STYLE="margin-bottom: 0cm">
This assumes that the server project is called &ldquo;SuperScope&rdquo;,
and handles using the debug or release build.<BR/>
Note the quotes for
possible path elements with spaces in them. <I>
An alternative is to
set the build path to the required destination instead of the
default path.
</I>
</P>
</LI>
<LI>
<P STYLE="margin-bottom: 0cm">
<I>
Make sure the drivers are
registered through the local server by running it with the /register
parameter, see below for details.
</I>
</P>
</LI>
<LI>
<P STYLE="margin-bottom: 0cm">
<SPAN STYLE="background: #ffff00">IMPORTANT:</SPAN>
With a local server based driver (or hub) it is possible for
multiple clients to control the device(s). It is up to you to
safeguard against abuse. <I>
The sort of thing that's needed is to
have a counter of the number of connections to a device, the
connection is only fully broken when the number of connections is
zero. You may also need code to prevent several drivers from talking
to the hardware at the same time, the lock pattern is useful for
that.
</I>
</P>
</LI>
<LI>
<P>
You may want to add controls and/or status information to the
main form frmMain of the local server. Please resist the temptation
to turn the local server's main form into a graphical device control
panel. Instead, make a separate application that uses the served
driver(s). <U>A driver is not a program!</U>
</P>
</LI>
</OL>
<H3>Notes</H3>
<UL>
<LI>
<P STYLE="margin-bottom: 0cm">
The local server handles all of
the registration and unregistration for each of its served driver
classes, including the ASCOM Chooser info and the DCOM/AppID info
needed for activation from TheSky. By running the server from a
command line and giving /register or /unregister as the command line
option, it will register or unregister all served classes
(respectively). <SPAN STYLE="background: #ffff00">
Never use REGASM
on the local server executable!
</SPAN> <I>
This can be done in the
Visual Studio IDE by setting the server project to run as startup
and setting the command line argument to /register in Debug &ndash;
Start Options.
</I>
</P>
</LI>
<LI>
<P STYLE="margin-bottom: 0cm">
When you make the installer for
your local server based driver/hub, do not let it register the
executable for COM. Instead, have it activate the installed local
server with the /register option.
</P>
</LI>
<LI>
<P>
The ASCOM registration uses the ServedClassName attribute as
the friendly name that will show in the chooser and the ProgId
attribute as the driver Id.
</P>
</LI>
<LI>
<P>
The best deployment way is to install all the files in a
folder that's a sub folder of the main driver, so the SuperScope
driver files will be in the folder ...\ASCOM\Telescope\SuperScope.
This can be done in the Inno script by changing the DefaultDirName
like this:<BR/>
DefaultDirName=&quot;{cf}\ASCOM\Telescope\SuperScope&quot;<BR/>then
the files can all be installed with DestDir: {app};
</P>
</LI>
</UL>
<H3>
<A NAME="theory"></A>Theory of Operation
</H3>
<P>
The local server is an executable which can provide multiple
instances of multiple drivers to multiple clients. This capability is
needed for two applications:
</P>
<UL>
<LI>
<P STYLE="margin-bottom: 0cm">
A hub, which allows multiple
clients to share a single device
</P>
</LI>
<LI>
<P>
A device which provides multiple services, such as a
telescope which has a focuser built-in where both the telescope and
focuser are controlled by the same serial connection and different
client programs need to control to the focuser and telescope.
</P>
</LI>
</UL>
<P>
By simply dropping suitably developed driver assemblies into the
same folder as the local server executable, the local server will
find them and register them for COM and ASCOM and serve any number of
instances of the drivers' interfaces to any number of client
programs. It does this by locating and loading the driver assemblies,
analysing them to detect their classes and interfaces, and
implementing a class factory that can create instances of them for
clients.
</P>
<P>
A driver is an assembly which contains a class that <EM>implements</EM>
one of the ASCOM standard driver interfaces and <EM>inherits</EM> the
ReferenceCountedObjectBase class of the local server. Apart from
that, driver assemblies are identical to those that are used
in-process (DLL-type). The instructions above detail the steps needed
to convert an in-process driver into one that can be served by the
local server.
</P>
<P>
The name of the local server is important, so we provide it as a
<EM>template</EM> from which you can create a local server for your
produce. To make this clear, let's assume that your company AlphaTech
produces a telescope system which contains a microcontroller that is
able to control not only the telescope mount, but also a focuser and
a camera rotator. The mount, focuser, and rotator are all controlled
via commands sent through a common serial line connecting the
computer to the microcontroller, so you need a local server. In
ASCOM, then, you probably want your system to appear as
AlphaTech.Telescope, AlphaTech.Focuser, and AlphaTech.Rotator. Then
you would name the local server AlphaTech. Be sure to give this due
consideration before creating the template, the project name is the
name of your local server. <I>
Is this still correct? I get the
impression that ASCOM.AlphaTech.Server would be OK.
</I>
</P>
<P>
The fact that driver classes inherit from the local server's
ReferenceCountedObjectBase class allows the local server to maintain
a reference count on the driver class. If a client creates an
instance of a served driver, the local server automatically starts up
and provides an instance of the class to the client. Once started the
local server can provide additional instances of any of its served
driver classes. If the reference count of all served classes drops to
zero as a result of clients releasing their instances, the local
server will automatically exit.
</P>
<P>
Registration services provided include not only the basic COM
class registration, but also DCOM/AppID info needed to use the served
classes from outbound connections from Software Bisque's TheSky. It
also registers the served classes for the ASCOM Chooser. The
&quot;friendly&quot; name of each served driver that appears in the
chooser comes from the driver's ServedClassName attribute. This also
used to identify a driver so that non driver dlls, such as Interop
dlls can be ignored. The COM ProgID for each served driver is
specified in the ProgId attribute - ASCOM.<EM>localservername</EM>.<EM>drivertype</EM>,
for example, ASCOM.AlphaTech.Telescope, where AlphaTech is the local
server name and Telescope is the type of the driver. Unregistering
removes all of this information from the system. Specifying the
ProgId as an attribute allows multiple driver assemblies to be
generated using the same source and namespace. This is used to
provide multiple instances of the same driver, each with a different
ProgId and so able to be registered separately.
</P>
<P>
Driver DLLs are identified for registering/unregistering because
they contain a type with the ServedClassName attribute. Only these
will be registered for Com and ASCOM. This has changed; in Platform
5 there was no attribute and the local server attempted to register
all dlls. The new behaviour allows support dlls such as interop dlls
to be included without them being registered incorrectly. There was
also an interim version where the ServedClassName attribute was on
the assembly, not the class. <I>
All these previous versions, and the
new drivers will operate together with Platform 6, the changes are
local to the individual drivers.
</I>
</P>
<H3>
<A NAME="details"></A>Detailed Use and Deployment
</H3>
<P>
Once you have built your local server and the served driver class
assemblies, here's how to use it. To register the served classes,
activate the local server from a shell command line with the option
/register (or /regserver, for VB6 compatibility):
</P>
<PRE CLASS="western">
C:\xxx&gt; <EM>localserver</EM>.exe /register
</PRE>
<P>
To unregister the local server and its drivers, activate the local
server from a shell command line with the option /unregister (or
/unregserver for VB6 compatibility):
</P>
<PRE CLASS="western">
C:\xxx&gt; <EM>localserver</EM>.exe /unregister
</PRE>
<P>
When the operating system starts the local server in response to a
client creating one of it's served driver classes, the command option
/embedding is included. The local server's code detects this and sets
a variable that you can use.
</P>
<P STYLE="margin-bottom: 0cm">
When deploying a hub or set of drivers
with the local server, you'll have to arrange for the local server
and the driver assemblies to be placed together in a folder in the
ASCOM driver folder. Any support files, such as Interop DLLs can be
put in the same fiolder. That's all you need to do, the local server
will find them in the same folder as it is located in.
</P>
<DIV ALIGN="RIGHT">
<TABLE WIDTH="100"% BORDER="0" CELLPADDING="4" CELLSPACING="0">
<TR>
<TD>
<TABLE WIDTH="100"% BORDER="0" CELLPADDING="4" CELLSPACING="0">
<TR>
<TD>
<H3>ASCOM Initiative</H3>
</TD>
<TD>
<IMG SRC="ASCOM.png" NAME="graphics1" ALIGN="RIGHT" WIDTH="48" HEIGHT="56" BORDER="0"/>
</TD>
</TR>
</TABLE>
<P>
<BR/>
<BR/>
</P>
</TD>
</TR>
<TR>
<TD>
<P>
The ASCOM Initiative consists of a group of astronomy software
developers and instrument vendors whose goals are to promote the
driver/client model and scripting automation.
</P>
<P>
See the <A HREF="http://ascom-standards.org/" TARGET="browser">
ASCOM
web site
</A> for more information. Please participate in the
<A HREF="https://ascomtalk.groups.io/g/Help/topics" TARGET="browser">
ASCOM-Talk
Group
</A>.
</P>
</TD>
</TR>
</TABLE>
</DIV>
<P>
<BR/>
<BR/>
</P>
<P>
<BR/>
<BR/>
</P>
</BODY>
</HTML>
@@ -0,0 +1,23 @@
using System.Runtime.InteropServices;
namespace ASCOM.LynxAstro.DewController
{
[ComVisible(false)]
public class ReferenceCountedObjectBase
{
public ReferenceCountedObjectBase()
{
// We increment the global count of objects.
Server.CountObject();
}
~ReferenceCountedObjectBase()
{
// We decrement the global count of objects.
Server.UncountObject();
// We then immediately test to see if we the conditions
// are right to attempt to terminate this server application.
Server.ExitIf();
}
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

@@ -0,0 +1,89 @@
using System;
using System.IO.Ports;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using ASCOM.LynxAstro.DewController.Properties;
namespace ASCOM.LynxAstro.DewController
{
[ComVisible(false)] // Form not registered for COM!
public partial class SetupDialogForm : Form
{
public SetupDialogForm()
{
InitializeComponent();
var assemblyInfo = new AssemblyInfo();
Text = string.Format(Resources.SetupDialogForm_SetupDialogForm__0__Settings___1__, assemblyInfo.Product, assemblyInfo.AssemblyVersion);
}
private void cmdOK_Click(object sender, EventArgs e) // OK button event handler
{
}
private void cmdCancel_Click(object sender, EventArgs e) // Cancel button event handler
{
Close();
}
private void BrowseToAscom(object sender, EventArgs e) // Click on ASCOM logo event handler
{
try
{
System.Diagnostics.Process.Start("https://ascom-standards.org/");
}
catch (System.ComponentModel.Win32Exception noBrowser)
{
if (noBrowser.ErrorCode == -2147467259)
MessageBox.Show(noBrowser.Message);
}
catch (System.Exception other)
{
MessageBox.Show(other.Message);
}
}
public void SetProfile(ProfileProperties profileProperties)
{
chkTrace.Checked = profileProperties.TraceLogger;
// set the list of com ports to those that are currently available
comboBoxComPort.Items.Clear();
comboBoxComPort.Items.AddRange(SerialPort.GetPortNames().ToArray<object>()); // use System.IO because it's static
// select the current port if possible
if (comboBoxComPort.Items.Contains(profileProperties.ComPort))
{
comboBoxComPort.SelectedItem = profileProperties.ComPort;
}
}
public ProfileProperties GetProfile()
{
var profileProperties = new ProfileProperties
{
TraceLogger = chkTrace.Checked,
ComPort = comboBoxComPort.SelectedItem.ToString(),
};
return profileProperties;
}
public void SetReadOnlyMode()
{
foreach (Control control in Controls)
{
control.Enabled = false;
}
cmdCancel.Enabled = true;
//cmdOK.Enabled = false;
//comboBoxComPort.Enabled = false;
//chkTrace.Enabled = false;
//txtGuideRate.Enabled = false;
//cboPrecision.Enabled = false;
}
}
}
+149
View File
@@ -0,0 +1,149 @@
namespace ASCOM.LynxAstro.DewController
{
partial class SetupDialogForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.cmdOK = new System.Windows.Forms.Button();
this.cmdCancel = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label();
this.picASCOM = new System.Windows.Forms.PictureBox();
this.label2 = new System.Windows.Forms.Label();
this.chkTrace = new System.Windows.Forms.CheckBox();
this.comboBoxComPort = new System.Windows.Forms.ComboBox();
((System.ComponentModel.ISupportInitialize)(this.picASCOM)).BeginInit();
this.SuspendLayout();
//
// cmdOK
//
this.cmdOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.cmdOK.DialogResult = System.Windows.Forms.DialogResult.OK;
this.cmdOK.Location = new System.Drawing.Point(281, 112);
this.cmdOK.Name = "cmdOK";
this.cmdOK.Size = new System.Drawing.Size(59, 24);
this.cmdOK.TabIndex = 0;
this.cmdOK.Text = "OK";
this.cmdOK.UseVisualStyleBackColor = true;
this.cmdOK.Click += new System.EventHandler(this.cmdOK_Click);
//
// cmdCancel
//
this.cmdCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.cmdCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.cmdCancel.Location = new System.Drawing.Point(281, 142);
this.cmdCancel.Name = "cmdCancel";
this.cmdCancel.Size = new System.Drawing.Size(59, 25);
this.cmdCancel.TabIndex = 1;
this.cmdCancel.Text = "Cancel";
this.cmdCancel.UseVisualStyleBackColor = true;
this.cmdCancel.Click += new System.EventHandler(this.cmdCancel_Click);
//
// label1
//
this.label1.Location = new System.Drawing.Point(12, 9);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(123, 31);
this.label1.TabIndex = 2;
this.label1.Text = "Construct your driver\'s setup dialog here.";
//
// picASCOM
//
this.picASCOM.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.picASCOM.Cursor = System.Windows.Forms.Cursors.Hand;
this.picASCOM.Image = global::ASCOM.LynxAstro.DewController.Properties.Resources.ASCOM;
this.picASCOM.Location = new System.Drawing.Point(292, 9);
this.picASCOM.Name = "picASCOM";
this.picASCOM.Size = new System.Drawing.Size(48, 56);
this.picASCOM.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
this.picASCOM.TabIndex = 3;
this.picASCOM.TabStop = false;
this.picASCOM.Click += new System.EventHandler(this.BrowseToAscom);
this.picASCOM.DoubleClick += new System.EventHandler(this.BrowseToAscom);
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(13, 90);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(58, 13);
this.label2.TabIndex = 5;
this.label2.Text = "Comm Port";
//
// chkTrace
//
this.chkTrace.AutoSize = true;
this.chkTrace.Location = new System.Drawing.Point(77, 118);
this.chkTrace.Name = "chkTrace";
this.chkTrace.Size = new System.Drawing.Size(69, 17);
this.chkTrace.TabIndex = 6;
this.chkTrace.Text = "Trace on";
this.chkTrace.UseVisualStyleBackColor = true;
//
// comboBoxComPort
//
this.comboBoxComPort.FormattingEnabled = true;
this.comboBoxComPort.Location = new System.Drawing.Point(77, 87);
this.comboBoxComPort.Name = "comboBoxComPort";
this.comboBoxComPort.Size = new System.Drawing.Size(90, 21);
this.comboBoxComPort.TabIndex = 7;
//
// SetupDialogForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(350, 175);
this.Controls.Add(this.comboBoxComPort);
this.Controls.Add(this.chkTrace);
this.Controls.Add(this.label2);
this.Controls.Add(this.picASCOM);
this.Controls.Add(this.label1);
this.Controls.Add(this.cmdCancel);
this.Controls.Add(this.cmdOK);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "SetupDialogForm";
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "LynxAstro.DewController Setup";
((System.ComponentModel.ISupportInitialize)(this.picASCOM)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button cmdOK;
private System.Windows.Forms.Button cmdCancel;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.PictureBox picASCOM;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.CheckBox chkTrace;
private System.Windows.Forms.ComboBox comboBoxComPort;
}
}
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
+379
View File
@@ -0,0 +1,379 @@
//
// ================
// Shared Resources
// ================
//
// This class is a container for all shared resources that may be needed
// by the drivers served by the Local Server.
//
// NOTES:
//
// * ALL DECLARATIONS MUST BE STATIC HERE!! INSTANCES OF THIS CLASS MUST NEVER BE CREATED!
//
// Written by: Bob Denny 29-May-2007
// Modified by Chris Rowland and Peter Simpson to hamdle multiple hardware devices March 2011
//
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using ASCOM.Utilities;
using ASCOM.Utilities.Interfaces;
using JetBrains.Annotations;
namespace ASCOM.LynxAstro.DewController
{
/// <summary>
/// The resources shared by all drivers and devices, in this example it's a serial port with a shared SendMessage method
/// an idea for locking the message and handling connecting is given.
/// In reality extensive changes will probably be needed.
/// Multiple drivers means that several applications connect to the same hardware device, aka a hub.
/// Multiple devices means that there are more than one instance of the hardware, such as two focusers.
/// In this case there needs to be multiple instances of the hardware connector, each with it's own connection count.
/// </summary>
public static class SharedResources
{
// object used for locking to prevent multiple drivers accessing common code at the same time
private static readonly object LockObject = new object();
// Shared serial port. This will allow multiple drivers to use one single serial port.
private static ISerial _sSharedSerial; // Shared serial port
//
// Public access to shared resources
//
#region single serial port connector
//
// this region shows a way that a single serial port could be connected to by multiple
// drivers.
//
// Connected is used to handle the connections to the port.
//
// SendMessage is a way that messages could be sent to the hardware without
// conflicts between different drivers.
//
// All this is for a single connection, multiple connections would need multiple ports
// and a way to handle connecting and disconnection from them - see the
// multi driver handling section for ideas.
//
/// <summary>
/// Shared serial port. Do not directly access this method.
/// </summary>
public static ISerial SharedSerial
{
get => _sSharedSerial ?? (_sSharedSerial = new Serial());
set => _sSharedSerial = value;
}
public static IProfileFactory ProfileFactory
{
get => _profileFactory ?? (_profileFactory = new ProfileFactory());
set => _profileFactory = value;
}
//todo add code to ensure that there is a minimum gap between commands. 5ms as default.
public static void SendBlind(string message)
{
lock (LockObject)
{
SharedSerial.ClearBuffers();
SharedSerial.Transmit(message);
}
}
/// <summary>
/// Example of a shared SendMessage method, the lock
/// prevents different drivers tripping over one another.
/// It needs error handling and assumes that the message will be sent unchanged
/// and that the reply will always be terminated by a "#" character.
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public static string SendString(string message)
{
lock (LockObject)
{
SharedSerial.ClearBuffers();
SharedSerial.Transmit(message);
return SharedSerial.ReceiveTerminated("#").TrimEnd('#');
}
}
public static string SendChar(string message)
{
lock (LockObject)
{
SharedSerial.ClearBuffers();
SharedSerial.Transmit(message);
return SharedSerial.ReceiveCounted(1);
}
}
public static string ReadTerminated()
{
lock (LockObject)
{
return SharedSerial.ReceiveTerminated("#");
}
}
public static void ReadCharacters(int throwAwayCharacters)
{
lock (LockObject)
{
SharedSerial.ReceiveCounted(throwAwayCharacters);
}
}
#endregion
#region Profile
private const string DriverId = "ASCOM.MeadeGeneric.Telescope";
// Constants used for Profile persistence
private const string ComPortProfileName = "COM Port";
private const string TraceStateProfileName = "Trace Level";
private const string SwitchNameProfileName = "SwitchName_{0}";
public static void WriteProfile(ProfileProperties profileProperties)
{
lock (LockObject)
{
using (IProfileWrapper driverProfile = ProfileFactory.Create())
{
driverProfile.DeviceType = "Telescope";
driverProfile.WriteValue(DriverId, TraceStateProfileName, profileProperties.TraceLogger.ToString());
driverProfile.WriteValue(DriverId, ComPortProfileName, profileProperties.ComPort);
}
}
}
private const string ComPortDefault = "COM1";
private const string TraceStateDefault = "false";
private const string noSwitchValue = "no_switch_value";
public static ProfileProperties ReadProfile()
{
lock (LockObject)
{
ProfileProperties profileProperties = new ProfileProperties();
using (IProfileWrapper driverProfile = ProfileFactory.Create())
{
driverProfile.DeviceType = "Telescope";
profileProperties.ComPort = driverProfile.GetValue(DriverId, ComPortProfileName, string.Empty, ComPortDefault);
profileProperties.TraceLogger = Convert.ToBoolean(driverProfile.GetValue(DriverId, TraceStateProfileName, string.Empty, TraceStateDefault));
var switchNo = 0;
var finished = false;
profileProperties.SwitchNames.Clear();
do
{
var switchName = string.Format(SwitchNameProfileName, switchNo);
var switchValue = driverProfile.GetValue(DriverId, switchName, string.Empty, noSwitchValue);
finished = switchValue == noSwitchValue;
if (!finished)
profileProperties.SwitchNames.Add(switchValue);
} while (!finished);
}
return profileProperties;
}
}
#endregion
#region SetupDialog
public static void SetupDialog()
{
var profileProperties = ReadProfile();
using (SetupDialogForm f = new SetupDialogForm())
{
f.SetProfile(profileProperties);
if (IsConnected())
{
f.SetReadOnlyMode();
}
var result = f.ShowDialog();
if (result == DialogResult.OK)
{
profileProperties = f.GetProfile();
WriteProfile(profileProperties); // Persist device configuration values to the ASCOM Profile store
}
}
}
#endregion
#region Multi Driver handling
public static string FirmwareVersion { get; private set; } = string.Empty;
// this section illustrates how multiple drivers could be handled,
// it's for drivers where multiple connections to the hardware can be made and ensures that the
// hardware is only disconnected from when all the connected devices have disconnected.
// It is NOT a complete solution! This is to give ideas of what can - or should be done.
//
// An alternative would be to move the hardware control here, handle connecting and disconnecting,
// and provide the device with a suitable connection to the hardware.
//
/// <summary>
/// dictionary carrying device connections.
/// The Key is the connection number that identifies the device, it could be the COM port name,
/// USB ID or IP Address, the Value is the DeviceHardware class
/// </summary>
private static readonly Dictionary<string, DeviceHardware> ConnectedDevices = new Dictionary<string, DeviceHardware>();
private static readonly Dictionary<string, DeviceHardware> ConnectedDeviceIds = new Dictionary<string, DeviceHardware>();
private static IProfileFactory _profileFactory;
/// <summary>
/// This is called in the driver Connect(true) property,
/// it add the device id to the list of devices if it's not there and increments the device count.
/// </summary>
/// <param name="deviceId"></param>
/// <param name="driverId"></param>
/// <param name="traceLogger"></param>
public static ConnectionInfo Connect(string deviceId, string driverId, ITraceLogger traceLogger)
{
lock (LockObject)
{
if (!ConnectedDevices.ContainsKey(deviceId))
ConnectedDevices.Add(deviceId, new DeviceHardware());
if (!ConnectedDeviceIds.ContainsKey(driverId))
ConnectedDeviceIds.Add(driverId, new DeviceHardware());
if (deviceId == "Serial")
{
if (ConnectedDevices[deviceId].Count == 0)
{
var profileProperties = ReadProfile();
SharedSerial.PortName = profileProperties.ComPort;
//SharedSerial.DTREnable = profileProperties.RtsDtrEnabled;
//SharedSerial.RTSEnable = profileProperties.RtsDtrEnabled;
SharedSerial.DataBits = 8;
SharedSerial.StopBits = SerialStopBits.One;
SharedSerial.Parity = SerialParity.None;
SharedSerial.Speed = SerialSpeed.ps9600;
SharedSerial.Handshake = SerialHandshake.None;
SharedSerial.Connected = true;
}
try
{
var encodedString = SendString(":GV#");
FirmwareVersion = DecodeResult(":GV", encodedString );
//Command: :GV#
//Purpose: Get the devices firmware version.
//Response: :GVXXXXXXXX# where X is a version string, e.g. 1.0.
}
catch (Exception ex)
{
traceLogger.LogIssue("Connect", $"Error getting telescope information \"{ex.Message}\" setting to LX200 Classic mode.");
FirmwareVersion = "Unknown";
}
}
else
throw new ArgumentException($"deviceId {deviceId} not currently supported");
ConnectedDevices[deviceId].Count++; // increment the value
ConnectedDeviceIds[driverId].Count++; // increment the value
return new ConnectionInfo
{
//Connections = ConnectedDevices[deviceId].Count,
SameDevice = ConnectedDeviceIds[driverId].Count
};
}
}
private static string DecodeResult(string pattern, string encodedString)
{
var decodedString = encodedString.Substring( pattern.Length ).TrimEnd('#');
return decodedString;
}
public static void Disconnect(string deviceId, string driverId)
{
lock (LockObject)
{
if (ConnectedDevices.ContainsKey(deviceId))
{
ConnectedDevices[deviceId].Count--;
if (ConnectedDevices[deviceId].Count <= 0)
{
ConnectedDevices.Remove(deviceId);
if (deviceId == "Serial")
{
SharedSerial.Connected = false;
}
}
}
if (ConnectedDeviceIds.ContainsKey(driverId))
{
ConnectedDeviceIds[driverId].Count--;
}
}
}
private static bool IsConnected()
{
foreach (var device in ConnectedDevices)
{
if (device.Value.Count > 0)
return true;
}
return false;
}
#endregion
public static void Lock(Action action)
{
lock (LockObject)
{
action();
}
}
public static T Lock<T>(Func<T> func)
{
lock (LockObject)
{
return func();
}
}
/// <summary>
/// Skeleton of a hardware class, all this does is hold a count of the connections,
/// in reality extra code will be needed to handle the hardware in some way
/// </summary>
private class DeviceHardware
{
internal int Count { set; get; }
internal DeviceHardware()
{
Count = 0;
}
}
}
}
@@ -0,0 +1,70 @@
using System;
using ASCOM.Utilities.Interfaces;
namespace ASCOM.LynxAstro.DewController
{
public class SharedResourcesWrapper : ISharedResourcesWrapper
{
public ConnectionInfo Connect(string deviceId, string driverId, ITraceLogger traceLogger)
{
return SharedResources.Connect(deviceId, driverId, traceLogger);
}
public void Disconnect(string deviceId, string driverId)
{
SharedResources.Disconnect(deviceId, driverId);
}
public string FirmwareVersion => SharedResources.FirmwareVersion;
public void Lock(Action action)
{
SharedResources.Lock(action);
}
public T Lock<T>(Func<T> func)
{
return SharedResources.Lock(func);
}
public string SendString(string message)
{
return SharedResources.SendString(message);
}
public void SendBlind(string message)
{
SharedResources.SendBlind(message);
}
public string SendChar(string message)
{
return SharedResources.SendChar(message);
}
public string ReadTerminated()
{
return SharedResources.ReadTerminated();
}
public void ReadCharacters(int throwAwayCharacters)
{
SharedResources.ReadCharacters(throwAwayCharacters);
}
public ProfileProperties ReadProfile()
{
return SharedResources.ReadProfile();
}
public void SetupDialog()
{
SharedResources.SetupDialog();
}
public void WriteProfile(ProfileProperties profileProperties)
{
SharedResources.WriteProfile(profileProperties);
}
}
}
+63
View File
@@ -0,0 +1,63 @@
using System;
namespace ASCOM.LynxAstro.DewController
{
partial class frmMain
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.label1 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// label1
//
this.label1.Location = new System.Drawing.Point(12, 10);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(199, 33);
this.label1.TabIndex = 0;
this.label1.Text = "This is an ASCOM driver, not a program for you to use.";
//
// frmMain
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(233, 52);
this.Controls.Add(this.label1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
this.Name = "frmMain";
this.Text = "LynxAstro.DewController Driver Server";
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Label label1;
}
}
+15
View File
@@ -0,0 +1,15 @@
using System.Windows.Forms;
namespace ASCOM.LynxAstro.DewController
{
public partial class frmMain : Form
{
delegate void SetTextCallback(string text);
public frmMain()
{
InitializeComponent();
}
}
}
+120
View File
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
+5
View File
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="ASCOM.Platform" version="6.5.2" targetFramework="net472" />
<package id="JetBrains.Annotations" version="2020.3.0" targetFramework="net472" />
</packages>